Compare commits
186 Commits
46b264e69e
...
dev_vite
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5eaa77596e | ||
|
|
848e7b4692 | ||
|
|
fd140ebc56 | ||
|
|
34094c8c92 | ||
|
|
e4dc2bf729 | ||
|
|
7f226179d9 | ||
|
|
3edff6b05c | ||
|
|
6fd1212298 | ||
| e093cccb8d | |||
| b2c6c61515 | |||
| 0219b1a2f4 | |||
| 133433a260 | |||
| 90a59a3dc5 | |||
| c8a65ee2cb | |||
| 226918e941 | |||
|
|
494bfd68ca | ||
|
|
95b70792ba | ||
|
|
a0fffa5896 | ||
|
|
06eaabc742 | ||
|
|
27da4739a6 | ||
| 52576aa0a1 | |||
| 22aa7c37cd | |||
| 752b33f196 | |||
| f3b873b7ae | |||
| 006c2e3f9c | |||
|
|
1f413b36ca | ||
|
|
e7b052f100 | ||
|
|
19bb412470 | ||
|
|
a1e071f7bc | ||
|
|
5388b2df4c | ||
|
|
76e507cae3 | ||
|
|
d4e9462d39 | ||
|
|
4a11d172d2 | ||
|
|
e20092c77f | ||
|
|
5f4656c629 | ||
|
|
14eca9aff2 | ||
|
|
88f0528553 | ||
|
|
afbea289fb | ||
| eb2baa26a7 | |||
|
|
62829395ce | ||
|
|
16532ce44b | ||
|
|
27de720137 | ||
|
|
acf2029efe | ||
|
|
49398aac48 | ||
|
|
b3d9bce440 | ||
|
|
596bc75b83 | ||
|
|
c673948dd3 | ||
|
|
1f8ee2e48e | ||
| e5ae549a3d | |||
| 88c2ae8583 | |||
|
|
f4897e2c92 | ||
| aab96bbe70 | |||
| 4004fa2703 | |||
|
|
4a078186a9 | ||
| fafccf0352 | |||
| 64844105b5 | |||
| d6a07e7fc7 | |||
| 7eff1b0506 | |||
| 2dc98e5dd8 | |||
|
|
3e7a90bd2d | ||
|
|
d42a1bef8d | ||
| 5d184bf1f9 | |||
| 56825fcbb1 | |||
| 7cf37e2da6 | |||
| 59a7c169ad | |||
| fc997a1cce | |||
|
|
8abcdb151d | ||
|
|
55481c6d51 | ||
| ca39910f4c | |||
| 646b48ca6b | |||
| 45f150769e | |||
|
|
7115feb20c | ||
| 00d488cbc2 | |||
| 12233b952b | |||
| 4b8554f41e | |||
| f30a749f65 | |||
|
|
af544d2da8 | ||
| aedd633f8e | |||
| 1e4134f8b9 | |||
|
|
27da8f6680 | ||
|
|
88c66c634f | ||
| 5cfccabcd7 | |||
| 04ad920590 | |||
| 05178c4cb0 | |||
| a385aba49f | |||
|
|
813918eb39 | ||
|
|
f77a2f2e01 | ||
|
|
9dc25ddced | ||
|
|
e453d1efd4 | ||
|
|
78922a5b91 | ||
|
|
b04bcb5918 | ||
|
|
6d41e8cc34 | ||
|
|
9dca4e3155 | ||
|
|
0c140c2896 | ||
|
|
bd603e1bf9 | ||
| f269a40431 | |||
| 55a8675806 | |||
|
|
c0e5611897 | ||
|
|
821f35b7c7 | ||
|
|
39c0ee110a | ||
|
|
22e8efda25 | ||
|
|
114a998031 | ||
|
|
ee4eef1558 | ||
|
|
a9e5b979a1 | ||
|
|
7bb38bf2e5 | ||
|
|
e4fc51c574 | ||
|
|
071930f257 | ||
|
|
136c24ce30 | ||
|
|
2708c5442c | ||
|
|
0cbd0c848d | ||
|
|
9845b2ebb0 | ||
|
|
41f8bed6a3 | ||
|
|
ca21169fda | ||
|
|
b1458de4e0 | ||
|
|
743fc762d6 | ||
| 7297e4e7a4 | |||
| 3bff1ebb66 | |||
| 0d1656ee0a | |||
| 7d0873d874 | |||
| d8caa472ea | |||
| 6b138b7a04 | |||
| 82941bca7c | |||
| 949ff9292d | |||
| 19230f6c5a | |||
| 583f61d875 | |||
|
|
44250f2f79 | ||
|
|
11c9de8ced | ||
|
|
06d78524ed | ||
|
|
fd518ad9b3 | ||
| 19ef5b031e | |||
| 4394158d30 | |||
| ec632554e2 | |||
| 429c7db195 | |||
| 8a9b217314 | |||
| f9caa4b279 | |||
| 68f17ba87b | |||
| 92c789510f | |||
| 0a442f8132 | |||
|
|
1fe1bd4aa2 | ||
|
|
a2b45e2041 | ||
|
|
da64b57c1c | ||
|
|
7ad29081af | ||
|
|
ce6522ef90 | ||
| 9758c562c3 | |||
| 9e12d54540 | |||
|
|
44abb1b1ee | ||
|
|
27b71f1bec | ||
|
|
ddb7a366b5 | ||
| d4d104c690 | |||
| 48516a5f42 | |||
| 646ecd072c | |||
| ce0f9f0bbf | |||
| 0985a004de | |||
| 1d9fdfa9f8 | |||
| f56718e93a | |||
|
|
91cfcd7e40 | ||
|
|
7c14b1d831 | ||
|
|
8966b52430 | ||
| 8a9e7205eb | |||
| 0778cb7081 | |||
| 66a5f632fb | |||
|
|
5df602e26f | ||
|
|
9707615b63 | ||
|
|
4d6a1f512e | ||
|
|
d7d66b8da4 | ||
|
|
5fa049f73d | ||
|
|
575445f767 | ||
|
|
0ea664f32a | ||
|
|
68de44236d | ||
|
|
f43c56236b | ||
|
|
54cc7bd359 | ||
|
|
88f3bed2c1 | ||
|
|
74d8723ecd | ||
|
|
4352f7c2f4 | ||
|
|
c6b1bdbdf1 | ||
|
|
3be24cad90 | ||
|
|
b33a2e1d08 | ||
|
|
f16aa6ea14 | ||
|
|
a25abeb527 | ||
|
|
3b70ed2830 | ||
|
|
5e77348913 | ||
|
|
7fdd22fe63 | ||
| a525d4f54a | |||
|
|
d359cd7763 | ||
| 23085d9a9b | |||
|
|
35c6dfe29c |
4
.env.dev
@@ -3,11 +3,13 @@ VITE_USER_NODE_ENV = 'development'
|
|||||||
# VITE_APP_BASE_URL = 'https://api.aida.com.hk'
|
# VITE_APP_BASE_URL = 'https://api.aida.com.hk'
|
||||||
|
|
||||||
# VITE_APP_BASE_URL = 'http://18.167.251.121:10086'
|
# VITE_APP_BASE_URL = 'http://18.167.251.121:10086'
|
||||||
VITE_APP_BASE_URL = 'https://develop.api.aida.com.hk'
|
# VITE_APP_BASE_URL = 'https://develop.api.aida.com.hk'
|
||||||
|
VITE_APP_BASE_URL = 'http://18.167.251.121:10094'
|
||||||
# VITE_APP_BASE_URL = 'https://www.api.aida.com.hk'
|
# VITE_APP_BASE_URL = 'https://www.api.aida.com.hk'
|
||||||
# 徐佩
|
# 徐佩
|
||||||
# VITE_APP_BASE_URL = 'http://192.168.31.118:5567'
|
# VITE_APP_BASE_URL = 'http://192.168.31.118:5567'
|
||||||
# 李天祥
|
# 李天祥
|
||||||
# VITE_APP_BASE_URL = 'http://192.168.31.82:5567'
|
# VITE_APP_BASE_URL = 'http://192.168.31.82:5567'
|
||||||
|
# VITE_APP_BASE_URL = 'http://192.168.31.82:5569'
|
||||||
# 海波
|
# 海波
|
||||||
# VITE_APP_BASE_URL = 'http://192.168.31.34:5567'
|
# VITE_APP_BASE_URL = 'http://192.168.31.34:5567'
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
VITE_USER_NODE_ENV = 'development'
|
VITE_USER_NODE_ENV = 'development_cloud'
|
||||||
# VITE_APP_BASE_URL = 'https://aida.com.hk/test'
|
# VITE_APP_BASE_URL = 'https://aida.com.hk/test'
|
||||||
# VITE_APP_BASE_URL = 'http://18.167.251.121:10088'
|
# VITE_APP_BASE_URL = 'http://18.167.251.121:10088'
|
||||||
# VITE_APP_BASE_URL = 'https://api.aida.com.hk'
|
# VITE_APP_BASE_URL = 'https://api.aida.com.hk'
|
||||||
VITE_APP_BASE_URL = 'https://develop.api.aida.com.hk'
|
# VITE_APP_BASE_URL = 'https://develop.api.aida.com.hk'
|
||||||
|
VITE_APP_BASE_URL = 'https://www.develop-ms.api.aida.com.hk'
|
||||||
|
|
||||||
# VITE_APP_BASE_URL = 'http://localhost:22170'
|
# VITE_APP_BASE_URL = 'http://localhost:22170'
|
||||||
|
|||||||
4
.gitignore
vendored
@@ -24,4 +24,6 @@ dist.rar
|
|||||||
*.sw?
|
*.sw?
|
||||||
.eslintrc-auto-import.json
|
.eslintrc-auto-import.json
|
||||||
components.d.ts
|
components.d.ts
|
||||||
.cursor
|
.cursor
|
||||||
|
*.zip
|
||||||
|
*.7z
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
/** @type {import('prettier').Config} */
|
|
||||||
module.exports = {
|
|
||||||
// 打印宽度
|
|
||||||
printWidth: 100,
|
|
||||||
// 使用 4 空格缩进
|
|
||||||
tabWidth: 4,
|
|
||||||
// 使用 4 空格缩进,不使用制表符
|
|
||||||
useTabs: true,
|
|
||||||
// 行尾使用 LF (Unix 风格)
|
|
||||||
endOfLine: 'lf',
|
|
||||||
// 语句末尾使用分号
|
|
||||||
semi: false,
|
|
||||||
// 使用单引号
|
|
||||||
singleQuote: false,
|
|
||||||
// 对象和数组末尾不添加尾随逗号
|
|
||||||
trailingComma: 'none',
|
|
||||||
// JSX 引号使用单引号
|
|
||||||
jsxSingleQuote: false,
|
|
||||||
// 括号内侧空格
|
|
||||||
bracketSpacing: true,
|
|
||||||
// JSX 标签不换行
|
|
||||||
bracketSameLine: false,
|
|
||||||
// 箭头函数参数始终使用括号
|
|
||||||
arrowParens: 'always',
|
|
||||||
// HTML、Vue、Angular 和 Markdown 使用 LF
|
|
||||||
htmlWhitespaceSensitivity: 'css',
|
|
||||||
// Vue 文件脚本和样式缩进
|
|
||||||
vueIndentScriptAndStyle: false,
|
|
||||||
// 行注释位置在注释上方,不加空格
|
|
||||||
proseWrap: 'preserve',
|
|
||||||
// 根据文件类型自动推断
|
|
||||||
embeddedLanguageFormatting: 'auto',
|
|
||||||
};
|
|
||||||
17
.prettierrc.json
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 100,
|
||||||
|
"tabWidth": 4,
|
||||||
|
"useTabs": true,
|
||||||
|
"endOfLine": "lf",
|
||||||
|
"semi": false,
|
||||||
|
"singleQuote": false,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"jsxSingleQuote": false,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"bracketSameLine": false,
|
||||||
|
"arrowParens": "always",
|
||||||
|
"htmlWhitespaceSensitivity": "css",
|
||||||
|
"vueIndentScriptAndStyle": true,
|
||||||
|
"proseWrap": "preserve",
|
||||||
|
"embeddedLanguageFormatting": "auto"
|
||||||
|
}
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
line-height: 150%;
|
line-height: 150%;
|
||||||
}
|
}
|
||||||
:deep(.ant-form) .ant-form-item-label > label.ant-form-item-required:not(.ant-form-item-required-mark-optional)::before {
|
:deep(.ant-form) .ant-form-item-label > label.ant-form-item-required:not(.ant-form-item-required-mark-optional)::before {
|
||||||
content: "";
|
display: none;
|
||||||
}
|
}
|
||||||
:deep(.ant-form) .ant-form-item-label > label.ant-form-item-required:not(.ant-form-item-required-mark-optional):after {
|
:deep(.ant-form) .ant-form-item-label > label.ant-form-item-required:not(.ant-form-item-required-mark-optional):after {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|||||||
@@ -167,8 +167,7 @@ li {
|
|||||||
padding: 0.6rem 0.5rem;
|
padding: 0.6rem 0.5rem;
|
||||||
}
|
}
|
||||||
.ant-modal-mask {
|
.ant-modal-mask {
|
||||||
background-color: #666666;
|
background-color: rgba(102, 102, 102, 0.5);
|
||||||
opacity: 0.5;
|
|
||||||
}
|
}
|
||||||
.select_block {
|
.select_block {
|
||||||
height: 4rem;
|
height: 4rem;
|
||||||
@@ -1251,8 +1250,8 @@ tr > .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:last-child::afte
|
|||||||
border-color: #000 !important;
|
border-color: #000 !important;
|
||||||
}
|
}
|
||||||
.ant-spin .ant-spin-dot {
|
.ant-spin .ant-spin-dot {
|
||||||
width: 1.5em;
|
width: 4.5rem;
|
||||||
height: 1.5em;
|
height: 4.5rem;
|
||||||
}
|
}
|
||||||
.ant-spin-dot-item {
|
.ant-spin-dot-item {
|
||||||
background-color: #000000 !important;
|
background-color: #000000 !important;
|
||||||
@@ -2477,6 +2476,15 @@ textarea:focus {
|
|||||||
border-radius: 0.4rem;
|
border-radius: 0.4rem;
|
||||||
background: rgba(0, 0, 0, 0.2);
|
background: rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
.mosaic-bg {
|
||||||
|
--mosaic-bg-size: 1rem;
|
||||||
|
--mosaic-bg-color1: #efefef;
|
||||||
|
--mosaic-bg-color2: #fff;
|
||||||
|
background-image: repeating-conic-gradient(var(--mosaic-bg-color1) 0% 25%, var(--mosaic-bg-color2) 0% 50%);
|
||||||
|
background-repeat: repeat;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-size: var(--mosaic-bg-size) var(--mosaic-bg-size);
|
||||||
|
}
|
||||||
.mark_loading {
|
.mark_loading {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
3
src/assets/icons/home.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M13.4872 5.28094L9.06266 0.853126C8.51506 0.306793 7.7733 0 7 0C6.2267 0 5.48494 0.306793 4.93734 0.853126L0.512757 5.28094C0.349671 5.44308 0.220373 5.636 0.132355 5.84851C0.0443375 6.06102 -0.000647733 6.2889 7.04636e-06 6.51894V12.249C7.04636e-06 12.7134 0.184381 13.1587 0.51257 13.4871C0.840758 13.8155 1.28588 14 1.75001 14H12.25C12.7141 14 13.1592 13.8155 13.4874 13.4871C13.8156 13.1587 14 12.7134 14 12.249V6.51894C14.0006 6.2889 13.9557 6.06102 13.8676 5.84851C13.7796 5.636 13.6503 5.44308 13.4872 5.28094ZM8.75 12.8326H5.25V10.5364C5.25 10.072 5.43438 9.62663 5.76256 9.29825C6.09075 8.96986 6.53587 8.78538 7 8.78538C7.46413 8.78538 7.90925 8.96986 8.23744 9.29825C8.56562 9.62663 8.75 10.072 8.75 10.5364V12.8326ZM12.8333 12.249C12.8333 12.4038 12.7719 12.5522 12.6625 12.6617C12.5531 12.7711 12.4047 12.8326 12.25 12.8326H9.91666V10.5364C9.91666 9.76241 9.60937 9.0201 9.06239 8.47279C8.51541 7.92549 7.77355 7.61801 7 7.61801C6.22645 7.61801 5.48459 7.92549 4.93761 8.47279C4.39063 9.0201 4.08334 9.76241 4.08334 10.5364V12.8326H1.75001C1.5953 12.8326 1.44692 12.7711 1.33753 12.6617C1.22813 12.5522 1.16667 12.4038 1.16667 12.249V6.51894C1.16721 6.36425 1.22862 6.216 1.33759 6.10627L5.76217 1.6802C6.09099 1.35272 6.53605 1.16887 7 1.16887C7.46394 1.16887 7.90901 1.35272 8.23783 1.6802L12.6624 6.10802C12.771 6.21732 12.8323 6.36486 12.8333 6.51894V12.249Z" fill="#585858"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
3
src/assets/icons/seller/download.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M13.4167 14H0.583333C0.2625 14 0 13.7375 0 13.4167C0 13.0958 0.2625 12.8333 0.583333 12.8333H13.4167C13.7375 12.8333 14 13.0958 14 13.4167C14 13.7375 13.7375 14 13.4167 14ZM8.61583 11.0017L12.32 7.06417C12.8275 6.55667 12.9733 5.83333 12.6992 5.17417C12.425 4.515 11.8125 4.10083 11.095 4.095H9.8875L9.87 2.31583C9.87 1.03833 8.83167 0 7.55417 0H6.39917C5.12167 0 4.08333 1.03833 4.08333 2.32167V4.08333H2.8875C2.17 4.08333 1.5575 4.4975 1.28333 5.1625C1.00917 5.82167 1.155 6.55083 1.65083 7.04083L5.34333 11.0075C5.7925 11.4567 6.3875 11.6842 6.9825 11.6842C7.5775 11.6842 8.16667 11.4567 8.62167 11.0075L8.61583 11.0017ZM4.66667 5.25C4.82417 5.25 4.97 5.18583 5.08083 5.08083C5.19167 4.97 5.25 4.82417 5.25 4.66667V2.31583C5.25 1.68 5.76333 1.16667 6.39917 1.16667H7.55417C8.19 1.16667 8.70333 1.68583 8.70333 2.32167L8.72083 4.68417C8.72083 5.005 8.98333 5.26167 9.30417 5.26167H11.0833C11.4392 5.26167 11.5792 5.53583 11.6083 5.6175C11.6433 5.69917 11.7367 5.99083 11.4683 6.25333L7.77583 10.1792C7.32667 10.6225 6.60333 10.6167 6.17167 10.185L2.47917 6.21833C2.22833 5.9675 2.32167 5.67583 2.35667 5.59417C2.39167 5.5125 2.53167 5.23833 2.88167 5.23833H4.66667V5.25Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
11
src/assets/icons/seller/draft.svg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_1622_6669)">
|
||||||
|
<path d="M15.9998 13.3334C14.945 13.3334 13.9139 13.6462 13.0368 14.2322C12.1597 14.8182 11.4761 15.6512 11.0725 16.6257C10.6688 17.6003 10.5632 18.6726 10.769 19.7072C10.9748 20.7418 11.4827 21.6921 12.2286 22.4379C12.9745 23.1838 13.9248 23.6918 14.9594 23.8976C15.9939 24.1034 17.0663 23.9977 18.0408 23.5941C19.0154 23.1904 19.8483 22.5068 20.4343 21.6297C21.0204 20.7527 21.3332 19.7215 21.3332 18.6667C21.3332 17.2522 20.7713 15.8957 19.7711 14.8955C18.7709 13.8953 17.4143 13.3334 15.9998 13.3334ZM15.9998 21.3334C15.4724 21.3334 14.9569 21.177 14.5183 20.884C14.0798 20.5909 13.738 20.1745 13.5362 19.6872C13.3343 19.1999 13.2815 18.6637 13.3844 18.1465C13.4873 17.6292 13.7413 17.154 14.1142 16.7811C14.4872 16.4081 14.9623 16.1542 15.4796 16.0513C15.9969 15.9484 16.5331 16.0012 17.0203 16.203C17.5076 16.4049 17.9241 16.7467 18.2171 17.1852C18.5101 17.6237 18.6665 18.1393 18.6665 18.6667C18.6665 19.374 18.3856 20.0522 17.8855 20.5523C17.3854 21.0524 16.7071 21.3334 15.9998 21.3334Z" fill="white"/>
|
||||||
|
<path d="M30.048 5.49603L26.504 1.95203C25.8865 1.33115 25.1519 0.838932 24.3429 0.503869C23.5338 0.168806 22.6664 -0.00244608 21.7907 2.6395e-05H6.66667C4.89921 0.00214354 3.20474 0.705202 1.95496 1.95499C0.705176 3.20477 0.00211714 4.89923 0 6.66669L0 25.3334C0.00211714 27.1008 0.705176 28.7953 1.95496 30.0451C3.20474 31.2949 4.89921 31.9979 6.66667 32H25.3333C27.1008 31.9979 28.7953 31.2949 30.045 30.0451C31.2948 28.7953 31.9979 27.1008 32 25.3334V10.2094C32.0025 9.33368 31.8312 8.4662 31.4962 7.65715C31.1611 6.8481 30.6689 6.11355 30.048 5.49603ZM22.6667 2.77336V4.00003C22.6667 5.06089 22.2452 6.07831 21.4951 6.82845C20.7449 7.5786 19.7275 8.00003 18.6667 8.00003H13.3333C12.2725 8.00003 11.2551 7.5786 10.5049 6.82845C9.75476 6.07831 9.33333 5.06089 9.33333 4.00003V2.66669H21.7907C22.0857 2.66931 22.3796 2.70509 22.6667 2.77336ZM29.3333 25.3334C29.3333 26.3942 28.9119 27.4116 28.1618 28.1618C27.4116 28.9119 26.3942 29.3334 25.3333 29.3334H6.66667C5.6058 29.3334 4.58839 28.9119 3.83824 28.1618C3.08809 27.4116 2.66667 26.3942 2.66667 25.3334V6.66669C2.66667 5.60583 3.08809 4.58841 3.83824 3.83827C4.58839 3.08812 5.6058 2.66669 6.66667 2.66669V4.00003C6.66878 5.76749 7.37184 7.46195 8.62163 8.71173C9.87141 9.96152 11.5659 10.6646 13.3333 10.6667H18.6667C20.3433 10.6615 21.9562 10.0236 23.1828 8.88051C24.4095 7.73745 25.1594 6.17348 25.2827 4.50136L28.1627 7.38136C28.9099 8.13319 29.3306 9.14935 29.3333 10.2094V25.3334Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_1622_6669">
|
||||||
|
<rect width="32" height="32" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
3
src/assets/icons/seller/dui.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="24" height="17" viewBox="0 0 24 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M7.77 16.402C7.37319 16.4028 6.98013 16.3253 6.61339 16.1737C6.24666 16.0222 5.91348 15.7997 5.633 15.519L0 9.886L1.424 8.461L7.057 14.094C7.24602 14.2829 7.50229 14.389 7.7695 14.389C8.03671 14.389 8.29298 14.2829 8.482 14.094L22.576 0L24 1.425L9.906 15.519C9.62571 15.7997 9.2927 16.0222 8.92613 16.1737C8.55956 16.3252 8.16666 16.4028 7.77 16.402Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 479 B |
11
src/assets/icons/seller/edit.svg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_1571_1813)">
|
||||||
|
<path d="M24.8745 1.24001L8.61853 17.496C7.99765 18.1135 7.50544 18.8481 7.17037 19.6571C6.83531 20.4662 6.66406 21.3337 6.66653 22.2093V24C6.66653 24.3536 6.80701 24.6928 7.05705 24.9428C7.3071 25.1929 7.64624 25.3333 7.99986 25.3333H9.79053C10.6662 25.3358 11.5337 25.1646 12.3427 24.8295C13.1518 24.4944 13.8863 24.0022 14.5039 23.3813L30.7599 7.12535C31.5391 6.34424 31.9766 5.28598 31.9766 4.18268C31.9766 3.07938 31.5391 2.02112 30.7599 1.24001C29.9674 0.48254 28.9134 0.0598145 27.8172 0.0598145C26.721 0.0598145 25.667 0.48254 24.8745 1.24001ZM28.8745 5.24002L12.6185 21.496C11.8667 22.2433 10.8505 22.6639 9.79053 22.6667H9.3332V22.2093C9.33598 21.1493 9.75662 20.1332 10.5039 19.3813L26.7599 3.12535C27.0446 2.85329 27.4233 2.70147 27.8172 2.70147C28.2111 2.70147 28.5897 2.85329 28.8745 3.12535C29.1545 3.40603 29.3116 3.78627 29.3116 4.18268C29.3116 4.57909 29.1545 4.95933 28.8745 5.24002Z" fill="white"/>
|
||||||
|
<path d="M30.6667 11.972C30.313 11.972 29.9739 12.1125 29.7239 12.3625C29.4738 12.6126 29.3333 12.9517 29.3333 13.3053V20H24C22.9391 20 21.9217 20.4214 21.1716 21.1716C20.4214 21.9217 20 22.9391 20 24V29.3333H6.66667C5.6058 29.3333 4.58839 28.9119 3.83824 28.1618C3.08809 27.4116 2.66667 26.3942 2.66667 25.3333V6.66667C2.66667 5.6058 3.08809 4.58839 3.83824 3.83824C4.58839 3.08809 5.6058 2.66667 6.66667 2.66667H18.7227C19.0763 2.66667 19.4154 2.52619 19.6655 2.27614C19.9155 2.02609 20.056 1.68696 20.056 1.33333C20.056 0.979711 19.9155 0.640573 19.6655 0.390524C19.4154 0.140476 19.0763 0 18.7227 0L6.66667 0C4.89921 0.00211714 3.20474 0.705176 1.95496 1.95496C0.705176 3.20474 0.00211714 4.89921 0 6.66667L0 25.3333C0.00211714 27.1008 0.705176 28.7953 1.95496 30.045C3.20474 31.2948 4.89921 31.9979 6.66667 32H21.7907C22.6666 32.0025 23.5342 31.8313 24.3435 31.4962C25.1528 31.1612 25.8876 30.6689 26.5053 30.048L30.0467 26.504C30.6677 25.8865 31.1601 25.152 31.4953 24.3429C31.8306 23.5339 32.0022 22.6664 32 21.7907V13.3053C32 12.9517 31.8595 12.6126 31.6095 12.3625C31.3594 12.1125 31.0203 11.972 30.6667 11.972ZM24.62 28.1627C24.084 28.6973 23.4062 29.0675 22.6667 29.2293V24C22.6667 23.6464 22.8071 23.3072 23.0572 23.0572C23.3072 22.8071 23.6464 22.6667 24 22.6667H29.2333C29.0684 23.4047 28.6987 24.0812 28.1667 24.6187L24.62 28.1627Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_1571_1813">
|
||||||
|
<rect width="32" height="32" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.5 KiB |
11
src/assets/icons/seller/eye.svg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_1696_371)">
|
||||||
|
<path d="M17.4527 7.06427C16.2894 5.16977 13.6434 1.99127 8.99943 1.99127C4.35543 1.99127 1.70943 5.16977 0.546178 7.06427C0.186574 7.6459 -0.00390625 8.3162 -0.00390625 9.00002C-0.00390625 9.68384 0.186574 10.3541 0.546178 10.9358C1.70943 12.8303 4.35543 16.0088 8.99943 16.0088C13.6434 16.0088 16.2894 12.8303 17.4527 10.9358C17.8123 10.3541 18.0028 9.68384 18.0028 9.00002C18.0028 8.3162 17.8123 7.6459 17.4527 7.06427ZM16.1739 10.1505C15.1749 11.775 12.9137 14.5088 8.99943 14.5088C5.08518 14.5088 2.82393 11.775 1.82493 10.1505C1.61128 9.80481 1.49812 9.40643 1.49812 9.00002C1.49812 8.59362 1.61128 8.19524 1.82493 7.84952C2.82393 6.22502 5.08518 3.49127 8.99943 3.49127C12.9137 3.49127 15.1749 6.22202 16.1739 7.84952C16.3876 8.19524 16.5007 8.59362 16.5007 9.00002C16.5007 9.40643 16.3876 9.80481 16.1739 10.1505Z" fill="black"/>
|
||||||
|
<path d="M9 5.25C8.25832 5.25 7.5333 5.46993 6.91661 5.88199C6.29993 6.29404 5.81928 6.87971 5.53545 7.56494C5.25162 8.25016 5.17736 9.00416 5.32206 9.73159C5.46675 10.459 5.8239 11.1272 6.34835 11.6517C6.8728 12.1761 7.54098 12.5333 8.26841 12.6779C8.99584 12.8226 9.74984 12.7484 10.4351 12.4645C11.1203 12.1807 11.706 11.7001 12.118 11.0834C12.5301 10.4667 12.75 9.74168 12.75 9C12.7488 8.0058 12.3533 7.05267 11.6503 6.34967C10.9473 5.64666 9.9942 5.25119 9 5.25ZM9 11.25C8.55499 11.25 8.11998 11.118 7.74997 10.8708C7.37996 10.6236 7.09157 10.2722 6.92127 9.86104C6.75098 9.4499 6.70642 8.9975 6.79323 8.56105C6.88005 8.12459 7.09434 7.72368 7.40901 7.40901C7.72368 7.09434 8.12459 6.88005 8.56105 6.79323C8.99751 6.70642 9.44991 6.75097 9.86104 6.92127C10.2722 7.09157 10.6236 7.37996 10.8708 7.74997C11.118 8.11998 11.25 8.55499 11.25 9C11.25 9.59674 11.0129 10.169 10.591 10.591C10.169 11.0129 9.59674 11.25 9 11.25Z" fill="black"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_1696_371">
|
||||||
|
<rect width="18" height="18" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
11
src/assets/icons/seller/gouwudai.svg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_1696_334)">
|
||||||
|
<path d="M17.252 14.2499H15.752V12.7499C15.752 12.551 15.6729 12.3603 15.5323 12.2196C15.3916 12.079 15.2009 11.9999 15.002 11.9999C14.803 11.9999 14.6123 12.079 14.4716 12.2196C14.331 12.3603 14.252 12.551 14.252 12.7499V14.2499H12.752C12.553 14.2499 12.3623 14.329 12.2216 14.4696C12.081 14.6103 12.002 14.801 12.002 14.9999C12.002 15.1989 12.081 15.3896 12.2216 15.5303C12.3623 15.6709 12.553 15.7499 12.752 15.7499H14.252V17.2499C14.252 17.4489 14.331 17.6396 14.4716 17.7803C14.6123 17.9209 14.803 17.9999 15.002 17.9999C15.2009 17.9999 15.3916 17.9209 15.5323 17.7803C15.6729 17.6396 15.752 17.4489 15.752 17.2499V15.7499H17.252C17.4509 15.7499 17.6416 15.6709 17.7823 15.5303C17.9229 15.3896 18.002 15.1989 18.002 14.9999C18.002 14.801 17.9229 14.6103 17.7823 14.4696C17.6416 14.329 17.4509 14.2499 17.252 14.2499Z" fill="black"/>
|
||||||
|
<path d="M15.75 4.5H13.5C13.5 3.30653 13.0259 2.16193 12.182 1.31802C11.3381 0.474106 10.1935 0 9 0C7.80653 0 6.66193 0.474106 5.81802 1.31802C4.97411 2.16193 4.5 3.30653 4.5 4.5H2.25C1.65326 4.5 1.08097 4.73705 0.65901 5.15901C0.237053 5.58097 0 6.15326 0 6.75L0 14.25C0.00119089 15.2442 0.396661 16.1973 1.09966 16.9003C1.80267 17.6033 2.7558 17.9988 3.75 18H10.5C10.6989 18 10.8897 17.921 11.0303 17.7803C11.171 17.6397 11.25 17.4489 11.25 17.25C11.25 17.0511 11.171 16.8603 11.0303 16.7197C10.8897 16.579 10.6989 16.5 10.5 16.5H3.75C3.15326 16.5 2.58097 16.2629 2.15901 15.841C1.73705 15.419 1.5 14.8467 1.5 14.25V6.75C1.5 6.55109 1.57902 6.36032 1.71967 6.21967C1.86032 6.07902 2.05109 6 2.25 6H4.5V7.5C4.5 7.69891 4.57902 7.88968 4.71967 8.03033C4.86032 8.17098 5.05109 8.25 5.25 8.25C5.44891 8.25 5.63968 8.17098 5.78033 8.03033C5.92098 7.88968 6 7.69891 6 7.5V6H12V7.5C12 7.69891 12.079 7.88968 12.2197 8.03033C12.3603 8.17098 12.5511 8.25 12.75 8.25C12.9489 8.25 13.1397 8.17098 13.2803 8.03033C13.421 7.88968 13.5 7.69891 13.5 7.5V6H15.75C15.9489 6 16.1397 6.07902 16.2803 6.21967C16.421 6.36032 16.5 6.55109 16.5 6.75V10.5C16.5 10.6989 16.579 10.8897 16.7197 11.0303C16.8603 11.171 17.0511 11.25 17.25 11.25C17.4489 11.25 17.6397 11.171 17.7803 11.0303C17.921 10.8897 18 10.6989 18 10.5V6.75C18 6.15326 17.7629 5.58097 17.341 5.15901C16.919 4.73705 16.3467 4.5 15.75 4.5ZM6 4.5C6 3.70435 6.31607 2.94129 6.87868 2.37868C7.44129 1.81607 8.20435 1.5 9 1.5C9.79565 1.5 10.5587 1.81607 11.1213 2.37868C11.6839 2.94129 12 3.70435 12 4.5H6Z" fill="black"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_1696_334">
|
||||||
|
<rect width="18" height="18" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.6 KiB |
3
src/assets/icons/seller/preview.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 7V5C0 2.243 2.243 0 5 0H7C7.552 0 8 0.448 8 1C8 1.552 7.552 2 7 2H5C3.346 2 2 3.346 2 5V7C2 7.552 1.552 8 1 8C0.448 8 0 7.552 0 7ZM12 10C10.895 10 10 10.895 10 12C10 13.105 10.895 14 12 14C13.105 14 14 13.105 14 12C14 10.895 13.105 10 12 10ZM7 22H5C3.346 22 2 20.654 2 19V17C2 16.448 1.552 16 1 16C0.448 16 0 16.448 0 17V19C0 21.757 2.243 24 5 24H7C7.552 24 8 23.552 8 23C8 22.448 7.552 22 7 22ZM19 0H17C16.448 0 16 0.448 16 1C16 1.552 16.448 2 17 2H19C20.654 2 22 3.346 22 5V7C22 7.552 22.448 8 23 8C23.552 8 24 7.552 24 7V5C24 2.243 21.757 0 19 0ZM12 18C7.423 18 4.479 13.979 3.941 12.903C3.654 12.33 3.654 11.673 3.941 11.098C4.478 10.021 7.421 6 12 6C16.579 6 19.522 10.021 20.059 11.098C20.344 11.67 20.344 12.327 20.059 12.9C19.521 13.978 16.578 17.999 11.999 17.999L12 18ZM18.27 11.992C17.942 11.335 15.534 8 12 8C8.466 8 6.058 11.335 5.73 11.992C6.058 12.666 8.467 16 12 16C15.533 16 17.942 12.648 18.27 11.992ZM23 16C22.448 16 22 16.448 22 17V19C22 20.654 20.654 22 19 22H17C16.448 22 16 22.448 16 23C16 23.552 16.448 24 17 24H19C21.757 24 24 21.757 24 19V17C24 16.448 23.552 16 23 16Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
3
src/assets/icons/seller/qiandaizi.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="17" height="18" viewBox="0 0 17 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10.236 4.11975C10.8907 3.594 11.565 2.8875 11.907 2.028C12.0855 1.5795 12.0278 1.07025 11.7533 0.666C11.4705 0.249 11.0017 0 10.5 0H6C5.49825 0 5.0295 0.249 4.74675 0.666C4.47225 1.07025 4.41525 1.5795 4.593 2.028C4.935 2.88675 5.60925 3.594 6.264 4.11975C2.772 5.41575 0 9.86925 0 13.5C0 15.9818 2.01825 18 4.5 18H12C14.4818 18 16.5 15.9818 16.5 13.5C16.5 9.86925 13.728 5.41575 10.236 4.11975ZM10.5128 1.47375C10.1258 2.4465 8.94225 3.2685 8.2485 3.65625C7.55625 3.2715 6.37725 2.45625 5.99925 1.5L10.5128 1.47375ZM11.9993 16.5H4.5C2.8455 16.5 1.5 15.1545 1.5 13.5C1.5 9.56775 5.0325 5.25 8.25 5.25C11.4675 5.25 15 9.56775 15 13.5C15 15.1545 13.6538 16.5 11.9993 16.5ZM8.24925 16.5C7.83525 16.5 7.49925 16.164 7.49925 15.75V15H7.29825C6.49725 15 5.751 14.5695 5.34975 13.8757C5.14275 13.5173 5.265 13.059 5.6235 12.8512C5.9805 12.6435 6.44025 12.7657 6.648 13.125C6.7815 13.356 7.03125 13.5 7.29825 13.5H8.99925C9.4125 13.5 9.74925 13.1632 9.74925 12.75C9.74925 12.4665 9.546 12.2265 9.26625 12.18L6.98475 11.7997C5.979 11.6325 5.2485 10.77 5.2485 9.75C5.2485 8.5095 6.258 7.5 7.4985 7.5V6.75C7.4985 6.336 7.8345 6 8.2485 6C8.6625 6 8.9985 6.336 8.9985 6.75V7.5H9.1995C9.99975 7.5 10.7467 7.93125 11.148 8.625C11.355 8.9835 11.2327 9.44175 10.8742 9.6495C10.5165 9.85725 10.0575 9.735 9.84975 9.37575C9.7155 9.144 9.4665 9.00075 9.1995 9.00075H7.4985C7.08525 9.00075 6.7485 9.3375 6.7485 9.75075C6.7485 10.0343 6.95175 10.2743 7.2315 10.3207L9.513 10.701C10.5188 10.8682 11.2492 11.7307 11.2492 12.7507C11.2492 13.9913 10.2397 15.0007 8.99925 15.0007V15.7507C8.99925 16.1647 8.66325 16.5 8.24925 16.5Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
3
src/assets/icons/seller/search.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M19.7663 18.5889L14.7962 13.6188C16.1506 11.9623 16.8165 9.84866 16.6562 7.71497C16.4959 5.58128 15.5216 3.59083 13.9349 2.15534C12.3482 0.719841 10.2704 -0.0508742 8.13136 0.00260835C5.99233 0.0560909 3.95568 0.929679 2.44268 2.44268C0.929679 3.95568 0.0560909 5.99233 0.00260835 8.13136C-0.0508742 10.2704 0.719841 12.3482 2.15534 13.9349C3.59083 15.5216 5.58128 16.4959 7.71497 16.6562C9.84866 16.8165 11.9623 16.1506 13.6188 14.7962L18.5889 19.7663C18.7459 19.9179 18.9563 20.0019 19.1746 20C19.3929 19.9981 19.6017 19.9105 19.7561 19.7561C19.9105 19.6017 19.9981 19.3929 20 19.1746C20.0019 18.9563 19.9179 18.7459 19.7663 18.5889ZM8.35314 15.0143C7.03568 15.0143 5.74781 14.6237 4.65238 13.8917C3.55695 13.1598 2.70317 12.1194 2.199 10.9023C1.69483 9.6851 1.56292 8.34575 1.81994 7.05361C2.07697 5.76146 2.71138 4.57455 3.64297 3.64297C4.57455 2.71138 5.76146 2.07697 7.05361 1.81994C8.34575 1.56292 9.6851 1.69483 10.9023 2.199C12.1194 2.70317 13.1598 3.55695 13.8917 4.65238C14.6237 5.74781 15.0143 7.03568 15.0143 8.35314C15.0124 10.1192 14.3099 11.8123 13.0611 13.0611C11.8123 14.3099 10.1192 15.0124 8.35314 15.0143Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
3
src/assets/icons/seller/share.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M28 16H24C22.5293 16 21.3333 17.196 21.3333 18.6667C21.3333 20.1373 20.1373 21.3333 18.6667 21.3333H13.3333C11.8627 21.3333 10.6667 20.1373 10.6667 18.6667C10.6667 17.196 9.47067 16 8 16H4C1.79467 16 0 17.7947 0 20V25.3333C0 29.0093 2.99067 32 6.66667 32H25.3333C29.0093 32 32 29.0093 32 25.3333V20C32 17.7947 30.2053 16 28 16ZM29.3333 25.3333C29.3333 27.5387 27.5387 29.3333 25.3333 29.3333H6.66667C4.46133 29.3333 2.66667 27.5387 2.66667 25.3333V20C2.66667 19.264 3.264 18.6667 4 18.6667L8 18.664V18.6667C8 21.608 10.392 24 13.3333 24H18.6667C21.608 24 24 21.608 24 18.6667H28C28.736 18.6667 29.3333 19.264 29.3333 20V25.3333ZM9.724 7.05733C9.20267 6.536 9.20267 5.69333 9.724 5.172L14.1147 0.781333C14.6293 0.266667 15.3053 0.008 15.9813 0.004L16 0L16.0187 0.004C16.696 0.008 17.3707 0.266667 17.8853 0.781333L22.276 5.172C22.7973 5.69333 22.7973 6.536 22.276 7.05733C22.016 7.31733 21.6747 7.448 21.3333 7.448C20.992 7.448 20.6507 7.31733 20.3907 7.05733L17.3333 4V13.3333C17.3333 14.0707 16.7373 14.6667 16 14.6667C15.2627 14.6667 14.6667 14.0707 14.6667 13.3333V4L11.6093 7.05733C11.088 7.57867 10.2453 7.57867 9.724 7.05733Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
BIN
src/assets/images/seller/checked.png
Normal file
|
After Width: | Height: | Size: 479 B |
BIN
src/assets/images/seller/image-placeholder.png
Normal file
|
After Width: | Height: | Size: 621 B |
BIN
src/assets/images/seller/selectCollectionNullStatus.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
src/assets/images/seller/setting/alipay-chinese.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
src/assets/images/seller/setting/alipay-hk.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
BIN
src/assets/images/seller/setting/paypal.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
src/assets/images/seller/setting/stripe.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
src/assets/images/seller/tips.png
Normal file
|
After Width: | Height: | Size: 686 B |
|
Before Width: | Height: | Size: 73 KiB |
@@ -9,6 +9,11 @@
|
|||||||
"id": 2,
|
"id": 2,
|
||||||
"title": "AiDA X SFT AI Fashion Award 2024",
|
"title": "AiDA X SFT AI Fashion Award 2024",
|
||||||
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "AiDA Global Design Awards 2026",
|
||||||
|
"imgUrl": "/image/events/award-poster.gif"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"eventsItem": [
|
"eventsItem": [
|
||||||
@@ -16,18 +21,19 @@
|
|||||||
"id": 3,
|
"id": 3,
|
||||||
"title": "AiDA Global Design Awards 2026",
|
"title": "AiDA Global Design Awards 2026",
|
||||||
"imgUrl": "/image/events/award-poster.gif",
|
"imgUrl": "/image/events/award-poster.gif",
|
||||||
|
"tips": "For inquiries: awards2026@code-create.com.hk",
|
||||||
"textList": [
|
"textList": [
|
||||||
{
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "Click the “View Details” button for more information and to join the competition! The AiDA Global Design Award 2026 is an international design competition hosted by Code‑Create, a globally leading AI fashion solutions provider, celebrating the future of creativity powered by artificial intelligence. Open to designers from Hong Kong, China, Singapore, South Korea, and beyond, the competition brings together global talent, empowering AI as a creative partner—pushing fashion beyond traditional boundaries and unlocking new possibilities where technology amplifies human imagination."
|
"text": "Click the “View Details” button for more information and to join the competition! The AiDA Global Design Award 2026 is an international design competition hosted by Code‑Create, a globally leading AI fashion solutions provider, celebrating the future of creativity powered by artificial intelligence. Open to designers worldwide the competition brings together global talent, empowering AI as a creative partner—pushing fashion beyond traditional boundaries and unlocking new possibilities where technology amplifies human imagination."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "Participants have the opportunity to compete for cash prizes totaling up to US$9,000, gain global media exposure showcased by top international platforms, and connect with designers and industry leaders worldwide. Finalists will also attend an exclusive award ceremony in Hong Kong, with travel support provided, allowing them to showcase their talent, network with professionals, and celebrate their achievements on an international stage."
|
"text": "Participants have the opportunity to compete for cash prizes totaling up to US$9,000, gain global media exposure showcased by top international platforms, and connect with designers and industry leaders worldwide. Finalists will also attend an exclusive award ceremony in Hong Kong, with travel allowance, allowing them to showcase their talent, network with professionals, and celebrate their achievements on an international stage."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,11 @@
|
|||||||
"id": 2,
|
"id": 2,
|
||||||
"title": "AiDA X SFT AI时尚设计比赛2024",
|
"title": "AiDA X SFT AI时尚设计比赛2024",
|
||||||
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
"imgUrl": "/image/events/Fashion-Award-2024.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"title": "AiDA全球设计奖 2026",
|
||||||
|
"imgUrl": "/image/events/award-poster-zh.gif"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"eventsItem": [
|
"eventsItem": [
|
||||||
@@ -16,18 +21,19 @@
|
|||||||
"id": 3,
|
"id": 3,
|
||||||
"title": "AiDA全球设计奖 2026",
|
"title": "AiDA全球设计奖 2026",
|
||||||
"imgUrl": "/image/events/award-poster-zh.gif",
|
"imgUrl": "/image/events/award-poster-zh.gif",
|
||||||
|
"tips": "如有疑问,请联系:awards2026@code-create.com.hk",
|
||||||
"textList": [
|
"textList": [
|
||||||
{
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "秉承推动 AI 赋能创意设计的初衷,Code‑Create 举办了「AiDA 全球设计大奖 2026」,面向来自香港、中国、新加坡、韩国及全球的设计师,鼓励大家探索 AI 与时尚设计的无限可能,突破传统界限,释放科技与想象力的创新潜能。点击“查看详情”按钮获取更多比赛信息,抓住成为 AI 时尚先锋的机会吧!"
|
"text": "秉承推动 AI 赋能创意设计的初衷,Code‑Create 举办了「AiDA 全球设计大奖 2026」,面向来全球的设计师,鼓励大家探索 AI 与时尚设计的无限可能,突破传统界限,释放科技与想象力的创新潜能。点击“查看详情”按钮获取更多比赛信息,抓住成为 AI 时尚先锋的机会吧!"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"paragraph": [
|
"paragraph": [
|
||||||
{
|
{
|
||||||
"text": "参赛者将有机会赢取总奖金 9,000 美元,作品还将获得国际媒体展示机会,并与全球设计师和行业领袖建立联系。入围决赛者将受邀参加在香港举办的 专属颁奖典礼,主办方提供差旅支持,让设计师在国际舞台展示才华、拓展人脉,并共同庆祝创意成果。"
|
"text": "参赛者将有机会赢取总奖金 9,000 美元,作品还将获得国际媒体展示机会,并与全球设计师和行业领袖建立联系。入围决赛者将受邀参加在香港举办的 专属颁奖典礼,主办方提供差旅津贴,让设计师在国际舞台展示才华、拓展人脉,并共同庆祝创意成果。"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
&.ant-form-item-required:not(.ant-form-item-required-mark-optional) {
|
&.ant-form-item-required:not(.ant-form-item-required-mark-optional) {
|
||||||
&::before {
|
&::before {
|
||||||
content: "";
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
|
|||||||
@@ -1251,8 +1251,8 @@ tr > .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:last-child::afte
|
|||||||
border-color: #000 !important;
|
border-color: #000 !important;
|
||||||
}
|
}
|
||||||
.ant-spin .ant-spin-dot {
|
.ant-spin .ant-spin-dot {
|
||||||
width: 1.5em;
|
width: 4.5rem;
|
||||||
height: 1.5em;
|
height: 4.5rem;
|
||||||
}
|
}
|
||||||
.ant-spin-dot-item {
|
.ant-spin-dot-item {
|
||||||
background-color: #000000 !important;
|
background-color: #000000 !important;
|
||||||
@@ -2470,6 +2470,22 @@ textarea:focus {
|
|||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
border-radius: 0.7rem;
|
border-radius: 0.7rem;
|
||||||
}
|
}
|
||||||
|
.mini-scrollbar::-webkit-scrollbar {
|
||||||
|
width: 0.4rem;
|
||||||
|
}
|
||||||
|
.mini-scrollbar::-webkit-scrollbar-thumb {
|
||||||
|
border-radius: 0.4rem;
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
.mosaic-bg {
|
||||||
|
--mosaic-bg-size: 1rem;
|
||||||
|
--mosaic-bg-color1: #efefef;
|
||||||
|
--mosaic-bg-color2: #fff;
|
||||||
|
background-image: repeating-conic-gradient(var(--mosaic-bg-color1) 0% 25%, var(--mosaic-bg-color2) 0% 50%);
|
||||||
|
background-repeat: repeat;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-size: var(--mosaic-bg-size) var(--mosaic-bg-size);
|
||||||
|
}
|
||||||
.mark_loading {
|
.mark_loading {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -2507,6 +2523,6 @@ textarea:focus {
|
|||||||
.justify-center {
|
.justify-center {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
.flex-1{
|
.flex-1 {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,8 +172,9 @@ input:focus{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ant-modal-mask{
|
.ant-modal-mask{
|
||||||
background-color: #666666;
|
background-color: rgba(102,102,102,0.5);
|
||||||
opacity: .5;
|
// background-color: #666666;
|
||||||
|
// opacity: .5;
|
||||||
}
|
}
|
||||||
.select_block{
|
.select_block{
|
||||||
height: 4rem;
|
height: 4rem;
|
||||||
@@ -1379,8 +1380,8 @@ tr > .ant-picker-cell-in-view.ant-picker-cell-range-hover-start:last-child::afte
|
|||||||
}
|
}
|
||||||
//loding样式
|
//loding样式
|
||||||
.ant-spin .ant-spin-dot{
|
.ant-spin .ant-spin-dot{
|
||||||
width: 1.5em;
|
width: 4.5rem;
|
||||||
height: 1.5em;
|
height: 4.5rem;
|
||||||
}
|
}
|
||||||
.ant-spin-dot-item{
|
.ant-spin-dot-item{
|
||||||
background-color: #000000 !important;
|
background-color: #000000 !important;
|
||||||
@@ -2397,6 +2398,16 @@ textarea:focus{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mosaic-bg{
|
||||||
|
--mosaic-bg-size: 1rem;
|
||||||
|
--mosaic-bg-color1: #efefef;
|
||||||
|
--mosaic-bg-color2: #fff;
|
||||||
|
background-image: repeating-conic-gradient(var(--mosaic-bg-color1) 0% 25%, var(--mosaic-bg-color2) 0% 50%);
|
||||||
|
background-repeat: repeat;
|
||||||
|
background-position: 50% 50%;
|
||||||
|
background-size: var(--mosaic-bg-size) var(--mosaic-bg-size);
|
||||||
|
}
|
||||||
|
|
||||||
//蒙层样式
|
//蒙层样式
|
||||||
.mark_loading{
|
.mark_loading{
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
|||||||
@@ -266,9 +266,11 @@ export default defineComponent({
|
|||||||
.account_page{
|
.account_page{
|
||||||
height: 100%;
|
height: 100%;
|
||||||
// overflow-y: auto;
|
// overflow-y: auto;
|
||||||
padding: 0 26rem;
|
// padding: 0 26rem;
|
||||||
// padding: 0 7rem;
|
// padding: 0 7rem;
|
||||||
padding-top: 4rem;
|
padding-top: 4rem;
|
||||||
|
max-width: 100rem;
|
||||||
|
margin: 0 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
.account_page_titleImg{
|
.account_page_titleImg{
|
||||||
|
|||||||
@@ -1,22 +1,37 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="account_systemMessage">
|
<div class="account_systemMessage">
|
||||||
<div class="account_generalMessage_title modal_title_text">
|
<div class="account_generalMessage_title modal_title_text">
|
||||||
<!-- <span>系统消息</span> -->
|
<!-- <span>系统消息</span> -->
|
||||||
<div class="account_generalMessage_title_setting" @click="allRead">{{$t('account.AllRead')}}</div>
|
<div class="account_generalMessage_title_setting" @click="allRead">
|
||||||
|
{{ $t("account.AllRead") }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="account_generalMessage_item modal_title_text" v-for="item in dataList" :key="item.id" @click="setRead(item)">
|
<div
|
||||||
|
class="account_generalMessage_item modal_title_text"
|
||||||
|
v-for="item in dataList"
|
||||||
|
:key="item.id"
|
||||||
|
@click="setRead(item)"
|
||||||
|
>
|
||||||
<a-badge :dot="item.isRead == 0"></a-badge>
|
<a-badge :dot="item.isRead == 0"></a-badge>
|
||||||
<div class="account_generalMessage_item_title">
|
<div class="account_generalMessage_item_title">
|
||||||
<div class="account_generalMessage_item_title_text" :title="item.content">{{ item.content.title }}</div>
|
<div class="account_generalMessage_item_title_text" :title="item.content">
|
||||||
|
{{ item.content.title }}
|
||||||
|
</div>
|
||||||
<div class="modal_title_text_intro">{{ item.createTime }}</div>
|
<div class="modal_title_text_intro">{{ item.createTime }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal_title_text_intro">
|
<div class="modal_title_text_intro">
|
||||||
{{ item.content.content }}
|
{{ item.content.content }}
|
||||||
<span v-if="item.content.link" class="account_generalMessage_item_link">{{ item.content.link }}</span>
|
<span v-if="item.content.link" class="account_generalMessage_item_link">{{
|
||||||
|
item.content.link
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="account_generalMessage_item modal_title_text" style="display:flex;justify-content: center;" v-if="dataList.length == 0 && isNoData">
|
<div
|
||||||
{{$t('account.dataNull')}}
|
class="account_generalMessage_item modal_title_text"
|
||||||
|
style="display: flex; justify-content: center"
|
||||||
|
v-if="dataList.length == 0 && isNoData"
|
||||||
|
>
|
||||||
|
{{ $t("account.dataNull") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="page_loading_box" v-show="!isNoData">
|
<div class="page_loading_box" v-show="!isNoData">
|
||||||
<span class="page_loading" ref="loadingDom" v-show="!isShowMark"></span>
|
<span class="page_loading" ref="loadingDom" v-show="!isShowMark"></span>
|
||||||
@@ -24,120 +39,138 @@
|
|||||||
<a-spin size="large" />
|
<a-spin size="large" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent,computed,ref,reactive,nextTick,toRefs,createVNode, onMounted} from 'vue'
|
import {
|
||||||
import { Https } from "@/tool/https";
|
defineComponent,
|
||||||
import { useRouter,useRoute } from 'vue-router'
|
computed,
|
||||||
import { useStore } from "vuex";
|
ref,
|
||||||
import { useI18n } from 'vue-i18n'
|
reactive,
|
||||||
|
nextTick,
|
||||||
|
toRefs,
|
||||||
|
createVNode,
|
||||||
|
onMounted
|
||||||
|
} from "vue"
|
||||||
|
import { Https } from "@/tool/https"
|
||||||
|
import { useRouter, useRoute } from "vue-router"
|
||||||
|
import { useStore } from "vuex"
|
||||||
|
import { useI18n } from "vue-i18n"
|
||||||
|
import { isValidUrl } from "@/tool/util"
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components:{
|
components: {},
|
||||||
},
|
|
||||||
// emits:['putListData'],
|
// emits:['putListData'],
|
||||||
props:['setReadStatus','setAllmessage','getHistory'],
|
props: ["setReadStatus", "setAllmessage", "getHistory"],
|
||||||
setup(prop,{emit}) {
|
setup(prop, { emit }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const store = useStore();
|
const store = useStore()
|
||||||
let accountMessage = reactive({
|
let accountMessage = reactive({
|
||||||
dataList: [],
|
dataList: [],
|
||||||
page:1,
|
page: 1,
|
||||||
size:10,
|
size: 10,
|
||||||
isNoData: false,
|
isNoData: false,
|
||||||
isShowMark: false,
|
isShowMark: false
|
||||||
})
|
})
|
||||||
let loadingDom:any = ref(null)
|
let loadingDom: any = ref(null)
|
||||||
let setmessageList = ()=>{
|
let setmessageList = () => {
|
||||||
accountMessage.isShowMark = true
|
accountMessage.isShowMark = true
|
||||||
let data = {
|
let data = {
|
||||||
page: accountMessage.page,
|
page: accountMessage.page,
|
||||||
size: accountMessage.size,
|
size: accountMessage.size
|
||||||
}
|
}
|
||||||
prop.getHistory(data).then((rv:any)=>{
|
prop.getHistory(data)
|
||||||
accountMessage.isShowMark = false
|
.then((rv: any) => {
|
||||||
|
accountMessage.isShowMark = false
|
||||||
if(rv.content.length == 0) {
|
|
||||||
|
if (rv.content.length == 0) {
|
||||||
|
accountMessage.isNoData = true
|
||||||
|
} else {
|
||||||
|
rv.content.forEach((item: any) => {
|
||||||
|
item.content = JSON.parse(item.content)
|
||||||
|
})
|
||||||
|
accountMessage.dataList.push(...rv.content)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
accountMessage.isShowMark = false
|
||||||
accountMessage.isNoData = true
|
accountMessage.isNoData = true
|
||||||
}else{
|
})
|
||||||
rv.content.forEach((item:any) => {
|
}
|
||||||
item.content = JSON.parse(item.content)
|
let setRead = (item: any) => {
|
||||||
});
|
let content = item.content.content
|
||||||
accountMessage.dataList.push(...rv.content)
|
if (isValidUrl(content)) {
|
||||||
|
if (import.meta.env.VITE_APP_BASE_URL === "https://develop.api.aida.com.hk") {
|
||||||
|
content += "&env=dev"
|
||||||
}
|
}
|
||||||
}).catch(() => {
|
window.open(content, "_blank")
|
||||||
accountMessage.isShowMark = false
|
}
|
||||||
accountMessage.isNoData = true
|
|
||||||
})
|
prop.setReadStatus(item)
|
||||||
}
|
.then((rv: any) => {
|
||||||
let setRead = (item:any)=>{
|
|
||||||
prop.setReadStatus(item).then((rv:any)=>{
|
|
||||||
item.isRead = 1
|
|
||||||
}).catch((err:any)=>{
|
|
||||||
})
|
|
||||||
}
|
|
||||||
let allRead = ()=>{
|
|
||||||
// emit('setAllmessage')
|
|
||||||
prop.setAllmessage().then(()=>{
|
|
||||||
accountMessage.dataList.forEach((item:any)=>{
|
|
||||||
item.isRead = 1
|
item.isRead = 1
|
||||||
})
|
})
|
||||||
}).catch((err:any)=>{
|
.catch((err: any) => {})
|
||||||
})
|
}
|
||||||
|
let allRead = () => {
|
||||||
|
// emit('setAllmessage')
|
||||||
|
prop.setAllmessage()
|
||||||
|
.then(() => {
|
||||||
|
accountMessage.dataList.forEach((item: any) => {
|
||||||
|
item.isRead = 1
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((err: any) => {})
|
||||||
}
|
}
|
||||||
// provide('exhibitionList',exhibitionList)
|
// provide('exhibitionList',exhibitionList)
|
||||||
onMounted (()=>{
|
onMounted(() => {
|
||||||
accountMessage.isNoData = false
|
accountMessage.isNoData = false
|
||||||
accountMessage.page = 0
|
accountMessage.page = 0
|
||||||
let imgParent:any = document.querySelector('.account_systemMessage .page_loading')
|
let imgParent: any = document.querySelector(".account_systemMessage .page_loading")
|
||||||
new IntersectionObserver(
|
new IntersectionObserver(
|
||||||
(entries, observer) => {
|
(entries, observer) => {
|
||||||
// 如果不是相交,则直接返回
|
// 如果不是相交,则直接返回
|
||||||
// console.log(entries[0]);
|
// console.log(entries[0]);
|
||||||
if (!entries[0].intersectionRatio) return;
|
if (!entries[0].intersectionRatio) return
|
||||||
accountMessage.page+=1
|
accountMessage.page += 1
|
||||||
setmessageList()
|
setmessageList()
|
||||||
},
|
}
|
||||||
// { root:worksPage }
|
// { root:worksPage }
|
||||||
).observe(loadingDom.value);
|
).observe(loadingDom.value)
|
||||||
})
|
})
|
||||||
return{
|
return {
|
||||||
...toRefs(accountMessage),
|
...toRefs(accountMessage),
|
||||||
setmessageList,
|
setmessageList,
|
||||||
setRead,
|
setRead,
|
||||||
allRead,
|
allRead,
|
||||||
loadingDom,
|
loadingDom
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data(){
|
data() {
|
||||||
return{
|
return {}
|
||||||
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.account_systemMessage{
|
.account_systemMessage {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.account_generalMessage_item{
|
.account_generalMessage_item {
|
||||||
font-size: var(--aida-fsize1-6);
|
font-size: var(--aida-fsize1-6);
|
||||||
.account_generalMessage_item_title{
|
.account_generalMessage_item_title {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
.account_generalMessage_item_title_text{
|
.account_generalMessage_item_title_text {
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
.modal_title_text_intro{
|
.modal_title_text_intro {
|
||||||
margin-left: 4rem;
|
margin-left: 4rem;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.modal_title_text_intro{
|
.modal_title_text_intro {
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ commandManager.setChangeCallback((info) => {
|
|||||||
emit("undo-redo-status-changed", {
|
emit("undo-redo-status-changed", {
|
||||||
canUndo: canUndo.value,
|
canUndo: canUndo.value,
|
||||||
canRedo: canRedo.value,
|
canRedo: canRedo.value,
|
||||||
|
type: info.type,
|
||||||
commandManager,
|
commandManager,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -907,7 +907,8 @@
|
|||||||
}
|
}
|
||||||
emit("changeCanvas", commandData)
|
emit("changeCanvas", commandData)
|
||||||
canvasManager.changeCanvas()
|
canvasManager.changeCanvas()
|
||||||
if ((command.canUndo || command.canRedo) && props.enabledRedGreenMode) {
|
const type = command.type
|
||||||
|
if (props.enabledRedGreenMode && (type === "undo" || type === "redo")) {
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
try {
|
try {
|
||||||
const imageData = await canvasManager.exportImage({
|
const imageData = await canvasManager.exportImage({
|
||||||
@@ -1040,6 +1041,7 @@
|
|||||||
},
|
},
|
||||||
// 导出图片
|
// 导出图片
|
||||||
exportImage: async ({
|
exportImage: async ({
|
||||||
|
isFrontBackUpdata = false, // 更新红绿图时候需要用,直接更新红绿图
|
||||||
isContainBg = false, // 是否包含背景图层
|
isContainBg = false, // 是否包含背景图层
|
||||||
isContainFixed = false, // 是否包含固定图层
|
isContainFixed = false, // 是否包含固定图层
|
||||||
isContainFixedOther = true, // 是否包含其他固定图层--颜色图层
|
isContainFixedOther = true, // 是否包含其他固定图层--颜色图层
|
||||||
@@ -1056,6 +1058,10 @@
|
|||||||
} = {}) => {
|
} = {}) => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
canvasManager?.canvas?.discardActiveObject()
|
canvasManager?.canvas?.discardActiveObject()
|
||||||
|
if (isFrontBackUpdata) {
|
||||||
|
await canvasManager?.setSpecialCliptInfo(true, true)
|
||||||
|
canvasManager.canvas.renderAll()
|
||||||
|
}
|
||||||
var base64 = await canvasManager.exportImage({
|
var base64 = await canvasManager.exportImage({
|
||||||
isContainBg,
|
isContainBg,
|
||||||
isContainFixed,
|
isContainFixed,
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ export class BrushIndicator {
|
|||||||
// this.show(e.e);
|
// this.show(e.e);
|
||||||
this._mouseEnterHandler && this._mouseEnterHandler(e)
|
this._mouseEnterHandler && this._mouseEnterHandler(e)
|
||||||
} else {
|
} else {
|
||||||
// requestIdleCallback(() => {
|
// setTimeout(() => {
|
||||||
// this.updatePosition(e.e);
|
// this.updatePosition(e.e);
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
|||||||
@@ -133,11 +133,12 @@ export class RedGreenModeManager {
|
|||||||
this.canvas.on("mouse:up", (event) => {
|
this.canvas.on("mouse:up", (event) => {
|
||||||
// 可以在这里添加更多逻辑,比如生成图片或更新状态
|
// 可以在这里添加更多逻辑,比如生成图片或更新状态
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
requestIdleCallback(async () => {
|
setTimeout(async () => {
|
||||||
if (!this.isInitialized) {
|
if (!this.isInitialized) {
|
||||||
console.warn("红绿图模式未初始化,无法处理鼠标事件");
|
console.warn("红绿图模式未初始化,无法处理鼠标事件");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log("鼠标抬起事件触发", this.onImageGenerated);
|
||||||
if (this.onImageGenerated) {
|
if (this.onImageGenerated) {
|
||||||
const imageData = await this.canvasManager.exportImage({
|
const imageData = await this.canvasManager.exportImage({
|
||||||
restoreOpacityInRedGreen: true, // 恢复红绿图模式下的透明度
|
restoreOpacityInRedGreen: true, // 恢复红绿图模式下的透明度
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ export class ThumbnailManager {
|
|||||||
|
|
||||||
// 延迟执行,避免阻塞UI
|
// 延迟执行,避免阻塞UI
|
||||||
fabricObjects.length > 0 &&
|
fabricObjects.length > 0 &&
|
||||||
requestIdleCallback(() => {
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const base64 = await this._generateLayerThumbnailNow(fabricObjects, layer);
|
const base64 = await this._generateLayerThumbnailNow(fabricObjects, layer);
|
||||||
// this.layerThumbnails.set(layerId, base64);
|
// this.layerThumbnails.set(layerId, base64);
|
||||||
@@ -55,7 +54,6 @@ export class ThumbnailManager {
|
|||||||
console.error("生成图层缩略图时出错:", error);
|
console.error("生成图层缩略图时出错:", error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,7 +63,7 @@ export class ThumbnailManager {
|
|||||||
generateAllLayerThumbnails(layers) {
|
generateAllLayerThumbnails(layers) {
|
||||||
if (!layers || !Array.isArray(layers)) return;
|
if (!layers || !Array.isArray(layers)) return;
|
||||||
|
|
||||||
requestIdleCallback(() => {
|
setTimeout(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
layers.forEach((layer) => {
|
layers.forEach((layer) => {
|
||||||
if (layer && layer.id) {
|
if (layer && layer.id) {
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ export class CommandManager {
|
|||||||
this._recordPerformance("execute", command.constructor.name, duration);
|
this._recordPerformance("execute", command.constructor.name, duration);
|
||||||
|
|
||||||
// 通知状态变化
|
// 通知状态变化
|
||||||
this._notifyStateChange();
|
this._notifyStateChange("execute");
|
||||||
|
|
||||||
console.log(`✅ 命令执行成功: ${command.constructor.name}`);
|
console.log(`✅ 命令执行成功: ${command.constructor.name}`);
|
||||||
return result;
|
return result;
|
||||||
@@ -219,7 +219,7 @@ export class CommandManager {
|
|||||||
this._recordPerformance("undo", command.constructor.name, duration);
|
this._recordPerformance("undo", command.constructor.name, duration);
|
||||||
|
|
||||||
// 通知状态变化
|
// 通知状态变化
|
||||||
this._notifyStateChange();
|
this._notifyStateChange("undo");
|
||||||
|
|
||||||
console.log(`✅ 命令撤销成功: ${command.constructor.name}`);
|
console.log(`✅ 命令撤销成功: ${command.constructor.name}`);
|
||||||
return result;
|
return result;
|
||||||
@@ -258,7 +258,7 @@ export class CommandManager {
|
|||||||
this._recordPerformance("redo", command.constructor.name, duration);
|
this._recordPerformance("redo", command.constructor.name, duration);
|
||||||
|
|
||||||
// 通知状态变化
|
// 通知状态变化
|
||||||
this._notifyStateChange();
|
this._notifyStateChange("redo");
|
||||||
|
|
||||||
console.log(`✅ 命令重做成功: ${command.constructor.name}`);
|
console.log(`✅ 命令重做成功: ${command.constructor.name}`);
|
||||||
return result;
|
return result;
|
||||||
@@ -298,7 +298,7 @@ export class CommandManager {
|
|||||||
|
|
||||||
this.undoStack = [];
|
this.undoStack = [];
|
||||||
this.redoStack = [];
|
this.redoStack = [];
|
||||||
this._notifyStateChange();
|
this._notifyStateChange("clear");
|
||||||
// console.log("📝 命令历史已清空");
|
// console.log("📝 命令历史已清空");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,10 +417,12 @@ export class CommandManager {
|
|||||||
* 通知状态变化
|
* 通知状态变化
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_notifyStateChange() {
|
_notifyStateChange(type) {
|
||||||
if (this.onStateChange) {
|
if (this.onStateChange) {
|
||||||
try {
|
try {
|
||||||
this.onStateChange(this.getState());
|
const obj = this.getState();
|
||||||
|
obj.type = type;
|
||||||
|
this.onStateChange(obj);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("状态变化回调执行失败:", error);
|
console.error("状态变化回调执行失败:", error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export class LiquifyRealTimeUpdater {
|
|||||||
|
|
||||||
if (isDrawing && this.config.useDirectUpdate) {
|
if (isDrawing && this.config.useDirectUpdate) {
|
||||||
// 拖拽过程中使用快速更新(降低质量以提高性能)
|
// 拖拽过程中使用快速更新(降低质量以提高性能)
|
||||||
this._fastUpdate(imageData);
|
await this._fastUpdate(imageData);
|
||||||
} else {
|
} else {
|
||||||
// 拖拽结束后使用完整更新(最高质量)
|
// 拖拽结束后使用完整更新(最高质量)
|
||||||
await this._fullUpdate(imageData);
|
await this._fullUpdate(imageData);
|
||||||
@@ -124,7 +124,7 @@ export class LiquifyRealTimeUpdater {
|
|||||||
* @param {ImageData} imageData 图像数据
|
* @param {ImageData} imageData 图像数据
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_fastUpdate(imageData) {
|
async _fastUpdate(imageData) {
|
||||||
if (!this.targetObject || !this.targetObject._element) {
|
if (!this.targetObject || !this.targetObject._element) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -138,12 +138,14 @@ export class LiquifyRealTimeUpdater {
|
|||||||
|
|
||||||
// 直接更新fabric对象的图像源(使用PNG格式保持质量)
|
// 直接更新fabric对象的图像源(使用PNG格式保持质量)
|
||||||
const targetElement = this.targetObject._element;
|
const targetElement = this.targetObject._element;
|
||||||
|
|
||||||
// 方案1: 直接设置src属性(最高性能)
|
// 方案1: 直接设置src属性(最高性能)
|
||||||
const dataURL = this.tempCanvas.toDataURL("image/png", quality);
|
const dataURL = this.tempCanvas.toDataURL("image/png", quality);
|
||||||
|
|
||||||
if (targetElement.src !== dataURL) {
|
if (targetElement.src !== dataURL) {
|
||||||
targetElement.src = dataURL;
|
// targetElement.src = dataURL;
|
||||||
|
const image = new Image();
|
||||||
|
image.src = dataURL;
|
||||||
|
await image.decode();
|
||||||
|
this.targetObject.setElement(image);
|
||||||
|
|
||||||
// 关键优化:直接设置fabric对象为脏状态,但不立即渲染
|
// 关键优化:直接设置fabric对象为脏状态,但不立即渲染
|
||||||
// this.targetObject.dirty = false; // 标记为不需要立即渲染
|
// this.targetObject.dirty = false; // 标记为不需要立即渲染
|
||||||
@@ -153,7 +155,7 @@ export class LiquifyRealTimeUpdater {
|
|||||||
// 使用requestAnimationFrame进行批量渲染优化
|
// 使用requestAnimationFrame进行批量渲染优化
|
||||||
// if (!this.renderingScheduled && !this.config.skipRenderDuringDrag) {
|
// if (!this.renderingScheduled && !this.config.skipRenderDuringDrag) {
|
||||||
// this.renderingScheduled = true;
|
// this.renderingScheduled = true;
|
||||||
// requestIdleCallback(() => {
|
// setTimeout(() => {
|
||||||
// this.canvas.renderAll();
|
// this.canvas.renderAll();
|
||||||
// this.renderingScheduled = false;
|
// this.renderingScheduled = false;
|
||||||
// });
|
// });
|
||||||
|
|||||||
@@ -447,6 +447,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</CanvasEditor>
|
</CanvasEditor>
|
||||||
</div>
|
</div>
|
||||||
|
<img src="" alt="" id="canvas-test-dom">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style>
|
<style>
|
||||||
@@ -458,6 +459,13 @@
|
|||||||
height: 600px !important;
|
height: 600px !important;
|
||||||
z-index: 99999999;
|
z-index: 99999999;
|
||||||
}
|
}
|
||||||
|
#canvas-test-dom{
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9999999999;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
* {
|
* {
|
||||||
|
|||||||
@@ -163,7 +163,6 @@ export default defineComponent({
|
|||||||
const privewDetail = async (oldSelectDetail = detailData.selectDetail)=>{
|
const privewDetail = async (oldSelectDetail = detailData.selectDetail)=>{
|
||||||
// if(!detailDom.editCanvas)return
|
// if(!detailDom.editCanvas)return
|
||||||
return new Promise(async (res,reject)=>{
|
return new Promise(async (res,reject)=>{
|
||||||
console.log(detailDom.editCanvas)
|
|
||||||
await detailDom.editCanvas.exportImage({
|
await detailDom.editCanvas.exportImage({
|
||||||
isContainFixed:true,
|
isContainFixed:true,
|
||||||
width:props.sketchSize.width,
|
width:props.sketchSize.width,
|
||||||
@@ -245,17 +244,27 @@ export default defineComponent({
|
|||||||
|
|
||||||
|
|
||||||
const frontBackChange = async (value:any)=>{
|
const frontBackChange = async (value:any)=>{
|
||||||
|
let front = detailData.frontBack.front[detailData.imgDomIndex]
|
||||||
|
let back = detailData.frontBack.back[detailData.imgDomIndex]
|
||||||
|
store.commit('DesignDetail/updataDetailItem',{maskUrl:value})
|
||||||
|
await nextTick()
|
||||||
if(!detailData.selectDetail.partialDesign.partialDesignPath && !detailData.selectDetail.partialDesign.partialDesignBase64){
|
if(!detailData.selectDetail.partialDesign.partialDesignPath && !detailData.selectDetail.partialDesign.partialDesignBase64){
|
||||||
await privewDetail()
|
await privewDetail()
|
||||||
|
}else{
|
||||||
|
await detailDom.editCanvas.exportImage({
|
||||||
|
isFrontBackUpdata: true,
|
||||||
|
isContainFixed:true,
|
||||||
|
width:props.sketchSize.width,
|
||||||
|
height:props.sketchSize.height,
|
||||||
|
}).then((rv)=>{
|
||||||
|
if(detailData.selectDetail?.partialDesign)detailData.selectDetail.partialDesign.partialDesignBase64 = rv
|
||||||
|
})
|
||||||
}
|
}
|
||||||
let full = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.partialDesign.partialDesignPath || detailData.selectDetail.path
|
let full = detailData.selectDetail.partialDesign.partialDesignBase64 || detailData.selectDetail.partialDesign.partialDesignPath || detailData.selectDetail.path
|
||||||
let size = {
|
let size = {
|
||||||
...detailData.canvasConfig,
|
...detailData.canvasConfig,
|
||||||
}
|
}
|
||||||
store.commit('DesignDetail/updataDetailItem',{maskUrl:value})
|
|
||||||
segmentImage(value,full,size).then(async (rv)=>{
|
segmentImage(value,full,size).then(async (rv)=>{
|
||||||
let front = detailData.frontBack.front[detailData.imgDomIndex]
|
|
||||||
let back = detailData.frontBack.back[detailData.imgDomIndex]
|
|
||||||
if(!front?.oldImageUrl)front.oldImageUrl = front.imageUrl
|
if(!front?.oldImageUrl)front.oldImageUrl = front.imageUrl
|
||||||
if(!front?.oldMaskUrl)front.oldMaskUrl = front.maskUrl
|
if(!front?.oldMaskUrl)front.oldMaskUrl = front.maskUrl
|
||||||
if(!back?.oldImageUrl)back.oldImageUrl = back.imageUrl
|
if(!back?.oldImageUrl)back.oldImageUrl = back.imageUrl
|
||||||
@@ -267,7 +276,6 @@ export default defineComponent({
|
|||||||
back.imageUrl = rv.targetBackUrl
|
back.imageUrl = rv.targetBackUrl
|
||||||
// store.commit('DesignDetail/updataDetailItem',{maskUrl:value})
|
// store.commit('DesignDetail/updataDetailItem',{maskUrl:value})
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
const editSketchCanvasInit = async (value:any)=>{
|
const editSketchCanvasInit = async (value:any)=>{
|
||||||
detailData.canvasInstance = value
|
detailData.canvasInstance = value
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
<div class="upload_item">
|
<div class="upload_item">
|
||||||
<div class="upload_file_item upload_component">
|
<div class="upload_file_item upload_component">
|
||||||
<a-upload
|
<a-upload
|
||||||
:action="uploadUrl + (upLoadHttpsUrl?upLoadHttpsUrl:'/api/element/upload')"
|
:action="uploadUrl + (upLoadHttpsUrl?upLoadHttpsUrl:'/aida/api/element/upload')"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
:multiple="true"
|
:multiple="true"
|
||||||
|
|||||||
@@ -233,10 +233,10 @@ export default defineComponent({
|
|||||||
let sketchH = editPrintElementData.sketchWH.height * editPrintElementData.sketchWH.scale[1]
|
let sketchH = editPrintElementData.sketchWH.height * editPrintElementData.sketchWH.scale[1]
|
||||||
let x = sketchW / 2 - (sketchW * (width / editPrintElementData.sketchWH.width)/2)
|
let x = sketchW / 2 - (sketchW * (width / editPrintElementData.sketchWH.width)/2)
|
||||||
let y = sketchH / 2 -(sketchH * height/2)
|
let y = sketchH / 2 -(sketchH * height/2)
|
||||||
if(editPrintElementData.stateOverallSingle !== 'single'){
|
// if(editPrintElementData.stateOverallSingle !== 'single'){
|
||||||
x = sketchW / 2
|
// x = sketchW / 2
|
||||||
y = sketchH / 2
|
// y = sketchH / 2
|
||||||
}
|
// }
|
||||||
let location = [x,y]
|
let location = [x,y]
|
||||||
resolve({scale,location})
|
resolve({scale,location})
|
||||||
}
|
}
|
||||||
@@ -393,8 +393,8 @@ export default defineComponent({
|
|||||||
angle: 0,
|
angle: 0,
|
||||||
flipX: false,
|
flipX: false,
|
||||||
flipY: false,
|
flipY: false,
|
||||||
// blendMode: "multiply",
|
blendMode: "multiply",
|
||||||
blendMode: "source-over",
|
// blendMode: "source-over",
|
||||||
gapX: 0,
|
gapX: 0,
|
||||||
gapY: 0,
|
gapY: 0,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,11 +189,11 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
return { scaleX, scaleY, rotate };
|
return { scaleX, scaleY, rotate };
|
||||||
}
|
}
|
||||||
const initMoveableForSelected = () => {
|
const initMoveableForSelected = async (isDestroy:boolean = false) => {
|
||||||
// 销毁旧的实例
|
// 销毁旧的实例
|
||||||
if(selectItem.imgDomIndex == -1)return
|
if(selectItem.imgDomIndex == -1)return
|
||||||
if (moveableInstance.value) {
|
if (moveableInstance?.value?.destroy && !isDestroy) {
|
||||||
moveableInstance.value.destroy();
|
moveableInstance?.value?.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedEl = elementRefs.value[selectItem.imgDomIndex];
|
const selectedEl = elementRefs.value[selectItem.imgDomIndex];
|
||||||
@@ -509,7 +509,7 @@ export default defineComponent({
|
|||||||
watch(()=>detailData.frontBack.front.length,(newValue,oldValue)=>{
|
watch(()=>detailData.frontBack.front.length,(newValue,oldValue)=>{
|
||||||
if(selectItem.selectDetail?.id)selectItem.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == selectItem.selectDetail?.id)
|
if(selectItem.selectDetail?.id)selectItem.imgDomIndex = detailData.frontBack.front.findIndex((item:any)=>item.id == selectItem.selectDetail?.id)
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
initMoveableForSelected()
|
initMoveableForSelected(oldValue == 0)
|
||||||
},100)
|
},100)
|
||||||
})
|
})
|
||||||
const setRevocation = async ()=>{
|
const setRevocation = async ()=>{
|
||||||
|
|||||||
@@ -21,7 +21,11 @@
|
|||||||
{{ $t("event.detail") }}
|
{{ $t("event.detail") }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal_title_text content" v-for="item in eventsDetail.textList">
|
<div
|
||||||
|
class="modal_title_text content"
|
||||||
|
v-for="item in eventsDetail.textList"
|
||||||
|
:class="{ award: eventsDetail.id === 3 }"
|
||||||
|
>
|
||||||
<div class="eventsDetail_content_right_btn_box">
|
<div class="eventsDetail_content_right_btn_box">
|
||||||
<div
|
<div
|
||||||
class="eventsDetail_content_right_btn"
|
class="eventsDetail_content_right_btn"
|
||||||
@@ -43,6 +47,7 @@
|
|||||||
v-detailText="introItem.text"
|
v-detailText="introItem.text"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tips" v-if="eventsDetail.tips">{{ eventsDetail.tips }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -120,11 +125,16 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
const openDetail = () => {
|
const openDetail = () => {
|
||||||
let language = locale.value === "ENGLISH" ? "en" : "zh"
|
let language = locale.value === "ENGLISH" ? "en" : "cn"
|
||||||
let url = `https://aida-global-design-awards.com.hk/${language}`
|
let url = `https://aida-global-design-awards.com.hk/${language}`
|
||||||
|
// 如果是dev环境把域名换成http://192.168.31.198
|
||||||
|
|
||||||
|
if (import.meta.env.VITE_APP_BASE_URL === "https://develop.api.aida.com.hk") {
|
||||||
|
url += "?env=dev"
|
||||||
|
}
|
||||||
window.open(url, "_blank")
|
window.open(url, "_blank")
|
||||||
|
|
||||||
// router.push("/award/index")
|
// router.push("/award/index")
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const currentLocale = locale.value
|
const currentLocale = locale.value
|
||||||
@@ -233,7 +243,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
.eventsDetail_content_right {
|
.eventsDetail_content_right {
|
||||||
.modal_title_text {
|
.modal_title_text {
|
||||||
letter-spacing: 0.4rem;
|
letter-spacing: 0.3rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
&-header {
|
&-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -265,18 +275,21 @@ export default defineComponent({
|
|||||||
.eventsDetail_content_right_btn_box {
|
.eventsDetail_content_right_btn_box {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
.eventsDetail_content_right_btn {
|
// .eventsDetail_content_right_btn {
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.modal_title_text:last-child {
|
// .modal_title_text:last-child {
|
||||||
}
|
// }
|
||||||
.modal_title_text:last-child::after {
|
.modal_title_text:last-child::after {
|
||||||
content: "";
|
content: "";
|
||||||
display: block;
|
display: block;
|
||||||
border-top: 3px solid;
|
border-top: 3px solid;
|
||||||
height: 6rem;
|
height: 6rem;
|
||||||
}
|
}
|
||||||
|
.modal_title_text.award:last-child:after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -293,4 +306,13 @@ export default defineComponent({
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.tips{
|
||||||
|
color: rgba(0, 0, 0, 0.45);
|
||||||
|
font-size: var(--aida-fsize1-4);
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0.3rem;
|
||||||
|
}
|
||||||
|
.modal_title_text.content.award{
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
<a-upload
|
<a-upload
|
||||||
class="search_upImg"
|
class="search_upImg"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
:action="uploadUrl + '/api/element/upload'"
|
:action="uploadUrl + '/aida/api/element/upload'"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:data="{
|
:data="{
|
||||||
...upload
|
...upload
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
<a-upload
|
<a-upload
|
||||||
class="search_upImg"
|
class="search_upImg"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
:action="uploadUrl + '/api/element/upload'"
|
:action="uploadUrl + '/aida/api/element/upload'"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:data="{
|
:data="{
|
||||||
...upload
|
...upload
|
||||||
@@ -531,7 +531,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
const setSpeed = (item: any) => {
|
const setSpeed = (item: any) => {
|
||||||
speed.speedData = item
|
speed.speedData = {...item}
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.msg == 'Sketchboard') {
|
if (props.msg == 'Sketchboard') {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<div class="upload_file_item upload_component" v-show="fileList.length < 15">
|
<div class="upload_file_item upload_component" v-show="fileList.length < 15">
|
||||||
<a-upload
|
<a-upload
|
||||||
:capture="null"
|
:capture="null"
|
||||||
:action="uploadUrl + '/api/element/upload'"
|
:action="uploadUrl + '/aida/api/element/upload'"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:data="{
|
:data="{
|
||||||
...upload
|
...upload
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="upload_file_item upload_component" v-show="fileList.length < 10">
|
<div class="upload_file_item upload_component" v-show="fileList.length < 10">
|
||||||
<a-upload
|
<a-upload
|
||||||
:action="uploadUrl + '/api/element/upload'"
|
:action="uploadUrl + '/aida/api/element/upload'"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:data="{
|
:data="{
|
||||||
|
|||||||
@@ -103,7 +103,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<a-upload
|
<a-upload
|
||||||
:capture="null"
|
:capture="null"
|
||||||
:action="uploadUrl + '/api/element/upload'"
|
:action="uploadUrl + '/aida/api/element/upload'"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:data="{
|
:data="{
|
||||||
...upload,
|
...upload,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<!-- <div class="newPosted_generalMessage_title_setting pointer" @click="allRead">全部已读</div> -->
|
<!-- <div class="newPosted_generalMessage_title_setting pointer" @click="allRead">全部已读</div> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="newPosted_generalMessage_center modal_title_text">
|
<div class="newPosted_generalMessage_center modal_title_text">
|
||||||
<div class="newPosted_generalMessage_item" v-for="item in dataList" :key="item.id" @click="setRead(item)">
|
<div class="newPosted_generalMessage_item" v-for="item in dataList" :key="item.id">
|
||||||
<!-- <a-badge :dot="item.isRead == 0"></a-badge> -->
|
<!-- <a-badge :dot="item.isRead == 0"></a-badge> -->
|
||||||
<div class="newPosted_generalMessage_item_right">
|
<div class="newPosted_generalMessage_item_right">
|
||||||
<div class="newPosted_generalMessage_item_img pointer" @click="openOtherUsers(item)">
|
<div class="newPosted_generalMessage_item_img pointer" @click="openOtherUsers(item)">
|
||||||
|
|||||||
@@ -205,7 +205,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="payment">
|
<div class="payment">
|
||||||
<div class="allocation">
|
<div class="allocation">
|
||||||
<div class="selectType">
|
<!-- <div class="selectType">
|
||||||
<div class="text">{{ $t('Renew.Payment') }}:</div>
|
<div class="text">{{ $t('Renew.Payment') }}:</div>
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
/>
|
/>
|
||||||
{{ $t('Renew.Alipay') }}
|
{{ $t('Renew.Alipay') }}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
<div class="gallery_btn gallery_btn_radius" @click="payment">
|
<div class="gallery_btn gallery_btn_radius" @click="payment">
|
||||||
{{ $t('upgradePlan.Continue') }}
|
{{ $t('upgradePlan.Continue') }}
|
||||||
|
|||||||
@@ -77,17 +77,10 @@ export default defineComponent({
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(-50%,-50%);
|
transform: translate(-50%,-50%);
|
||||||
width: 80%;
|
|
||||||
height: auto;
|
|
||||||
max-height: 80vh;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: max-content;
|
|
||||||
video{
|
video{
|
||||||
width: 100%;
|
max-height:80vh;
|
||||||
max-height: 80vh;
|
max-width:80vw;
|
||||||
height: 100%;
|
|
||||||
object-fit: contain;
|
|
||||||
width: max-content;
|
|
||||||
}
|
}
|
||||||
.general_video_btn{
|
.general_video_btn{
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
<div class="upload_item" v-show="uploadList.length < 1">
|
<div class="upload_item" v-show="uploadList.length < 1">
|
||||||
<div class="upload_file_item upload_component">
|
<div class="upload_file_item upload_component">
|
||||||
<a-upload
|
<a-upload
|
||||||
:action="uploadUrl + '/api/history/brandLogoUpload'"
|
:action="uploadUrl + '/aida/api/history/brandLogoUpload'"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
:headers="{ Authorization: token }"
|
:headers="{ Authorization: token }"
|
||||||
|
|||||||
@@ -213,10 +213,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="upload_file_item upload_component">
|
<div class="upload_file_item upload_component">
|
||||||
<!-- :action="uploadUrl + '/api/history/toProductImageElementUpload'" -->
|
<!-- :action="uploadUrl + '/aida/api/history/toProductImageElementUpload'" -->
|
||||||
<a-upload
|
<a-upload
|
||||||
:action="
|
:action="
|
||||||
getUploadUrl() + '/api/history/toProductImageElementUpload'
|
getUploadUrl() + '/aida/api/history/toProductImageElementUpload'
|
||||||
"
|
"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
>
|
>
|
||||||
|
|
||||||
<a-upload
|
<a-upload
|
||||||
:action="uploadUrl + '/api/element/upload'"
|
:action="uploadUrl + '/aida/api/element/upload'"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
:data="{
|
:data="{
|
||||||
|
|||||||
@@ -54,7 +54,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="upload_file_item upload_component" v-show="printboardList.length < 16">
|
<div class="upload_file_item upload_component" v-show="printboardList.length < 16">
|
||||||
<a-upload
|
<a-upload
|
||||||
:action="uploadUrl + '/api/element/upload'"
|
:action="uploadUrl + '/aida/api/element/upload'"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:before-upload="beforeUpload"
|
:before-upload="beforeUpload"
|
||||||
@@ -415,7 +415,7 @@ export default defineComponent({
|
|||||||
file:data.originFileObj
|
file:data.originFileObj
|
||||||
}
|
}
|
||||||
let fileUid = data.uid
|
let fileUid = data.uid
|
||||||
Https.axiosPost('/api/element/upload', new_data,{headers:{'Content-Type': 'multipart/form-data'}}).then(
|
Https.axiosPost('/aida/api/element/upload', new_data,{headers:{'Content-Type': 'multipart/form-data'}}).then(
|
||||||
(rv: any) => {
|
(rv: any) => {
|
||||||
if (rv) {
|
if (rv) {
|
||||||
for(let file of this.fileList){
|
for(let file of this.fileList){
|
||||||
@@ -491,7 +491,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
this.isUpload = true
|
this.isUpload = true
|
||||||
const hide = message.loading('loading', 0);
|
const hide = message.loading('loading', 0);
|
||||||
Https.axiosPost('/api/element/upload', new_data,{headers:{'Content-Type': 'multipart/form-data'}}).then(
|
Https.axiosPost('/aida/api/element/upload', new_data,{headers:{'Content-Type': 'multipart/form-data'}}).then(
|
||||||
(rv: any) => {
|
(rv: any) => {
|
||||||
for(let file of this.fileList){
|
for(let file of this.fileList){
|
||||||
if(fileData.uid === file.uid){
|
if(fileData.uid === file.uid){
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
v-show="sketchboardList.length < 20"
|
v-show="sketchboardList.length < 20"
|
||||||
>
|
>
|
||||||
<a-upload
|
<a-upload
|
||||||
:action="uploadUrl + '/api/element/upload'"
|
:action="uploadUrl + '/aida/api/element/upload'"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:data="{
|
:data="{
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<keep-alive :include="cachedRoutes">
|
<keep-alive :include="cachedRoutes">
|
||||||
<component
|
<component
|
||||||
:is="Component"
|
:is="Component"
|
||||||
:key="route.name"
|
:cachedRoutes="cachedRoutes"
|
||||||
/>
|
/>
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</router-view>
|
</router-view>
|
||||||
|
|||||||
@@ -41,10 +41,10 @@
|
|||||||
<div class="center">{{ selectObject?.styleName?selectObject?.styleName:$t('Header.All') }}</div>
|
<div class="center">{{ selectObject?.styleName?selectObject?.styleName:$t('Header.All') }}</div>
|
||||||
<div class="gallery_btn" @click="setStyle">{{ $t('Habit.Select') }}</div>
|
<div class="gallery_btn" @click="setStyle">{{ $t('Habit.Select') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="style brand marginBottom">
|
<!-- <div class="style brand marginBottom">
|
||||||
<div class="text">{{$t('Habit.Brand')}}:</div>
|
<div class="text">{{$t('Habit.Brand')}}:</div>
|
||||||
<div class="gallery_btn" @click="setBrandDNA">{{ $t('Habit.Select') }}</div>
|
<div class="gallery_btn" @click="setBrandDNA">{{ $t('Habit.Select') }}</div>
|
||||||
</div>
|
</div> -->
|
||||||
<div class="brandImg" v-if="selectObject.userBrandDna"><img :src="selectObject.userBrandDnaImg"></div>
|
<div class="brandImg" v-if="selectObject.userBrandDna"><img :src="selectObject.userBrandDnaImg"></div>
|
||||||
<div class="brandDNAStrenght marginBottom" v-if="selectObject.userBrandDna">
|
<div class="brandDNAStrenght marginBottom" v-if="selectObject.userBrandDna">
|
||||||
<div class="text" style="font-size: 1.6rem;">
|
<div class="text" style="font-size: 1.6rem;">
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
:options="[{value:'product',label:'product'},{value:'sketch',label:'sketch'}]"
|
:options="[{value:'product',label:'product'},{value:'sketch',label:'sketch'}]"
|
||||||
></a-select>
|
></a-select>
|
||||||
</div> -->
|
</div> -->
|
||||||
<selectList @selectImgItem="selectImgItem" :deReconstructionList="segmentationTypeList" :isSegmentation="true" upLoadHttpsUrl="/api/element/imageSegmentation" level1Type="Sketchboard" :randomId="false" type="sketch" :catecoryList="sketchCatecoryList">
|
<selectList @selectImgItem="selectImgItem" :deReconstructionList="segmentationTypeList" :isSegmentation="true" upLoadHttpsUrl="/aida/api/element/imageSegmentation" level1Type="Sketchboard" :randomId="false" type="sketch" :catecoryList="sketchCatecoryList">
|
||||||
<template v-slot:selectSex>
|
<template v-slot:selectSex>
|
||||||
<div class="generalModel_state" style="margin-left: auto">
|
<div class="generalModel_state" style="margin-left: auto">
|
||||||
<div class="generalModel_state_item smail" style="margin-right: 0">
|
<div class="generalModel_state_item smail" style="margin-right: 0">
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ export default defineComponent({
|
|||||||
// //fetch get请求携带token
|
// //fetch get请求携带token
|
||||||
|
|
||||||
|
|
||||||
// fetch("https://develop.api.aida.com.hk/api/project/getThreeDGlb?threeDSimpleId=1", {
|
// fetch("https://develop.api.aida.com.hk/aida/api/project/getThreeDGlb?threeDSimpleId=1", {
|
||||||
// headers:{
|
// headers:{
|
||||||
// authorization:'Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiI4OCIsInN1YiI6IntcImNvdW50cnlcIjpcIkNoaW5hXCIsXCJpZFwiOjg4LFwibGFuZ3VhZ2VcIjpcIkVOR0xJU0hcIixcInVzZXJuYW1lXCI6XCJzaGJcIn0iLCJpYXQiOjE3NDMzNDkwNjQsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE3NTE5ODkwNjR9.gmL0JufYy9wd23qCY-ibwhgpXZ2X68WAiHSeC99I4x7cipWyxLaQmuIBk2SJSdWBm0tTN2Mx-etXO9a7MtQmpw',
|
// authorization:'Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiI4OCIsInN1YiI6IntcImNvdW50cnlcIjpcIkNoaW5hXCIsXCJpZFwiOjg4LFwibGFuZ3VhZ2VcIjpcIkVOR0xJU0hcIixcInVzZXJuYW1lXCI6XCJzaGJcIn0iLCJpYXQiOjE3NDMzNDkwNjQsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE3NTE5ODkwNjR9.gmL0JufYy9wd23qCY-ibwhgpXZ2X68WAiHSeC99I4x7cipWyxLaQmuIBk2SJSdWBm0tTN2Mx-etXO9a7MtQmpw',
|
||||||
// }
|
// }
|
||||||
|
|||||||
@@ -78,7 +78,7 @@
|
|||||||
<div class="upload_file_item">
|
<div class="upload_file_item">
|
||||||
<a-upload
|
<a-upload
|
||||||
key="common"
|
key="common"
|
||||||
:action="getUploadUrl() + '/api/history/toProductImageElementUpload'"
|
:action="getUploadUrl() + '/aida/api/history/toProductImageElementUpload'"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
:data="{
|
:data="{
|
||||||
@@ -111,7 +111,7 @@
|
|||||||
<a-upload
|
<a-upload
|
||||||
key="lastframes"
|
key="lastframes"
|
||||||
:action="
|
:action="
|
||||||
getUploadUrl() + '/api/history/toProductImageElementUpload'
|
getUploadUrl() + '/aida/api/history/toProductImageElementUpload'
|
||||||
"
|
"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
<div class="upload_item item" v-show="!isDesignPage">
|
<div class="upload_item item" v-show="!isDesignPage">
|
||||||
<div class="upload_file_item">
|
<div class="upload_file_item">
|
||||||
<a-upload
|
<a-upload
|
||||||
:action="uploadUrl + '/api/history/toProductImageElementUpload'"
|
:action="uploadUrl + '/aida/api/history/toProductImageElementUpload'"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
:data="{
|
:data="{
|
||||||
|
|||||||
3598
src/lang/cn.ts
155
src/lang/en.ts
@@ -24,6 +24,7 @@ export default {
|
|||||||
SubscribeNow: 'Subscribe now',
|
SubscribeNow: 'Subscribe now',
|
||||||
TaskList: 'Task List',
|
TaskList: 'Task List',
|
||||||
ViewOrders: 'View Orders',
|
ViewOrders: 'View Orders',
|
||||||
|
PersonalCenter: 'Personal Center',
|
||||||
BecomeSeller: 'Become a Seller',
|
BecomeSeller: 'Become a Seller',
|
||||||
SellerDashboard: 'Seller Dashboard',
|
SellerDashboard: 'Seller Dashboard',
|
||||||
toolsToProduct: 'To product image',
|
toolsToProduct: 'To product image',
|
||||||
@@ -1786,5 +1787,159 @@ export default {
|
|||||||
step4Info: 'Publish and your design goes live on the marketplace.',
|
step4Info: 'Publish and your design goes live on the marketplace.',
|
||||||
showAgain: 'Don’t show me again',
|
showAgain: 'Don’t show me again',
|
||||||
GetStarted: 'Get Started',
|
GetStarted: 'Get Started',
|
||||||
|
},
|
||||||
|
SellerListEdit:{
|
||||||
|
saveDraft:'Save All New',
|
||||||
|
publish:'Publish',
|
||||||
|
sketch:'Sketch',
|
||||||
|
mainProductImage:'Main Product Image',
|
||||||
|
cover:'Cover',
|
||||||
|
productImageDesc:'Choose from product image',
|
||||||
|
cropDesc:'Crop from main product image or sketch',
|
||||||
|
productImageMainTitle:'Product Media ',
|
||||||
|
productImageSubTitle:'(from design collection)',
|
||||||
|
apparelSketchTitle:'Apparel Sketch ',
|
||||||
|
apparelSketchSubTitle:'(from design collection)',
|
||||||
|
productName:'Product Name',
|
||||||
|
price:'Price',
|
||||||
|
productDescription:'Product Description',
|
||||||
|
designFor:'Designed For',
|
||||||
|
productCategory:'Product Category',
|
||||||
|
categoryTips:'select all that apply',
|
||||||
|
policy:'By default, all sales follow the platform\'s licensing policy — buyers will receive a usage license upon download.',
|
||||||
|
learnMore:'Learn more',
|
||||||
|
requiredFieldTips:'Please fill in {field}',
|
||||||
|
requiredFieldTipsWithPage:'Listing {index}: Please fill in {field}',
|
||||||
|
draftSaved: 'Draft Saved',
|
||||||
|
draftDesc: 'Your listing has been saved as a draft. \nYou can continue editing or publish it later from My Listings.',
|
||||||
|
listingLive:'Listing Live',
|
||||||
|
publishDesc:'Your listing is now live on the marketplace.\nBuyers can discover and purchase your design.'
|
||||||
|
},
|
||||||
|
Seller: {
|
||||||
|
brandProfile: "Brand Profile",
|
||||||
|
myListings: "My Listings",
|
||||||
|
myOrders: "My Orders",
|
||||||
|
settings: "Settings",
|
||||||
|
// Brand Profile
|
||||||
|
brandProfileBgNullTip: "Your brand banner has not been set up yet.",
|
||||||
|
changeBrandBanner: "Change Brand Banner",
|
||||||
|
edit: "Edit",
|
||||||
|
cancel: "Cancel",
|
||||||
|
confirm: "Confirm",
|
||||||
|
saveChange: "Save Change",
|
||||||
|
brandProfileEditTip: "Changes will be reflected on your Stylish Parade brand page.",
|
||||||
|
storeName: "Store Name",
|
||||||
|
storeNameDesc: "Enter your store name",
|
||||||
|
ownerName: "Owner’s Full Name",
|
||||||
|
ownerNameDesc: "Enter store owner's full name",
|
||||||
|
email: "Email",
|
||||||
|
emailDesc: "Enter email",
|
||||||
|
mobile: "Phone Number",
|
||||||
|
mobileDesc: "Enter phone number",
|
||||||
|
link: "Link {index}",
|
||||||
|
links: "Portfoilo/Social Media Links",
|
||||||
|
storeDescription: "Store Description",
|
||||||
|
storeDescriptionDesc: "Briefly describe your design style and store features...",
|
||||||
|
storeDescriptionErr: "Please enter store description",
|
||||||
|
cropBrandBanner: "Crop Brand Banner",
|
||||||
|
cropAvatar: "Crop Avatar",
|
||||||
|
cropFrom: "Crop from:",
|
||||||
|
sketch: "Sketch",
|
||||||
|
mainProductImage: "Main Product Image",
|
||||||
|
cropPreview: "Crop Preview",
|
||||||
|
imageClipCoverTip: "Align crown to top, mid-thigh to bottom for best results.",
|
||||||
|
imageClipMainProductImageTip: "Align crown to top, foot base to bottom for best results.",
|
||||||
|
imageClipSketchTip: "Align crown to top, foot base to bottom for best results.",
|
||||||
|
imageClipApparelTip: "Trim whitespace and center your apparel sketch.",
|
||||||
|
// 我的订单
|
||||||
|
totalRevenue: "Total Revenue",
|
||||||
|
totalPurchases: "Total Purchases",
|
||||||
|
totalViews: "Total Views",
|
||||||
|
allInvoice: "All Invoice",
|
||||||
|
myOrdersTip: "A summary of all completed transactions.",
|
||||||
|
myOrdersSearchPlaceholder: "Search by item name or order ID",
|
||||||
|
orderId: "Order ID",
|
||||||
|
item: "Item",
|
||||||
|
price: "Price",
|
||||||
|
buyerUsername: "Buyer Username",
|
||||||
|
date: "Date",
|
||||||
|
// 设置
|
||||||
|
notifications: "Notifications",
|
||||||
|
notificationsTitle: "New order notification",
|
||||||
|
notificationsTip: "Receive an inbox message when a new order is placed.",
|
||||||
|
payout: "Payout",
|
||||||
|
payoutTitle: "Payment Providers",
|
||||||
|
payoutTip: "Select how you want to receive payments.",
|
||||||
|
unbound: "Unbound",
|
||||||
|
manage: "Manage",
|
||||||
|
bindNow: "Bind Now",
|
||||||
|
paymentCurrency: "Payment Currency",
|
||||||
|
HKD: "HKD - Hong Kong Dollar",
|
||||||
|
fixed: "Fixed",
|
||||||
|
dataPrivacy: "Data & Privacy",
|
||||||
|
dataPrivacyTitle: "Copyright licence",
|
||||||
|
dataPrivacyTip1: "A licence certificate is automatically included with every purchase download. View the default licensing terms applied to your listings.",
|
||||||
|
dataPrivacyTip2: "BThis licence is issued by Code-Create and is legally binding upon purchase. It certifies the buyer's right to use the purchased design asset in accordance with the terms below.",
|
||||||
|
dataPrivacyTip3: "For custom licensing arrangements, <span onclick='{click}()'>contact us</span>.",
|
||||||
|
downloadToView: "Download to View",
|
||||||
|
stopSelling: "Stop Selling",
|
||||||
|
stopSellingTitle: "Deactivate seller account",
|
||||||
|
stopSellingTip: "Permanently deactivate your seller account. All listings and invoice records will be deleted. You may re-register as a seller in the future, but your previous sales data cannot be recovered.",
|
||||||
|
deactivate: "Deactivate",
|
||||||
|
newListing: "New Listing",
|
||||||
|
draftMessage: 'Product moved to drafts and stats reset.',
|
||||||
|
publishMessage: 'Item is now live on the Marketplace.',
|
||||||
|
ActiveListings: 'Active Listings',
|
||||||
|
Praka: 'Praka',
|
||||||
|
Drafts: 'Drafts',
|
||||||
|
Cancel: 'Cancel',
|
||||||
|
Delete: 'Delete',
|
||||||
|
DeleteConfirm: 'Delete this listing?',
|
||||||
|
DeleteDesc: 'Your listing and its details will be permanently removed.',
|
||||||
|
Edit: 'Edit',
|
||||||
|
Draft: 'Draft',
|
||||||
|
Publish: 'Publish',
|
||||||
|
sketchesSelected: 'Sketches selected',
|
||||||
|
Next: 'Next',
|
||||||
|
All: 'All',
|
||||||
|
SeriesDesign: 'Series Design',
|
||||||
|
SingleDesign: 'Single Design',
|
||||||
|
sketchs: 'sketches',
|
||||||
|
MyListings: 'My Listings',
|
||||||
|
MyListingsInfo: 'Active listings and unpublished inventory',
|
||||||
|
SelectCollection: 'Select Collection',
|
||||||
|
SelectSketch: 'Select Sketch',
|
||||||
|
EditListingDetails: 'Edit Listing Details',
|
||||||
|
VideoWarning:'The first selected item is the main product image. Videos cannot be used.',
|
||||||
|
selectSketchMaxNum: 'Select up to 9 sketches',
|
||||||
|
},
|
||||||
|
ApplySeller: {
|
||||||
|
applySellerTitle: 'Apply to Become a Seller',
|
||||||
|
applySellerDesc: 'Join the Stylish Parade and start selling your design work',
|
||||||
|
formTitle: 'Brand Information',
|
||||||
|
formTip: 'Share a few details to set up your seller profile',
|
||||||
|
termsTitle: 'Seller Terms',
|
||||||
|
termsTip: 'Please carefully read and agree to the following terms',
|
||||||
|
agreementTitle: 'AiDA Seller Agreement',
|
||||||
|
agreementTip: 'Please read and agree to the following agreement',
|
||||||
|
agreementItem1: "Provide accurate and truthful personal and store information",
|
||||||
|
agreementItem2: "Only sell original designs or content with proper licensing",
|
||||||
|
agreementItem3: "Maintain high quality standards for all products",
|
||||||
|
agreementItem4: "Respond to customer inquiries within 48 hours",
|
||||||
|
agreementItem5: "Ship orders within promised timeframes",
|
||||||
|
agreementItem6: "Comply with AiDA's terms of service and community guidelines",
|
||||||
|
agreementItem7: "Pay applicable platform fees and transaction charges",
|
||||||
|
agreementItem8: "Handle customer disputes professionally and fairly",
|
||||||
|
agreementAgreement: "I have read and agree to the Seller Agreement, understanding my responsibilities and obligations as a seller on the AiDA platform.",
|
||||||
|
submitApplication: "Submit Application",
|
||||||
|
applicationSubmitted: "Application Submitted",
|
||||||
|
applicationSubmittedTip: "Approval is expected shortly. Upon receipt, please ensure your payout account is linked under <span>Seller Dashboard > Settings</span> prior to listing any items.",
|
||||||
|
auditStatus1_title: "Step 1: Submit Application",
|
||||||
|
auditStatus1_tip: "Fill out the seller information form and agree to our terms",
|
||||||
|
auditStatus2_title: "Step 2: Review & Verification",
|
||||||
|
auditStatus2_tip: "Our team will review your application (typically 1-3 business days)",
|
||||||
|
auditStatus3_title: "Step 3: Start Selling",
|
||||||
|
auditStatus3_tip: "Once approved, access your seller dashboard and start listing products",
|
||||||
|
backToHomepage: "Back to Homepage",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1045
src/router/index.ts
@@ -7,6 +7,7 @@ import UserHabit from './userHabit/userHabit'
|
|||||||
import Workspace from './workspace/workspace'
|
import Workspace from './workspace/workspace'
|
||||||
import Guide from './guide/guide'
|
import Guide from './guide/guide'
|
||||||
import adminPage from './adminPage/adminPage'
|
import adminPage from './adminPage/adminPage'
|
||||||
|
import seller from './seller/index'
|
||||||
export interface RootState{
|
export interface RootState{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -41,5 +42,6 @@ export default createStore<RootState>({
|
|||||||
Workspace,
|
Workspace,
|
||||||
Guide,
|
Guide,
|
||||||
adminPage,
|
adminPage,
|
||||||
|
seller,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
6
src/store/seller/index.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export const ApplyStatus = {
|
||||||
|
Null: null,// 未申请过
|
||||||
|
Pending: 0,// 已提交, 待审核
|
||||||
|
Approved: 1,// 审核通过
|
||||||
|
Rejected: 2,// 审核拒绝
|
||||||
|
}
|
||||||
91
src/store/seller/index.ts
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import { Module } from 'vuex'
|
||||||
|
import { RootState } from '../index'
|
||||||
|
import i18n from "@/lang/index";
|
||||||
|
import { Https } from '@/tool/https'
|
||||||
|
import { ApplyStatus } from "./index.d"
|
||||||
|
|
||||||
|
import store from '../index'
|
||||||
|
interface DesignerInfo {
|
||||||
|
shopName: string,
|
||||||
|
avatar: string,
|
||||||
|
brandBanner: string,
|
||||||
|
ownerName: string,
|
||||||
|
email: string,
|
||||||
|
mobile: string,
|
||||||
|
socialLinks: string[] | string,
|
||||||
|
description: string,
|
||||||
|
}
|
||||||
|
interface Seller {
|
||||||
|
isSeller: boolean,
|
||||||
|
applyStatus: number | null,
|
||||||
|
designerInfo: DesignerInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
const seller: Module<Seller, RootState> = {
|
||||||
|
namespaced: true,
|
||||||
|
state: {
|
||||||
|
isSeller: false,
|
||||||
|
applyStatus: null,
|
||||||
|
designerInfo: {
|
||||||
|
shopName: "--",
|
||||||
|
avatar: null,
|
||||||
|
brandBanner: null,
|
||||||
|
ownerName: "--",
|
||||||
|
email: "--",
|
||||||
|
mobile: "--",
|
||||||
|
socialLinks: ["--"],
|
||||||
|
description: "--"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
set_isSeller(state: Seller, value: boolean) {
|
||||||
|
state.isSeller = value
|
||||||
|
},
|
||||||
|
set_applyStatus(state: Seller, value: number) {
|
||||||
|
state.applyStatus = value
|
||||||
|
if (value == ApplyStatus.Approved) {
|
||||||
|
state.isSeller = true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set_designerInfo(state: Seller, value: DesignerInfo) {
|
||||||
|
state.designerInfo = {
|
||||||
|
...state.designerInfo,
|
||||||
|
...value,
|
||||||
|
}
|
||||||
|
if (typeof value.socialLinks === "string") {
|
||||||
|
state.designerInfo.socialLinks = JSON.parse(value.socialLinks)
|
||||||
|
} else if (Array.isArray(value.socialLinks)) {
|
||||||
|
state.designerInfo.socialLinks = value.socialLinks
|
||||||
|
}
|
||||||
|
},
|
||||||
|
clear_state(state: Seller) {
|
||||||
|
state.isSeller = false
|
||||||
|
state.applyStatus = null
|
||||||
|
state.designerInfo = {
|
||||||
|
shopName: "--",
|
||||||
|
avatar: "",
|
||||||
|
brandBanner: "",
|
||||||
|
ownerName: "--",
|
||||||
|
email: "--",
|
||||||
|
mobile: "--",
|
||||||
|
socialLinks: ["--"],
|
||||||
|
description: "--"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
get_isSeller({ commit }) {
|
||||||
|
Https.axiosGet(Https.httpUrls.checkSellerDesigner).then(rv => {
|
||||||
|
commit('set_isSeller', !!rv)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async get_designerInfo({ commit }) {
|
||||||
|
const rv = await Https.axiosGet(Https.httpUrls.getDesignerInfo)
|
||||||
|
commit('set_designerInfo', rv)
|
||||||
|
return rv
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default seller
|
||||||
@@ -13,24 +13,13 @@ axios.defaults.headers.post['lang'] = 'en' //配置语言请求头
|
|||||||
axios.defaults.withCredentials = true //跨域携带cookie
|
axios.defaults.withCredentials = true //跨域携带cookie
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
// if(import.meta.env.VITE_USER_NODE_ENV == "development"){
|
const baseURL = import.meta.env.VITE_APP_BASE_URL
|
||||||
// axios.defaults.baseURL = ""; //配置接口地址
|
console.log(baseURL)
|
||||||
// }else{
|
if (import.meta.env.VITE_USER_NODE_ENV == "development") {
|
||||||
// axios.defaults.baseURL = import.meta.env.VITE_APP_BASE_URL; //配置接口地址
|
axios.defaults.baseURL = "";
|
||||||
// }
|
} else {
|
||||||
// let httpIp
|
axios.defaults.baseURL = baseURL;
|
||||||
// if(import.meta.env.VITE_USER_NODE_ENV == 'development'){
|
}
|
||||||
// httpIp = 'http://192.168.1.12:10086'
|
|
||||||
// }else{
|
|
||||||
// httpIp = ''
|
|
||||||
// }
|
|
||||||
let httpIp = import.meta.env.VITE_USER_NODE_ENV == 'development' ? '' : ''
|
|
||||||
// let httpIp = import.meta.env.VITE_USER_NODE_ENV == 'development' ? "https://192.168.1.8:10086" : "";
|
|
||||||
|
|
||||||
axios.defaults.baseURL = httpIp //配置接口地址
|
|
||||||
// console.log(axios.defaults.baseURL);
|
|
||||||
axios.defaults.baseURL = import.meta.env.VITE_APP_BASE_URL //配置接口地址
|
|
||||||
console.log(import.meta.env.VITE_APP_BASE_URL)
|
|
||||||
|
|
||||||
// 创建取消令牌
|
// 创建取消令牌
|
||||||
const CancelToken = axios.CancelToken
|
const CancelToken = axios.CancelToken
|
||||||
@@ -149,341 +138,358 @@ axios.interceptors.response.use(
|
|||||||
export const Https = {
|
export const Https = {
|
||||||
httpUrls: {
|
httpUrls: {
|
||||||
interfaceUrl: '',
|
interfaceUrl: '',
|
||||||
parseGoogleCredential: '/api/third/party/parseGoogleCredential', //谷歌登录注册
|
parseGoogleCredential: '/aida/api/third/party/parseGoogleCredential', //谷歌登录注册
|
||||||
parseWeChatCode: '/api/third/party/parseWeChatCode', //微信登录
|
parseWeChatCode: '/aida/api/third/party/parseWeChatCode', //微信登录
|
||||||
accountIsLogin: '/api/account/isLogin', //判断用户是否登录
|
accountIsLogin: '/aida/api/account/isLogin', //判断用户是否登录
|
||||||
accountLogin: `/api/account/login`, //账号密码登录接口
|
accountLogin: `/aida/api/account/login`, //账号密码登录接口
|
||||||
organizationNameSearch: `/api/account/organizationNameSearch`, //查询学校或者企业版名字
|
organizationNameSearch: `/aida/api/account/organizationNameSearch`, //查询学校或者企业版名字
|
||||||
getUserLanguage: `/api/account/getUserLanguage`, //获取当前用户语言
|
getUserLanguage: `/aida/api/account/getUserLanguage`, //获取当前用户语言
|
||||||
changeUserLanguage: `/api/account/changeUserLanguage`, //切换用户当前语言
|
changeUserLanguage: `/aida/api/account/changeUserLanguage`, //切换用户当前语言
|
||||||
uploadAvatar: `/api/account/uploadAvatar`, //修改头像
|
uploadAvatar: `/aida/api/account/uploadAvatar`, //修改头像
|
||||||
editUserName: `/api/account/editUserName`, //修改用户名
|
editUserName: `/aida/api/account/editUserName`, //修改用户名
|
||||||
updateUserInfo: `/api/account/updateUserInfo`, //修改国家职业
|
updateUserInfo: `/aida/api/account/updateUserInfo`, //修改国家职业
|
||||||
accountDetail: `/api/account/getAccountDetail`, //用户详细信息
|
accountDetail: `/aida/api/account/getAccountDetail`, //用户详细信息
|
||||||
|
|
||||||
trialUserLogout: `/api/account/trialUserLogout`, //试用用户退出登录接口
|
trialUserLogout: `/aida/api/account/trialUserLogout`, //试用用户退出登录接口
|
||||||
completeGuidancet: `/api/account/completeGuidance`, //用户指引结束
|
completeGuidancet: `/aida/api/account/completeGuidance`, //用户指引结束
|
||||||
|
|
||||||
getExpiredTime: `/api/account/getExpiredTime`, //获取用户到期时间
|
getExpiredTime: `/aida/api/account/getExpiredTime`, //获取用户到期时间
|
||||||
|
|
||||||
addNoLoginRequired: `/api/third/party/addNoLoginRequired`, //机房用户注册
|
addNoLoginRequired: `/aida/api/third/party/addNoLoginRequired`, //机房用户注册
|
||||||
deleteNoLoginRequired: `/api/third/party/deleteNoLoginRequired`, //机房用户注销
|
deleteNoLoginRequired: `/aida/api/third/party/deleteNoLoginRequired`, //机房用户注销
|
||||||
noLoginRequired: `api/account/noLoginRequired`, //机房用户登录
|
noLoginRequired: `/aida/api/account/noLoginRequired`, //机房用户登录
|
||||||
existNoLoginRequired: `/api/third/party/existNoLoginRequired`, //获取唯一标识是否存在
|
existNoLoginRequired: `/aida/api/third/party/existNoLoginRequired`, //获取唯一标识是否存在
|
||||||
|
|
||||||
deleteNoLoginRequiredNew: `/api/third/party/deleteNoLoginRequiredNew`, //机房用户注销
|
deleteNoLoginRequiredNew: `/aida/api/third/party/deleteNoLoginRequiredNew`, //机房用户注销
|
||||||
addNoLoginRequiredNew: `api/third/party/addNoLoginRequiredNew`, //机房用户注册
|
addNoLoginRequiredNew: `/aida/api/third/party/addNoLoginRequiredNew`, //机房用户注册
|
||||||
updateNoLoginRequiredNew: `api/third/party/updateNoLoginRequiredNew`, //机房用户更新
|
updateNoLoginRequiredNew: `/aida/api/third/party/updateNoLoginRequiredNew`, //机房用户更新
|
||||||
|
|
||||||
endpoint: `api/third/party/your-secured-endpoint`, //获取唯一标识是否存在
|
endpoint: `/aida/api/third/party/your-secured-endpoint`, //获取唯一标识是否存在
|
||||||
|
|
||||||
designWorksRegister: '/api/account/designWorksRegister', //注册
|
designWorksRegister: '/aida/api/account/designWorksRegister', //注册
|
||||||
designWorksRegisterCode: '/api/account/designWorksRegisterCode', //注册
|
designWorksRegisterCode: '/aida/api/account/designWorksRegisterCode', //注册
|
||||||
|
|
||||||
preLogin: '/api/account/preLogin', //预先登入
|
preLogin: '/aida/api/account/preLogin', //预先登入
|
||||||
schoolLogin: '/api/account/schoolLogin', //学校管理员登录
|
schoolLogin: '/aida/api/account/schoolLogin', //学校管理员登录
|
||||||
enterpriseLogin: '/api/account/enterpriseLogin', //企业管理员登录
|
enterpriseLogin: '/aida/api/account/enterpriseLogin', //企业管理员登录
|
||||||
accountSendEmail: `/api/account/sendEmail`, //发送邮件
|
accountSendEmail: `/aida/api/account/sendEmail`, //发送邮件
|
||||||
accountResetPwd: '/api/account/resetPwd', //忘记密码修改
|
accountResetPwd: '/aida/api/account/resetPwd', //忘记密码修改
|
||||||
accountLogout: '/api/account/logout', //登出
|
accountLogout: '/aida/api/account/logout', //登出
|
||||||
accountBindEmail: '/api/account/bindEmail', //绑定邮箱
|
accountBindEmail: '/aida/api/account/bindEmail', //绑定邮箱
|
||||||
bindGoogle: '/api/account/bindGoogle', //绑定谷歌
|
bindGoogle: '/aida/api/account/bindGoogle', //绑定谷歌
|
||||||
bindWeChat: '/api/account/bindWeChat', //绑定微信
|
bindWeChat: '/aida/api/account/bindWeChat', //绑定微信
|
||||||
unbindGoogle: `/api/account/unbindGoogle`, //取消绑定谷歌
|
unbindGoogle: `/aida/api/account/unbindGoogle`, //取消绑定谷歌
|
||||||
unbindWeChat: '/api/account/unbindWeChat', //取消绑定微信
|
unbindWeChat: '/aida/api/account/unbindWeChat', //取消绑定微信
|
||||||
elementGeneratePrint: '/api/element/generatePrint', //生成印花
|
elementGeneratePrint: '/aida/api/element/generatePrint', //生成印花
|
||||||
elementSavePrint: '/api/element/savePrint', //保存印花
|
elementSavePrint: '/aida/api/element/savePrint', //保存印花
|
||||||
getRgbByTcx: '/api/element/getRgbByTcx', // 通过hsv值获取潘通信息
|
getRgbByTcx: '/aida/api/element/getRgbByTcx', // 通过hsv值获取潘通信息
|
||||||
getRgbByHsv: '/api/element/getRgbByHsv', //通过hsv值获取潘通信息
|
getRgbByHsv: '/aida/api/element/getRgbByHsv', //通过hsv值获取潘通信息
|
||||||
elementDelete: '/api/element/delete', //删除上传的图片
|
elementDelete: '/aida/api/element/delete', //删除上传的图片
|
||||||
designCollection: `/api/design/designCollection`, //设计 Conllection
|
designCollection: `/aida/api/design/designCollection`, //设计 Conllection
|
||||||
reDesignCollection: `/api/design/reDesignCollection`, //重新设计 Conllection
|
reDesignCollection: `/aida/api/design/reDesignCollection`, //重新设计 Conllection
|
||||||
countDesignProcess: '/api/design/countDesignProcess', //统计design进度
|
countDesignProcess: '/aida/api/design/countDesignProcess', //统计design进度
|
||||||
getDesignResult: '/api/design/getDesignResult', //查询design结果
|
getDesignResult: '/aida/api/design/getDesignResult', //查询design结果
|
||||||
designSort: `/api/design/sort`, //design排序
|
designSort: `/aida/api/design/sort`, //design排序
|
||||||
collectionLikeUpdate: `/api/history/collectionLikeUpdate`, //赋值排序
|
collectionLikeUpdate: `/aida/api/history/collectionLikeUpdate`, //赋值排序
|
||||||
|
|
||||||
designProcess: `/api/design/designProcess`, //统计design进度
|
designProcess: `/aida/api/design/designProcess`, //统计design进度
|
||||||
designGetModel: `/api/design/getModel`, //导出获取模特链接
|
designGetModel: `/aida/api/design/getModel`, //导出获取模特链接
|
||||||
|
|
||||||
//充值相关
|
//充值相关
|
||||||
productList: `/api/product/list`, //获取商品列表
|
productList: `/aida/api/product/list`, //获取商品列表
|
||||||
payAlipay: `/api/ali-pay/trade/page/pay`, //支付宝确认支付
|
payAlipay: `/aida/api/ali-pay/trade/page/pay`, //支付宝确认支付
|
||||||
payAlipayHK: `/api/alipay-hk/createOrder`, //香港支付宝确认支付
|
payAlipayHK: `/aida/api/alipay-hk/createOrder`, //香港支付宝确认支付
|
||||||
payStripe: `/api/stripe/createOrder`, //Stripe支付
|
payStripe: `/aida/api/stripe/createOrder`, //Stripe支付
|
||||||
payPaypal: `/api/paypal/trade`, //paypal确认支付
|
payPaypal: `/aida/api/paypal/trade`, //paypal确认支付
|
||||||
getCredits: `/api/credits/getCredits`, //查询用户积分
|
getCredits: `/aida/api/credits/getCredits`, //查询用户积分
|
||||||
|
|
||||||
cancelSubscription: `/api/stripe/cancelSubscription`, //取消订阅
|
cancelSubscription: `/aida/api/stripe/cancelSubscription`, //取消订阅
|
||||||
|
|
||||||
orderInfoList: `/api/order-info/list`, //查询订单列表
|
orderInfoList: `/aida/api/order-info/list`, //查询订单列表
|
||||||
getCreditsDetail: `/api/credits/getCreditsDetail`, //查询积分列表
|
getCreditsDetail: `/aida/api/credits/getCreditsDetail`, //查询积分列表
|
||||||
tradeRefundAlipay: `/api/ali-pay/trade/refund`, //支付宝退款
|
tradeRefundAlipay: `/aida/api/ali-pay/trade/refund`, //支付宝退款
|
||||||
tradeRefundPaypal: `/api/paypal/trade/refund`, //paypal退款
|
tradeRefundPaypal: `/aida/api/paypal/trade/refund`, //paypal退款
|
||||||
|
|
||||||
tradeQuery: `/api/ali-pay/trade/query/{orderNo}`, //查询订单状态
|
tradeQuery: `/aida/api/ali-pay/trade/query/{orderNo}`, //查询订单状态
|
||||||
|
|
||||||
getRgbByHsvBatch: `/api/element/getRgbByHsvBatch`, //通过hsv值数组批量获取潘通信息
|
getRgbByHsvBatch: `/aida/api/element/getRgbByHsvBatch`, //通过hsv值数组批量获取潘通信息
|
||||||
designLike: `/api/design/like`, //Design Like
|
designLike: `/aida/api/design/like`, //Design Like
|
||||||
designDislike: `/api/design/dislike`, //Design Dislike
|
designDislike: `/aida/api/design/dislike`, //Design Dislike
|
||||||
queryUserGroup: `/api/history/queryUserGroup`, //History用户分页分组列表
|
queryUserGroup: `/aida/api/history/queryUserGroup`, //History用户分页分组列表
|
||||||
deleteUserGroup: `/api/history/deleteUserGroup`, //History删除用户分组
|
deleteUserGroup: `/aida/api/history/deleteUserGroup`, //History删除用户分组
|
||||||
updateUserGroupName: `/api/history/updateUserGroupName`, //History修改用户分组名
|
updateUserGroupName: `/aida/api/history/updateUserGroupName`, //History修改用户分组名
|
||||||
projectSaveOrUpdate: `/api/project/saveOrUpdate`, //History修改用户分组名
|
projectSaveOrUpdate: `/aida/api/project/saveOrUpdate`, //History修改用户分组名
|
||||||
historyChoose: `/api/history/choose`, //History choose
|
historyChoose: `/aida/api/history/choose`, //History choose
|
||||||
getDesignDetail: `/api/design/detail/getDetail`, //查询design详情
|
getDesignDetail: `/aida/api/design/detail/getDetail`, //查询design详情
|
||||||
addSysSketchToLibrary: `/api/library/addSysSketchToLibrary`, //把系统衣服添加的library
|
addSysSketchToLibrary: `/aida/api/library/addSysSketchToLibrary`, //把系统衣服添加的library
|
||||||
designSingleWithGradient: `/api/design/detail/designSingleWithGradient`, //查询需要更新mask列表
|
designSingleWithGradient: `/aida/api/design/detail/designSingleWithGradient`, //查询需要更新mask列表
|
||||||
getNextSysElement: '/api/design/detail/getNextSysElement', //切换系统的element
|
getNextSysElement: '/aida/api/design/detail/getNextSysElement', //切换系统的element
|
||||||
detailPrintDot: '/api/design/detail/printDot', //print打点预览
|
detailPrintDot: '/aida/api/design/detail/printDot', //print打点预览
|
||||||
designSingle: `/api/design/detail/designSingle`, //单个design
|
designSingle: `/aida/api/design/detail/designSingle`, //单个design
|
||||||
queryLibraryPage: `/api/library/queryLibraryPage`, //Library分页列表
|
queryLibraryPage: `/aida/api/library/queryLibraryPage`, //Library分页列表
|
||||||
libraryUpload: `/api/library/upload`, // Library文件上传
|
libraryUpload: `/aida/api/library/upload`, // Library文件上传
|
||||||
setSketchLibrary: `/api/library/updateLibraryLevel2Type`, // 修改图片类型
|
setSketchLibrary: `/aida/api/library/updateLibraryLevel2Type`, // 修改图片类型
|
||||||
updateElementLevel2Type: `/api/element/updateElementLevel2Type`, // 修改拼贴上传的衣服类型
|
updateElementLevel2Type: `/aida/api/element/updateElementLevel2Type`, // 修改拼贴上传的衣服类型
|
||||||
|
|
||||||
queryClassification: `/api/classification/queryClassification`, //标签类别查询
|
queryClassification: `/aida/api/classification/queryClassification`, //标签类别查询
|
||||||
classificationSaveOrUpdate: `/api/classification/saveOrUpdate`, //标签类别新增修改
|
classificationSaveOrUpdate: `/aida/api/classification/saveOrUpdate`, //标签类别新增修改
|
||||||
classificationDelete: `/api/classification/delete`, //标签类别新增修改
|
classificationDelete: `/aida/api/classification/delete`, //标签类别新增修改
|
||||||
relationLibrary: `/api/classification/relationLibrary`, //标签类别新增修改
|
relationLibrary: `/aida/api/classification/relationLibrary`, //标签类别新增修改
|
||||||
getRelClassificationIdList: `/api/classification/getRelClassificationIdList`, //标签类别新增修改
|
getRelClassificationIdList: `/aida/api/classification/getRelClassificationIdList`, //标签类别新增修改
|
||||||
getRelPublicClassificationIdList: `/api/classification/getRelPublicClassificationIdList`, //多选获取公共标签
|
getRelPublicClassificationIdList: `/aida/api/classification/getRelPublicClassificationIdList`, //多选获取公共标签
|
||||||
editRelPublicClassificationIdList: `/api/classification/editRelPublicClassificationIdList`, //多选修改公共标签
|
editRelPublicClassificationIdList: `/aida/api/classification/editRelPublicClassificationIdList`, //多选修改公共标签
|
||||||
|
|
||||||
//模块化
|
//模块化
|
||||||
llmStream: `/api/llm/streamNew`, //聊天
|
llmStream: `/aida/api/llm/streamNew`, //聊天
|
||||||
// llmStream:`/api/llm/stream`,//聊天
|
// llmStream:`/aida/api/llm/stream`,//聊天
|
||||||
chatCreateProject: `/api/llm/chatCreateProject`, //聊天创建项目
|
chatCreateProject: `/aida/api/llm/chatCreateProject`, //聊天创建项目
|
||||||
getChatHistory: `/api/llm/getChatHistory`, //获取聊天历史记录
|
getChatHistory: `/aida/api/llm/getChatHistory`, //获取聊天历史记录
|
||||||
llmUploadFile: `/api/llm/uploadFile`, //聊天上传文件
|
llmUploadFile: `/aida/api/llm/uploadFile`, //聊天上传文件
|
||||||
|
|
||||||
saveOrUpdate: `/api/project/saveOrUpdate`, //模块化新增修改
|
saveOrUpdate: `/aida/api/project/saveOrUpdate`, //模块化新增修改
|
||||||
getModuleContent: `/api/project/getModuleContent`, //获取模块内容
|
getModuleContent: `/aida/api/project/getModuleContent`, //获取模块内容
|
||||||
saveModuleContent: `/api/project/saveModuleContent`, //储存模块内容
|
saveModuleContent: `/aida/api/project/saveModuleContent`, //储存模块内容
|
||||||
historyProject: `/api/project/page`, //项目记录
|
historyProject: `/aida/api/project/page`, //项目记录
|
||||||
projectDetail: `/api/project/delete`, //删除项目
|
projectDetail: `/aida/api/project/delete`, //删除项目
|
||||||
//3d
|
//3d
|
||||||
threeDPage: `/api/project/threeDPage`,
|
threeDPage: `/aida/api/project/threeDPage`,
|
||||||
downloadZip: `/api/project/downloadZip`, //下载zip
|
downloadZip: `/aida/api/project/downloadZip`, //下载zip
|
||||||
getThreeDSize: `/api/project/getThreeDSize`, //下载列表
|
getThreeDSize: `/aida/api/project/getThreeDSize`, //下载列表
|
||||||
getLayoutDetail: `/api/project/getLayoutDetail`, //获取3d详情
|
getLayoutDetail: `/aida/api/project/getLayoutDetail`, //获取3d详情
|
||||||
getThreeDGlb: `/api/project/getThreeDGlb`,
|
getThreeDGlb: `/aida/api/project/getThreeDGlb`,
|
||||||
selectHistoryProject: `/api/project/choose`, //选择项目
|
selectHistoryProject: `/aida/api/project/choose`, //选择项目
|
||||||
getMannequinDetail: `/api/project/getMannequinDetail`, //模块化查看模特点位
|
getMannequinDetail: `/aida/api/project/getMannequinDetail`, //模块化查看模特点位
|
||||||
modifyProportion: `/api/generate/modifyProportion`, //模特拉伸
|
modifyProportion: `/aida/api/generate/modifyProportion`, //模特拉伸
|
||||||
addSysModelToLib: `/api/library/addSysModelToLib`,
|
addSysModelToLib: `/aida/api/library/addSysModelToLib`,
|
||||||
poselikeOrDisike: `/api/generate/likeOrDislike`, //postTransform like
|
poselikeOrDisike: `/aida/api/generate/likeOrDislike`, //postTransform like
|
||||||
getAllPose: `/api/generate/getAllPose`, //获取动作
|
getAllPose: `/aida/api/generate/getAllPose`, //获取动作
|
||||||
|
|
||||||
//拼贴
|
//拼贴
|
||||||
genSketchRecon: `/api/generate/genSketchRecon`,
|
genSketchRecon: `/aida/api/generate/genSketchRecon`,
|
||||||
saveReconCanvas: `/api/generate/saveReconCanvas`,
|
saveReconCanvas: `/aida/api/generate/saveReconCanvas`,
|
||||||
|
|
||||||
//动作变换
|
//动作变换
|
||||||
poseTransform: `/api/generate/poseTransform`,
|
poseTransform: `/aida/api/generate/poseTransform`,
|
||||||
poseTransformResult: `/api/generate/poseTransformResult`,
|
poseTransformResult: `/aida/api/generate/poseTransformResult`,
|
||||||
|
|
||||||
batchUpdateLibraryName: '/api/library/batchUpdateLibraryName', //Library修改用户文件名
|
batchUpdateLibraryName: '/aida/api/library/batchUpdateLibraryName', //Library修改用户文件名
|
||||||
batchDeleteLibrary: '/api/library/batchDeleteLibrary', //删除library
|
batchDeleteLibrary: '/aida/api/library/batchDeleteLibrary', //删除library
|
||||||
queryLibraryTopAndBottomPage: '/api/library/queryLibraryTopAndBottomPage', //Library分页列表(查询top和bottom)
|
queryLibraryTopAndBottomPage: '/aida/api/library/queryLibraryTopAndBottomPage', //Library分页列表(查询top和bottom)
|
||||||
saveOrEditTemplatePoint: '/api/library/saveOrEditTemplatePoint', //保存或者编辑template打点
|
saveOrEditTemplatePoint: '/aida/api/library/saveOrEditTemplatePoint', //保存或者编辑template打点
|
||||||
libraryModelsDot: '/api/library/modelsDot', //Models打点预览
|
libraryModelsDot: '/aida/api/library/modelsDot', //Models打点预览
|
||||||
chatStreamTest: `/api/python/chatStream`, //机器人助力
|
chatStreamTest: `/aida/api/python/chatStream`, //机器人助力
|
||||||
pictureLikeOrUnLike: `/api/python/pictureLikeOrUnLike`, //机器人生成图喜欢
|
pictureLikeOrUnLike: `/aida/api/python/pictureLikeOrUnLike`, //机器人生成图喜欢
|
||||||
getBloodBars: `/api/python/getBloodBars`, //机器人血条
|
getBloodBars: `/aida/api/python/getBloodBars`, //机器人血条
|
||||||
//工作空间
|
//工作空间
|
||||||
workspaceDetail: `/api/workspace/detail`, //用户习惯详情
|
workspaceDetail: `/aida/api/workspace/detail`, //用户习惯详情
|
||||||
workspaceenumValues: `/api/workspace/enumValues`, //getSex
|
workspaceenumValues: `/aida/api/workspace/enumValues`, //getSex
|
||||||
|
|
||||||
workspaceRemove: `/api/workspace/remove`, //删除用户习惯详情
|
workspaceRemove: `/aida/api/workspace/remove`, //删除用户习惯详情
|
||||||
workspacesaveOrUpdate: `/api/workspace/saveOrUpdate`, //修改用户习惯详情
|
workspacesaveOrUpdate: `/aida/api/workspace/saveOrUpdate`, //修改用户习惯详情
|
||||||
getMannequins: `/api/workspace/getMannequins`, //模特
|
getMannequins: `/aida/api/workspace/getMannequins`, //模特
|
||||||
getStyleList: `/api/workspace/styleList`, //获取所有风格列表
|
getStyleList: `/aida/api/workspace/styleList`, //获取所有风格列表
|
||||||
|
|
||||||
workspaceList: `/api/workspace/list`,
|
workspaceList: `/aida/api/workspace/list`,
|
||||||
sketchAndPrintGenerate: '/api/generate/sketchAndPrint', //sketchGenerate生成图片
|
sketchAndPrintGenerate: '/aida/api/generate/sketchAndPrint', //sketchGenerate生成图片
|
||||||
|
|
||||||
generatePrepare: '/api/generate/prepare', //开始生成generate图片
|
generatePrepare: '/aida/api/generate/prepare', //开始生成generate图片
|
||||||
generateStopWaiting: '/api/generate/stopWaiting', //取消生成
|
generateStopWaiting: '/aida/api/generate/stopWaiting', //取消生成
|
||||||
generateResult: '/api/generate/result', //获取生成结果
|
generateResult: '/aida/api/generate/result', //获取生成结果
|
||||||
generateLike: '/api/generate/like', //喜欢ganerate图片
|
generateLike: '/aida/api/generate/like', //喜欢ganerate图片
|
||||||
generateDislike: '/api/generate/dislike', //喜欢ganerate图片
|
generateDislike: '/aida/api/generate/dislike', //喜欢ganerate图片
|
||||||
imageToSketch: '/api/generate/imageToSketch', //成品图转为线稿
|
imageToSketch: '/aida/api/generate/imageToSketch', //成品图转为线稿
|
||||||
modifySketch: '/api/generate/modifySketch', //修改画布内容并且储存
|
modifySketch: '/aida/api/generate/modifySketch', //修改画布内容并且储存
|
||||||
|
|
||||||
elementUpload: `/api/element/upload`, //上传图片
|
elementUpload: `/aida/api/element/upload`, //上传图片
|
||||||
imageSegmentation: `/api/element/imageSegmentation`, //分割衣服
|
imageSegmentation: `/aida/api/element/imageSegmentation`, //分割衣服
|
||||||
convertRelightElement: `/api/history/convertRelightElement`, //toproduct复制到上传图片位置
|
convertRelightElement: `/aida/api/history/convertRelightElement`, //toproduct复制到上传图片位置
|
||||||
|
|
||||||
// oldHis:`/oldHis/history/queryUserGroup`,//上传图片
|
// oldHis:`/oldHis/history/queryUserGroup`,//上传图片
|
||||||
sketchBoardsBoundingBox: `/api/design/sketchBoardsBoundingBox`, //裁剪sketch图片
|
sketchBoardsBoundingBox: `/aida/api/design/sketchBoardsBoundingBox`, //裁剪sketch图片
|
||||||
|
|
||||||
trialOrderList: `/api/account/trialOrderList`, //获取审批列表
|
trialOrderList: `/aida/api/account/trialOrderList`, //获取审批列表
|
||||||
switchIsAutoApproval: `/api/account/switchIsAutoApproval`, //切换是否自动审批
|
switchIsAutoApproval: `/aida/api/account/switchIsAutoApproval`, //切换是否自动审批
|
||||||
getIsAutoApproval: `/api/account/getIsAutoApproval`, //获取是否自动审批
|
getIsAutoApproval: `/aida/api/account/getIsAutoApproval`, //获取是否自动审批
|
||||||
trialOrderApproval: `/api/account/trialOrderApproval`, //通过审批
|
trialOrderApproval: `/aida/api/account/trialOrderApproval`, //通过审批
|
||||||
trialOrderRefuse: `/api/account/trialOrderRefuse`, //拒绝审批
|
trialOrderRefuse: `/aida/api/account/trialOrderRefuse`, //拒绝审批
|
||||||
|
|
||||||
//管理员接口
|
//管理员接口
|
||||||
//查询所有试用用户
|
//查询所有试用用户
|
||||||
inquiryGetTrial: `/api/inquiry/getTrial`, //查询所有试用用户
|
inquiryGetTrial: `/aida/api/inquiry/getTrial`, //查询所有试用用户
|
||||||
getCities: `/api/inquiry/getCities`, //获取所有付款订单使用的国家
|
getCities: `/aida/api/inquiry/getCities`, //获取所有付款订单使用的国家
|
||||||
getUserInfo: `/api/inquiry/getUserInfo`, //查询所有用户
|
getUserInfo: `/aida/api/inquiry/getUserInfo`, //查询所有用户
|
||||||
queryTransaction: `/api/inquiry/queryTransaction`, //查询交易记录
|
queryTransaction: `/aida/api/inquiry/queryTransaction`, //查询交易记录
|
||||||
queryTransactionDownload: `/api/inquiry/queryTransaction/download`, //导出交易记录
|
queryTransactionDownload: `/aida/api/inquiry/queryTransaction/download`, //导出交易记录
|
||||||
createCoupon: `/api/stripe/createCoupon`, //创建优惠码
|
createCoupon: `/aida/api/stripe/createCoupon`, //创建优惠码
|
||||||
updatePromCodeInfo: `/api/stripe/updatePromCodeInfo`, //修改优惠码
|
updatePromCodeInfo: `/aida/api/stripe/updatePromCodeInfo`, //修改优惠码
|
||||||
getAllCoupons: `/api/stripe/getAllCoupons`, //查询优惠码列表
|
getAllCoupons: `/aida/api/stripe/getAllCoupons`, //查询优惠码列表
|
||||||
checkCoupon: `/api/stripe/checkCoupon`, //根据优惠码获取结算后的金额
|
checkCoupon: `/aida/api/stripe/checkCoupon`, //根据优惠码获取结算后的金额
|
||||||
deletePromCode: `/api/stripe/deletePromCode`, //删除优惠券
|
deletePromCode: `/aida/api/stripe/deletePromCode`, //删除优惠券
|
||||||
addOrganization: `/api/inquiry/addOrganization`, //添加企业版或者教育版
|
addOrganization: `/aida/api/inquiry/addOrganization`, //添加企业版或者教育版
|
||||||
queryOrganization: `/api/inquiry/queryOrganization`, //查询企业版或者教育版
|
queryOrganization: `/aida/api/inquiry/queryOrganization`, //查询企业版或者教育版
|
||||||
createSubscribePlan: '/api/subscription_plan/createPlan', // 创建订阅计划
|
createSubscribePlan: '/aida/api/subscription_plan/createPlan', // 创建订阅计划
|
||||||
deleteSubscribePlan: '/api/subscription_plan/deletePlan', // 删除订阅计划
|
deleteSubscribePlan: '/aida/api/subscription_plan/deletePlan', // 删除订阅计划
|
||||||
updateSubscribePlan: '/api/subscription_plan/updatePlan', // 修改订阅计划
|
updateSubscribePlan: '/aida/api/subscription_plan/updatePlan', // 修改订阅计划
|
||||||
searchAllSubscribePlan: '/api/subscription_plan/searchByPage', // 分页查询所有订阅计划
|
searchAllSubscribePlan: '/aida/api/subscription_plan/searchByPage', // 分页查询所有订阅计划
|
||||||
searchSubscribeByOrg: '/api/subscription_plan/searchByOrganizationIdAndStatus', // 不分页查询
|
searchSubscribeByOrg: '/aida/api/subscription_plan/searchByOrganizationIdAndStatus', // 不分页查询
|
||||||
switchSubscribePlan: '/api/subscription_plan/switchSubscriptionPlan', // 切换管理员订阅计划
|
switchSubscribePlan: '/aida/api/subscription_plan/switchSubscriptionPlan', // 切换管理员订阅计划
|
||||||
switchSubAccountSubscribePlan:
|
switchSubAccountSubscribePlan:
|
||||||
'/api/subscription_plan/switchSubAccSubscriptionPlan', // 切换子账号订阅计划
|
'/aida/api/subscription_plan/switchSubAccSubscriptionPlan', // 切换子账号订阅计划
|
||||||
|
|
||||||
//云生成
|
//云生成
|
||||||
designCloud: `/api/design/designCloud`, //创建云生成
|
designCloud: `/aida/api/design/designCloud`, //创建云生成
|
||||||
cloudPage: `/api/design/cloudPage`, //创建云生成
|
cloudPage: `/aida/api/design/cloudPage`, //创建云生成
|
||||||
cloudTaskDelete: `/api/design/cloudTaskDelete`, //删除云生成
|
cloudTaskDelete: `/aida/api/design/cloudTaskDelete`, //删除云生成
|
||||||
cloudTaskNameUpdate: `/api/design/cloudTaskNameUpdate`, //修改云生成名字
|
cloudTaskNameUpdate: `/aida/api/design/cloudTaskNameUpdate`, //修改云生成名字
|
||||||
getDesignCloudResult: `/api/design/getDesignCloudResult`, //查询这条云生成记录的所有内容
|
getDesignCloudResult: `/aida/api/design/getDesignCloudResult`, //查询这条云生成记录的所有内容
|
||||||
|
|
||||||
//企业版教育版管理员页面
|
//企业版教育版管理员页面
|
||||||
subAccountList: `/api/account/subAccountList`, //查询子账号
|
subAccountList: `/aida/api/account/subAccountList`, //查询子账号
|
||||||
addOrUpdateSubAccount: `/api/account/addOrUpdateSubAccount`, //添加子账号
|
addOrUpdateSubAccount: `/aida/api/account/addOrUpdateSubAccount`, //添加子账号
|
||||||
deleteSubAccount: `/api/account/deleteSubAccount`, //删除子账号
|
deleteSubAccount: `/aida/api/account/deleteSubAccount`, //删除子账号
|
||||||
subAccountImportExcelDownload: `/api/account/subAccountImportExcelDownload`, //批量添加模板下载模板
|
subAccountImportExcelDownload: `/aida/api/account/subAccountImportExcelDownload`, //批量添加模板下载模板
|
||||||
exportAccountsToExcel: `/api/account/exportAccountsToExcel`, //教育版导出用户数据
|
exportAccountsToExcel: `/aida/api/account/exportAccountsToExcel`, //教育版导出用户数据
|
||||||
getNextSequence: `/api/project/getNextSequence`, //批量添加模板下载模板
|
getNextSequence: `/aida/api/project/getNextSequence`, //批量添加模板下载模板
|
||||||
subAccountImport: `/api/account/subAccountImport`, //模板导入
|
subAccountImport: `/aida/api/account/subAccountImport`, //模板导入
|
||||||
getGenerateFrequency: `/api/inquiry/getGenerateFrequency`, //积分使用详情
|
getGenerateFrequency: `/aida/api/inquiry/getGenerateFrequency`, //积分使用详情
|
||||||
getAllGenerateFuncName: `/api/inquiry/getAllGenerateFuncName`, //获取所有generate类型
|
getAllGenerateFuncName: `/aida/api/inquiry/getAllGenerateFuncName`, //获取所有generate类型
|
||||||
|
|
||||||
//查询某个时间内design点击次数
|
//查询某个时间内design点击次数
|
||||||
getDesignStatistic: `/api/inquiry/getDesignStatistic`, //拒绝审批
|
getDesignStatistic: `/aida/api/inquiry/getDesignStatistic`, //拒绝审批
|
||||||
getAllQuestionnaire: `/api/inquiry/getAllQuestionnaire`, //拒绝审批
|
getAllQuestionnaire: `/aida/api/inquiry/getAllQuestionnaire`, //拒绝审批
|
||||||
getActiveUserFunc: `/api/inquiry/getActiveUserFunc`, //获取各模块功能
|
getActiveUserFunc: `/aida/api/inquiry/getActiveUserFunc`, //获取各模块功能
|
||||||
toProductImageElementDelete: `/api/history/toProductImageElementDelete`, //删除指定模块上传的内容
|
toProductImageElementDelete: `/aida/api/history/toProductImageElementDelete`, //删除指定模块上传的内容
|
||||||
recentActiveUser: `/api/inquiry/recentActiveUser`, //获取近期活跃用户
|
recentActiveUser: `/aida/api/inquiry/recentActiveUser`, //获取近期活跃用户
|
||||||
recentActiveUserChart: `/api/inquiry/recentActiveUserChart`, //获取近期活跃用户图表数据
|
recentActiveUserChart: `/aida/api/inquiry/recentActiveUserChart`, //获取近期活跃用户图表数据
|
||||||
recentNewUser: `/api/inquiry/recentNewUser`, //获取近期新增用户
|
recentNewUser: `/aida/api/inquiry/recentNewUser`, //获取近期新增用户
|
||||||
recentNewUserChart: `/api/inquiry/recentNewUserChart`, //获取新增用户图表
|
recentNewUserChart: `/aida/api/inquiry/recentNewUserChart`, //获取新增用户图表
|
||||||
trialUserCountry: `/api/inquiry/trialUserCountry`, //试用用户国家-城市分布
|
trialUserCountry: `/aida/api/inquiry/trialUserCountry`, //试用用户国家-城市分布
|
||||||
conversionRate: `/api/inquiry/conversionRate`, //试用用户国家-城市分布
|
conversionRate: `/aida/api/inquiry/conversionRate`, //试用用户国家-城市分布
|
||||||
getAllUserId: `/api/inquiry/getAllUserId`, //获取所有用户id和Name
|
getAllUserId: `/aida/api/inquiry/getAllUserId`, //获取所有用户id和Name
|
||||||
adminAddUser: `/api/inquiry/addUser`, //添加用户
|
adminAddUser: `/aida/api/inquiry/addUser`, //添加用户
|
||||||
modifyUser: `/api/inquiry/modifyUser`, //修改用户
|
modifyUser: `/aida/api/inquiry/modifyUser`, //修改用户
|
||||||
publishSysMessage: `/api/message/publishSysMessage`, //发布系统任务
|
publishSysMessage: `/aida/api/message/publishSysMessage`, //发布系统任务
|
||||||
//affiliate接口
|
//affiliate接口
|
||||||
viewsIncrease: `/api/affiliate/viewsIncrease`, //增加访问量
|
viewsIncrease: `/aida/api/affiliate/viewsIncrease`, //增加访问量
|
||||||
affiliateRegistration: `/api/affiliate/registration`, //affiliate注册
|
affiliateRegistration: `/aida/api/affiliate/registration`, //affiliate注册
|
||||||
personalCenter: `/api/affiliate/personalCenter`, //affiliate个人中心
|
personalCenter: `/aida/api/affiliate/personalCenter`, //affiliate个人中心
|
||||||
affiliateList: `/api/affiliate/list`, //affiliate审批列表
|
affiliateList: `/aida/api/affiliate/list`, //affiliate审批列表
|
||||||
updateCommission: `/api/affiliate/updateCommission`, //编辑佣金比例
|
updateCommission: `/aida/api/affiliate/updateCommission`, //编辑佣金比例
|
||||||
editAffiliate: `/api/affiliate/editAffiliate`, //编辑affiliate
|
editAffiliate: `/aida/api/affiliate/editAffiliate`, //编辑affiliate
|
||||||
getEachAffiliateGeneratedRevenue: `/api/affiliate/getEachAffiliateGeneratedRevenue`, //affiliate每个用户根据日期查询收益
|
getEachAffiliateGeneratedRevenue: `/aida/api/affiliate/getEachAffiliateGeneratedRevenue`, //affiliate每个用户根据日期查询收益
|
||||||
affiliateApproval: `/api/affiliate/approval`, //affiliate同意 审批
|
affiliateApproval: `/aida/api/affiliate/approval`, //affiliate同意 审批
|
||||||
getPersonalMonthlyIncome: `/api/affiliate/getPersonalMonthlyIncome`, //affiliate图表接口
|
getPersonalMonthlyIncome: `/aida/api/affiliate/getPersonalMonthlyIncome`, //affiliate图表接口
|
||||||
getReferrals: `/api/affiliate/getReferrals`, //affiliate Referral列表
|
getReferrals: `/aida/api/affiliate/getReferrals`, //affiliate Referral列表
|
||||||
editReferral: `/api/affiliate/editReferral`, //affiliate编辑referral
|
editReferral: `/aida/api/affiliate/editReferral`, //affiliate编辑referral
|
||||||
batchDeleteReferral: `/api/affiliate/batchDeleteReferral`, //affiliate删除referral
|
batchDeleteReferral: `/aida/api/affiliate/batchDeleteReferral`, //affiliate删除referral
|
||||||
// batchDeleteReferral:`/api/affiliate/batchDeleteReferral`,//affiliate删除referral
|
// batchDeleteReferral:`/aida/api/affiliate/batchDeleteReferral`,//affiliate删除referral
|
||||||
|
|
||||||
getTasksList: `/api/tasks/getList`, //获取w为执行完的所有任务
|
getTasksList: `/aida/api/tasks/getList`, //获取w为执行完的所有任务
|
||||||
getTasksHistory: `/api/tasks/getAllTask`, //获取所有任务列表
|
getTasksHistory: `/aida/api/tasks/getAllTask`, //获取所有任务列表
|
||||||
prepareForSR: `/api/python/prepareForSR`, //超分
|
prepareForSR: `/aida/api/python/prepareForSR`, //超分
|
||||||
|
|
||||||
//作品广场
|
//作品广场
|
||||||
publish: `/api/portfolio/publish`, //发布作品到作品广场
|
publish: `/aida/api/portfolio/publish`, //发布作品到作品广场
|
||||||
getPorfolio: `/api/portfolio/page`, //查询作品广场
|
getPorfolio: `/aida/api/portfolio/page`, //查询作品广场
|
||||||
getPorfolioDetail: `/api/portfolio/detail`, //查询作品广场作品详情
|
getPorfolioDetail: `/aida/api/portfolio/detail`, //查询作品广场作品详情
|
||||||
setPorfolioChoose: `/api/portfolio/choose`, //二次创作
|
setPorfolioChoose: `/aida/api/portfolio/choose`, //二次创作
|
||||||
portfolioLike: `/api/portfolio/like`, //作品广场点赞
|
portfolioLike: `/aida/api/portfolio/like`, //作品广场点赞
|
||||||
portfolioNoLike: `/api/portfolio/unlike`, //作品广场取消点赞
|
portfolioNoLike: `/aida/api/portfolio/unlike`, //作品广场取消点赞
|
||||||
portfolioComment: `/api/portfolio/comment`, //作品广场评论
|
portfolioComment: `/aida/api/portfolio/comment`, //作品广场评论
|
||||||
portfolioCommentPage: `/api/portfolio/commentPage`, //作品广场评论列表
|
portfolioCommentPage: `/aida/api/portfolio/commentPage`, //作品广场评论列表
|
||||||
commentDelete: `/api/portfolio/commentDelete`, //删除评论
|
commentDelete: `/aida/api/portfolio/commentDelete`, //删除评论
|
||||||
porfolioDelete: `/api/portfolio/delete`, //删除作品
|
porfolioDelete: `/aida/api/portfolio/delete`, //删除作品
|
||||||
porfolioFollow: `/api/portfolio/follow`, //删除作品
|
porfolioFollow: `/aida/api/portfolio/follow`, //删除作品
|
||||||
porfolioFollow: `/api/portfolio/follow`, //关注
|
porfolioFollow: `/aida/api/portfolio/follow`, //关注
|
||||||
porfolioCancelFollow: `/api/portfolio/cancelFollow`, //取消关注
|
porfolioCancelFollow: `/aida/api/portfolio/cancelFollow`, //取消关注
|
||||||
porfolioGetFolloweeList: `/api/portfolio/getFolloweeList`, //获取关注列表
|
porfolioGetFolloweeList: `/aida/api/portfolio/getFolloweeList`, //获取关注列表
|
||||||
porfolioGetFollowerList: `/api/portfolio/getFollowerList`, //获取粉丝列表
|
porfolioGetFollowerList: `/aida/api/portfolio/getFollowerList`, //获取粉丝列表
|
||||||
|
|
||||||
//product生成
|
//product生成
|
||||||
toProduct: `/api/history/toProduct`, //开始生成
|
toProduct: `/aida/api/history/toProduct`, //开始生成
|
||||||
toProductImageResult: `/api/history/toProductImageResult`, //获取结果
|
toProductImageResult: `/aida/api/history/toProductImageResult`, //获取结果
|
||||||
toProductImageElementUpload: `/api/history/toProductImageElementUpload`, //上传
|
toProductImageElementUpload: `/aida/api/history/toProductImageElementUpload`, //上传
|
||||||
historyDeleteResult: `/api/history/deleteResult`, //relight toproduct删除
|
historyDeleteResult: `/aida/api/history/deleteResult`, //relight toproduct删除
|
||||||
generateDeleteResult: `/api/generate/deleteResult`, //pose删除
|
generateDeleteResult: `/aida/api/generate/deleteResult`, //pose删除
|
||||||
|
|
||||||
productImageLike: `/api/history/productImageLike`, //like生成结果
|
productImageLike: `/aida/api/history/productImageLike`, //like生成结果
|
||||||
productImageUnLike: `/api/history/productImageUnLike`, //取消like生成结果
|
productImageUnLike: `/aida/api/history/productImageUnLike`, //取消like生成结果
|
||||||
productImageLikeList: `/api/history/productImageLikeList`, //like生成结果
|
productImageLikeList: `/aida/api/history/productImageLikeList`, //like生成结果
|
||||||
|
|
||||||
//打光
|
//打光
|
||||||
relight: `/api/history/relight`, //开始生成
|
relight: `/aida/api/history/relight`, //开始生成
|
||||||
relightResult: `/api/history/relightResult`, //开始生成
|
relightResult: `/aida/api/history/relightResult`, //开始生成
|
||||||
|
|
||||||
//保存画布
|
//保存画布
|
||||||
canvasElementUpload: `/api/history/canvasElementUpload`, //画布上传临时图片
|
canvasElementUpload: `/aida/api/history/canvasElementUpload`, //画布上传临时图片
|
||||||
exportSave: `/api/history/exportSave`, //保存画布
|
exportSave: `/aida/api/history/exportSave`, //保存画布
|
||||||
exportSearch: `/api/history/exportSearch`, //保存画布
|
exportSearch: `/aida/api/history/exportSearch`, //保存画布
|
||||||
|
|
||||||
//活动
|
//活动
|
||||||
activity: `/api/account/activity`,
|
activity: `/aida/api/account/activity`,
|
||||||
|
|
||||||
//bradDNA
|
//bradDNA
|
||||||
brandLogoUpload: `/api/history/brandLogoUpload`, //上传bradDNA
|
brandLogoUpload: `/aida/api/history/brandLogoUpload`, //上传bradDNA
|
||||||
brandDNAGenerate: `/api/history/brandDNAGenerate`, //上传bradDNA
|
brandDNAGenerate: `/aida/api/history/brandDNAGenerate`, //上传bradDNA
|
||||||
brandDNAUpload: `/api/history/brandDNAUpload`, //上传DNA图片
|
brandDNAUpload: `/aida/api/history/brandDNAUpload`, //上传DNA图片
|
||||||
getInitializeProgress: `/api/history/getInitializeProgress`, //获取brand进度
|
getInitializeProgress: `/aida/api/history/getInitializeProgress`, //获取brand进度
|
||||||
brandDNADelete: `/api/history/brandDNADelete`, //删除brandDna
|
brandDNADelete: `/aida/api/history/brandDNADelete`, //删除brandDna
|
||||||
|
|
||||||
brandDNAPage: `/api/history/brandDNAPage`, //brand列表
|
brandDNAPage: `/aida/api/history/brandDNAPage`, //brand列表
|
||||||
brandDNASaveOrUpdate: `/api/history/brandDNASaveOrUpdate`, //提交个人信息
|
brandDNASaveOrUpdate: `/aida/api/history/brandDNASaveOrUpdate`, //提交个人信息
|
||||||
productImageInitialize: `/api/history/productImageInitialize`, //产品识别
|
productImageInitialize: `/aida/api/history/productImageInitialize`, //产品识别
|
||||||
//调查问卷
|
//调查问卷
|
||||||
questionnaire: `/api/account/questionnaire`, //保存画布
|
questionnaire: `/aida/api/account/questionnaire`, //保存画布
|
||||||
|
|
||||||
//消息系统
|
//消息系统
|
||||||
getUnreadCount: `/api/message/getUnreadCount`, //获取未读消息
|
getUnreadCount: `/aida/api/message/getUnreadCount`, //获取未读消息
|
||||||
setReadStatus: `/api/message/setReadStatus`, //设置消息已读
|
setReadStatus: `/aida/api/message/setReadStatus`, //设置消息已读
|
||||||
getHistoryNotification: `/api/message/getHistoryNotification`, //获取历史消息
|
getHistoryNotification: `/aida/api/message/getHistoryNotification`, //获取历史消息
|
||||||
oneClickRead: `/api/message/oneClickRead`, //全部设为已读
|
oneClickRead: `/aida/api/message/oneClickRead`, //全部设为已读
|
||||||
personalHomepage: `/api/account/personalHomepage`, //获取个人主页信息
|
personalHomepage: `/aida/api/account/personalHomepage`, //获取个人主页信息
|
||||||
refreshMinioUrl: `/api/third/party/refreshMinioUrl`, //获取可以使用的minio地址
|
refreshMinioUrl: `/aida/api/third/party/refreshMinioUrl`, //获取可以使用的minio地址
|
||||||
|
|
||||||
// 画布
|
// 画布
|
||||||
segAnything: `/api/python/segAnything`, //分割Anything
|
segAnything: `/aida/api/python/segAnything`, //分割Anything
|
||||||
|
|
||||||
// award页面
|
// award页面
|
||||||
checkEmail: '/api/global-award/checkEmail', // 检查邮箱是否存在
|
checkEmail: '/aida/api/global-award/checkEmail', // 检查邮箱是否存在
|
||||||
checkOTP: '/api/global-award/checkCode', // 检查验证码是否正确
|
checkOTP: '/aida/api/global-award/checkCode', // 检查验证码是否正确
|
||||||
initPdfUpload: '/api/global-award/uploads/pdf/init', // 初始化pdf上传
|
initPdfUpload: '/aida/api/global-award/uploads/pdf/init', // 初始化pdf上传
|
||||||
initVideoUpload: '/api/global-award/uploads/video/init', // 初始化video上传
|
initVideoUpload: '/aida/api/global-award/uploads/video/init', // 初始化video上传
|
||||||
uploadPDF: '/api/global-award/uploads/pdf/chunk', // 上传pdf
|
uploadPDF: '/aida/api/global-award/uploads/pdf/chunk', // 上传pdf
|
||||||
uploadVideo: '/api/global-award/uploads/video/chunk', // 上传video
|
uploadVideo: '/aida/api/global-award/uploads/video/chunk', // 上传video
|
||||||
uploadPDFComplete: '/api/global-award/uploads/pdf/complete', // 上传pdf完成
|
uploadPDFComplete: '/aida/api/global-award/uploads/pdf/complete', // 上传pdf完成
|
||||||
uploadVideoComplete: '/api/global-award/uploads/video/complete', // 上传video完成
|
uploadVideoComplete: '/aida/api/global-award/uploads/video/complete', // 上传video完成
|
||||||
submitForm: '/api/global-award/contestants/save', // 提交表单
|
submitForm: '/aida/api/global-award/contestants/save', // 提交表单
|
||||||
getContestantByID: '/api/global-award/contestants/' // 获取表单
|
getContestantByID: '/aida/api/global-award/contestants/', // 获取表单
|
||||||
|
|
||||||
|
|
||||||
|
// 卖家端接口
|
||||||
|
sellerUploadFile: '/seller/file/upload', // 卖家上传文件
|
||||||
|
checkSellerDesigner: '/seller/designer/check', // 检查卖家是否为设计师
|
||||||
|
getSellerApplyStatus: '/seller/designer/apply/status', // 获取卖家申请状态
|
||||||
|
submitSellerApply: '/seller/designer/apply', // 提交卖家申请
|
||||||
|
deleteSellerDesigner: '/seller/designer/delete', // 删除设计师
|
||||||
|
getDesignerInfo: '/seller/designer/info', // 获取设计师信息
|
||||||
|
updateDesignerInfo: '/seller/designer/update', // 更新设计师信息
|
||||||
|
getSellerOrderSummary: '/seller/order/summary', // 获取卖家订单数据总览
|
||||||
|
getSellerOrderList: '/seller/order/page', // 获取卖家订单列表
|
||||||
|
getListingPopup: '/seller/listing/popup/check', // 获取是否勾选发布作品提示
|
||||||
|
setListingPopup: '/seller/listing/popup/set', // 设置是否勾选发布作品提示
|
||||||
|
getListingList: '/seller/listing/page', // 获取商品列表,发布和未发布
|
||||||
|
putListingStatus: '/seller/listing/status', // 更新商品状态
|
||||||
},
|
},
|
||||||
|
|
||||||
axiosGet(url, config) {
|
axiosGet(url, config, pathParams) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (isLoginTime && url != '/api/portfolio/page') {
|
if (isLoginTime && url != '/aida/api/portfolio/page') {
|
||||||
resolve('')
|
resolve('')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
axios
|
axios
|
||||||
.get(url, config)
|
.get(setPathParams(url, pathParams), config)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
resolve(response)
|
resolve(response)
|
||||||
})
|
})
|
||||||
@@ -493,14 +499,14 @@ export const Https = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
axiosPut(url, data) {
|
axiosPut(url, data, pathParams) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (isLoginTime && url != '/api/portfolio/page') {
|
if (isLoginTime && url != '/aida/api/portfolio/page') {
|
||||||
resolve('')
|
resolve('')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
axios
|
axios
|
||||||
.put(url, data)
|
.put(setPathParams(url, pathParams), data)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
resolve(response)
|
resolve(response)
|
||||||
})
|
})
|
||||||
@@ -510,14 +516,14 @@ export const Https = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
axiosPost(url, data, config) {
|
axiosPost(url, data, config, pathParams) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (isLoginTime && url != '/api/portfolio/page') {
|
if (isLoginTime && url != '/aida/api/portfolio/page') {
|
||||||
resolve('')
|
resolve('')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
axios
|
axios
|
||||||
.post(url, data, config)
|
.post(setPathParams(url, pathParams), data, config)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
resolve(response)
|
resolve(response)
|
||||||
})
|
})
|
||||||
@@ -527,14 +533,14 @@ export const Https = {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
axiosDelete(url, newData) {
|
axiosDelete(url, newData, pathParams) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (isLoginTime && url != '/api/portfolio/page') {
|
if (isLoginTime && url != '/aida/api/portfolio/page') {
|
||||||
resolve('')
|
resolve('')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
axios
|
axios
|
||||||
.delete(url, { data: newData })
|
.delete(setPathParams(url, pathParams), { data: newData })
|
||||||
.then(response => {
|
.then(response => {
|
||||||
resolve(response)
|
resolve(response)
|
||||||
})
|
})
|
||||||
@@ -544,3 +550,12 @@ export const Https = {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setPathParams(url, pathParams = {}) {
|
||||||
|
const obj = typeof pathParams === 'object' ? pathParams : { id: pathParams }
|
||||||
|
const keys = Object.keys(obj)
|
||||||
|
keys.forEach(key => {
|
||||||
|
url = url.replace(new RegExp(`\\{${key}\\}`, 'g'), obj[key]);
|
||||||
|
})
|
||||||
|
return url
|
||||||
|
}
|
||||||
@@ -340,12 +340,12 @@ const navTypeList = (t)=>{
|
|||||||
value:'Models',
|
value:'Models',
|
||||||
router:'library=Models'
|
router:'library=Models'
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
icon:'fi-ss-gem',
|
// icon:'fi-ss-gem',
|
||||||
label:t('LibraryPage.brandDNA'),
|
// label:t('LibraryPage.brandDNA'),
|
||||||
value:'MyBrand',
|
// value:'MyBrand',
|
||||||
router:'library=MyBrand'
|
// router:'library=MyBrand'
|
||||||
},
|
// },
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
// history:{
|
// history:{
|
||||||
|
|||||||
@@ -672,28 +672,40 @@ function sketchToMask(sketchImage) {
|
|||||||
img.src = sketchImage;
|
img.src = sketchImage;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isValidUrl(string) {
|
||||||
|
try {
|
||||||
|
const url = new URL(string)
|
||||||
|
// 通常我们只需要 http 或 https 协议
|
||||||
|
return url.protocol === "http:" || url.protocol === "https:"
|
||||||
|
} catch (err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
isEmail,
|
isEmail,
|
||||||
getUploadUrl,
|
getUploadUrl,
|
||||||
getUniversalZoomLevel,
|
getUniversalZoomLevel,
|
||||||
rgbaToHex,
|
rgbaToHex,
|
||||||
getMinioUrl,
|
getMinioUrl,
|
||||||
base64ToFile,
|
base64ToFile,
|
||||||
dataURLtoFile,
|
dataURLtoFile,
|
||||||
blobToFile,
|
blobToFile,
|
||||||
base64toFile,
|
base64toFile,
|
||||||
rgbToHsv,
|
rgbToHsv,
|
||||||
formatTime,
|
formatTime,
|
||||||
dataURLtoBlob,
|
dataURLtoBlob,
|
||||||
isMoible,
|
isMoible,
|
||||||
downloadIamge,
|
downloadIamge,
|
||||||
downloadVideoWithFetch,
|
downloadVideoWithFetch,
|
||||||
getBrowserInfo,
|
getBrowserInfo,
|
||||||
setPubDate,
|
setPubDate,
|
||||||
murmur,
|
murmur,
|
||||||
setGradual,
|
setGradual,
|
||||||
calculateGradientCoordinate,
|
calculateGradientCoordinate,
|
||||||
segmentImage,
|
segmentImage,
|
||||||
UrlToFile,
|
UrlToFile,
|
||||||
sketchToMask
|
sketchToMask,
|
||||||
|
isValidUrl
|
||||||
}
|
}
|
||||||
@@ -318,7 +318,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="homeMain_user">
|
<div class="homeMain_user">
|
||||||
<div class="homeMain_user_icon" @click="openAccount">
|
<div class="homeMain_user_icon">
|
||||||
<img :src="userDetail.avatar" alt="" />
|
<img :src="userDetail.avatar" alt="" />
|
||||||
</div>
|
</div>
|
||||||
<div class="homeMain_user_detail">
|
<div class="homeMain_user_detail">
|
||||||
@@ -373,11 +373,15 @@
|
|||||||
<i class="fi fi-rs-notebook"></i>
|
<i class="fi fi-rs-notebook"></i>
|
||||||
<span class="select_item_des">{{ $t('Header.ViewOrders') }}</span>
|
<span class="select_item_des">{{ $t('Header.ViewOrders') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="select_item" @click="onBecomeSeller">
|
<div class="select_item" @click="openAccount">
|
||||||
|
<span class="icon"><svg-icon name="home" /></span>
|
||||||
|
<span class="select_item_des">{{ $t('Header.PersonalCenter') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="select_item" @click="onBecomeSeller" v-if="!isSeller">
|
||||||
<span class="icon"><svg-icon name="seller-sellerIndex" /></span>
|
<span class="icon"><svg-icon name="seller-sellerIndex" /></span>
|
||||||
<span class="select_item_des">{{ $t('Header.BecomeSeller') }}</span>
|
<span class="select_item_des">{{ $t('Header.BecomeSeller') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="select_item" @click="onSellerDashboard">
|
<div class="select_item" @click="onSellerDashboard" v-else>
|
||||||
<span class="icon"><svg-icon name="seller-sellerIndex" /></span>
|
<span class="icon"><svg-icon name="seller-sellerIndex" /></span>
|
||||||
<span class="select_item_des">{{ $t('Header.SellerDashboard') }}</span>
|
<span class="select_item_des">{{ $t('Header.SellerDashboard') }}</span>
|
||||||
<a-badge :dot="true"></a-badge>
|
<a-badge :dot="true"></a-badge>
|
||||||
@@ -409,7 +413,7 @@
|
|||||||
<a href="https://www.facebook.com/CodeCreateAI" target="_blank" >
|
<a href="https://www.facebook.com/CodeCreateAI" target="_blank" >
|
||||||
<img src="@/assets/images/socialMediaLogo/faceBookIcon.svg" alt="">
|
<img src="@/assets/images/socialMediaLogo/faceBookIcon.svg" alt="">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.youtube.com/@AiDA-3.1" target="_blank" >
|
<a href="https://www.youtube.com/@Code-Create_AiDA" target="_blank" >
|
||||||
<img src="@/assets/images/socialMediaLogo/socialIcons.svg" alt="">
|
<img src="@/assets/images/socialMediaLogo/socialIcons.svg" alt="">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.linkedin.com/company/code-create-limited" target="_blank" >
|
<a href="https://www.linkedin.com/company/code-create-limited" target="_blank" >
|
||||||
@@ -1073,9 +1077,13 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isSeller = computed(() => {
|
||||||
|
return store.state.seller.isSeller
|
||||||
|
})
|
||||||
return {
|
return {
|
||||||
store,
|
store,
|
||||||
userDetail,
|
userDetail,
|
||||||
|
isSeller,
|
||||||
t,
|
t,
|
||||||
...toRefs(homeMainData),
|
...toRefs(homeMainData),
|
||||||
...toRefs(historyData),
|
...toRefs(historyData),
|
||||||
@@ -1150,6 +1158,7 @@ export default defineComponent({
|
|||||||
reject()
|
reject()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
this.store.dispatch('seller/get_isSeller')//获取是否是卖家
|
||||||
let isMurmur = getCookie('isMurmur') //获取是否是试用用户
|
let isMurmur = getCookie('isMurmur') //获取是否是试用用户
|
||||||
this.isMurmur = JSON.parse(isMurmur)
|
this.isMurmur = JSON.parse(isMurmur)
|
||||||
if (this.userDetail.userId && this.userDetail.userId > -1) {
|
if (this.userDetail.userId && this.userDetail.userId > -1) {
|
||||||
@@ -1378,7 +1387,6 @@ export default defineComponent({
|
|||||||
this.store.commit('set_dataLoading', false)
|
this.store.commit('set_dataLoading', false)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
setLocale(v) {
|
setLocale(v) {
|
||||||
// 同步更新 localStorage 中的 loginLanguage
|
// 同步更新 localStorage 中的 loginLanguage
|
||||||
if (v) {
|
if (v) {
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ import { ExclamationCircleOutlined } from '@ant-design/icons-vue'
|
|||||||
import { useStore } from 'vuex'
|
import { useStore } from 'vuex'
|
||||||
import { setLang } from '@/tool/guide'
|
import { setLang } from '@/tool/guide'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import { gsap, TweenMax } from 'gsap'
|
import { gsap, TweenMax } from 'gsap'
|
||||||
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
import { ScrollTrigger } from 'gsap/ScrollTrigger'
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@@ -71,6 +71,7 @@ export default defineComponent({
|
|||||||
const {t, locale} = useI18n()
|
const {t, locale} = useI18n()
|
||||||
const store = useStore()
|
const store = useStore()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
let registerModel = ref()
|
let registerModel = ref()
|
||||||
let data = reactive({})
|
let data = reactive({})
|
||||||
|
|
||||||
@@ -117,7 +118,14 @@ export default defineComponent({
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
window.addEventListener('resize', updataIsMoblie)
|
window.addEventListener('resize', updataIsMoblie)
|
||||||
// 初始化语言设置
|
// 初始化语言设置
|
||||||
const savedLang = localStorage.getItem('loginLanguage')
|
let savedLang = localStorage.getItem('loginLanguage')
|
||||||
|
if(route?.params?.lang == 'cn'){
|
||||||
|
savedLang = 'CHINESE_SIMPLIFIED'
|
||||||
|
localStorage.setItem('loginLanguage', savedLang)
|
||||||
|
}{
|
||||||
|
savedLang = 'ENGLISH'
|
||||||
|
localStorage.setItem('loginLanguage', savedLang)
|
||||||
|
}
|
||||||
if (savedLang) {
|
if (savedLang) {
|
||||||
isChinese.value = savedLang === 'CHINESE_SIMPLIFIED'
|
isChinese.value = savedLang === 'CHINESE_SIMPLIFIED'
|
||||||
locale.value = savedLang
|
locale.value = savedLang
|
||||||
|
|||||||
@@ -338,7 +338,7 @@
|
|||||||
<a-upload
|
<a-upload
|
||||||
class="search_upImg"
|
class="search_upImg"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
:action="uploadUrl + '/api/element/upload'"
|
:action="uploadUrl + '/aida/api/element/upload'"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:before-upload="beforeUpload"
|
:before-upload="beforeUpload"
|
||||||
:data="{
|
:data="{
|
||||||
@@ -387,7 +387,7 @@
|
|||||||
<a-upload
|
<a-upload
|
||||||
class="search_upImg"
|
class="search_upImg"
|
||||||
:capture="null"
|
:capture="null"
|
||||||
:action="uploadUrl + '/api/element/upload'"
|
:action="uploadUrl + '/aida/api/element/upload'"
|
||||||
list-type="picture-card"
|
list-type="picture-card"
|
||||||
:data="{
|
:data="{
|
||||||
...upload,
|
...upload,
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="become-seller">
|
<div class="become-seller">
|
||||||
<seller-header
|
<seller-header />
|
||||||
title="Apply to Become a Seller"
|
|
||||||
tip="Join the Stylish Parade and start selling your design work"
|
|
||||||
/>
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<seller-review v-if="isSubmit" />
|
<seller-apply v-if="applyStatus === null" @submit="onSubmit" />
|
||||||
<seller-apply v-else @submit="isSubmit = true" />
|
<seller-review v-else />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -16,7 +13,20 @@
|
|||||||
import sellerHeader from "../seller-header.vue"
|
import sellerHeader from "../seller-header.vue"
|
||||||
import sellerReview from "./sellerReview.vue"
|
import sellerReview from "./sellerReview.vue"
|
||||||
import sellerApply from "./sellerApply.vue"
|
import sellerApply from "./sellerApply.vue"
|
||||||
const isSubmit = ref(false)
|
import { Https } from "@/tool/https"
|
||||||
|
import { useStore } from "vuex"
|
||||||
|
import { ApplyStatus } from "@/store/seller/index.d"
|
||||||
|
const store = useStore()
|
||||||
|
const applyStatus = computed(() => store.state.seller.applyStatus)
|
||||||
|
const onSubmit = () => store.commit("seller/set_applyStatus", ApplyStatus.Pending)
|
||||||
|
const getSellerApplyStatus = () => {
|
||||||
|
store.commit("set_loading", true)
|
||||||
|
Https.axiosGet(Https.httpUrls.getSellerApplyStatus).then((res) => {
|
||||||
|
store.commit("set_loading", false)
|
||||||
|
store.commit("seller/set_applyStatus", res)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
getSellerApplyStatus()
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.become-seller {
|
.become-seller {
|
||||||
|
|||||||
@@ -2,56 +2,58 @@
|
|||||||
<div class="seller-apply">
|
<div class="seller-apply">
|
||||||
<div class="session">
|
<div class="session">
|
||||||
<div class="content mini-scrollbar">
|
<div class="content mini-scrollbar">
|
||||||
<div class="title">Brand Information</div>
|
<div class="title">{{ $t("ApplySeller.formTitle") }}</div>
|
||||||
<div class="tip">Share a few details to set up your seller profile</div>
|
<div class="tip">{{ $t("ApplySeller.formTip") }}</div>
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<a-form :model="formData" :rules="formRules" layout="vertical" ref="formRef">
|
<a-form :model="formData" :rules="formRules" layout="vertical" ref="formRef">
|
||||||
<a-form-item label="Store Name" name="storeName">
|
<a-form-item :label="$t('Seller.storeName')" name="storeName">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData.storeName"
|
v-model:value="formData.storeName"
|
||||||
placeholder="Enter the store name"
|
:placeholder="$t('Seller.storeNameDesc')"
|
||||||
:maxlength="80"
|
:maxlength="80"
|
||||||
/>
|
/>
|
||||||
<span class="tip-length">{{ formData.storeName.length }}/80</span>
|
<span class="tip-length">{{ formData.storeName.length }}/80</span>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Owner’s Full Name" name="fullName">
|
<a-form-item :label="$t('Seller.ownerName')" name="fullName">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData.fullName"
|
v-model:value="formData.fullName"
|
||||||
placeholder="Enter store owner's full name"
|
:placeholder="$t('Seller.ownerNameDesc')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<a-form-item label="Email" name="email">
|
<a-form-item :label="$t('Seller.email')" name="email">
|
||||||
<a-input
|
<a-input
|
||||||
type="email"
|
type="email"
|
||||||
v-model:value="formData.email"
|
v-model:value="formData.email"
|
||||||
placeholder="Enter email"
|
:placeholder="$t('Seller.emailDesc')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Phone Number" name="phoneNumber">
|
<a-form-item :label="$t('Seller.mobile')" name="mobile">
|
||||||
<a-input
|
<a-input
|
||||||
type="tel"
|
type="tel"
|
||||||
v-model:value="formData.phoneNumber"
|
v-model:value="formData.mobile"
|
||||||
placeholder="Enter phone number"
|
:placeholder="$t('Seller.mobileDesc')"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</div>
|
</div>
|
||||||
<a-form-item label="Store Description" name="description">
|
<a-form-item :label="$t('Seller.storeDescription')" name="description">
|
||||||
<a-textarea
|
<a-textarea
|
||||||
v-model:value="formData.description"
|
v-model:value="formData.description"
|
||||||
placeholder="Briefly describe your design style and store features..."
|
:placeholder="$t('Seller.storeDescriptionDesc')"
|
||||||
:maxlength="500"
|
:maxlength="500"
|
||||||
/>
|
/>
|
||||||
<span class="tip-length">{{ formData.description.length }}/500</span>
|
<span class="tip-length">{{ formData.description.length }}/500</span>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Portfoilo/Social Media Links">
|
<a-form-item :label="$t('Seller.links')">
|
||||||
<a-input
|
<a-input
|
||||||
placeholder="https://"
|
placeholder="https://"
|
||||||
v-for="(v, i) in formData.links"
|
v-for="(v, i) in formData.links"
|
||||||
:key="i"
|
:key="i"
|
||||||
v-model:value="formData.links[i]"
|
v-model:value="formData.links[i]"
|
||||||
>
|
>
|
||||||
<template #prefix>Link {{ i + 1 }}</template>
|
<template #prefix>{{
|
||||||
|
$t("Seller.link", { index: i + 1 })
|
||||||
|
}}</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
<a-input
|
<a-input
|
||||||
placeholder="https://"
|
placeholder="https://"
|
||||||
@@ -71,33 +73,25 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="session">
|
<div class="session">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="title">Brand Information</div>
|
<div class="title">{{ $t("ApplySeller.termsTitle") }}</div>
|
||||||
<div class="tip">Share a few details to set up your seller profile</div>
|
<div class="tip">{{ $t("ApplySeller.termsTip") }}</div>
|
||||||
<div class="agreement">
|
<div class="agreement">
|
||||||
<div class="title">AiDA Seller Agreement</div>
|
<div class="title">{{ $t("ApplySeller.agreementTitle") }}</div>
|
||||||
<div class="tip">
|
<div class="tip">{{ $t("ApplySeller.agreementTip") }}</div>
|
||||||
By checking the box below, you agree to comply with the following terms:
|
|
||||||
</div>
|
|
||||||
<ul>
|
<ul>
|
||||||
<li>Provide accurate and truthful personal and store information</li>
|
<li v-for="(v, i) in 8" :key="i">
|
||||||
<li>Only sell original designs or content with proper licensing</li>
|
{{ $t(`ApplySeller.agreementItem${i + 1}`) }}
|
||||||
<li>Maintain high quality standards for all products</li>
|
</li>
|
||||||
<li>Respond to customer inquiries within 48 hours</li>
|
|
||||||
<li>Ship orders within promised timeframes</li>
|
|
||||||
<li>Comply with AiDA's terms of service and community guidelines</li>
|
|
||||||
<li>Pay applicable platform fees and transaction charges</li>
|
|
||||||
<li>Handle customer disputes professionally and fairly</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<a-checkbox class="agree-agreement" v-model:checked="isAgreement">
|
<a-checkbox class="agree-agreement" v-model:checked="isAgreement">
|
||||||
I have read and agree to the Seller Agreement, understanding my responsibilities
|
{{ $t("ApplySeller.agreementAgreement") }}
|
||||||
and obligations as a seller on the AiDA platform.
|
|
||||||
</a-checkbox>
|
</a-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="btns">
|
<div class="btns">
|
||||||
<button class="cancel" @click="onCancel">Cancel</button>
|
<button class="cancel" @click="onCancel">{{ $t("Seller.cancel") }}</button>
|
||||||
<button class="submit" :disabled="!isAgreement" @click="onSubmit">
|
<button class="submit" :disabled="!isAgreement" @click="onSubmit">
|
||||||
Submit Application
|
{{ $t("ApplySeller.submitApplication") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,23 +100,26 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive } from "vue"
|
import { ref, reactive } from "vue"
|
||||||
|
import { useI18n } from "vue-i18n"
|
||||||
|
const { t } = useI18n()
|
||||||
import { useRoute, useRouter } from "vue-router"
|
import { useRoute, useRouter } from "vue-router"
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
import { Https } from "@/tool/https"
|
||||||
const emit = defineEmits(["submit"])
|
const emit = defineEmits(["submit"])
|
||||||
const formRules = {
|
const formRules = {
|
||||||
storeName: [{ required: true, message: "Enter the store name" }],
|
storeName: [{ required: true, message: t("Seller.storeNameDesc") }],
|
||||||
fullName: [{ required: true, message: "Enter store owner's full name" }],
|
fullName: [{ required: true, message: t("Seller.ownerNameDesc") }],
|
||||||
email: [{ required: true, message: "Enter email" }],
|
email: [{ required: true, message: t("Seller.emailDesc") }],
|
||||||
phoneNumber: [{ required: true, message: "Enter phone number" }],
|
mobile: [{ required: true, message: t("Seller.mobileDesc") }],
|
||||||
description: [{ required: true, message: "Enter store description" }]
|
description: [{ required: true, message: t("Seller.storeDescriptionErr") }]
|
||||||
}
|
}
|
||||||
const formRef = ref(null)
|
const formRef = ref(null)
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
storeName: "",
|
storeName: "",
|
||||||
fullName: "",
|
fullName: "",
|
||||||
email: "",
|
email: "",
|
||||||
phoneNumber: "",
|
mobile: "",
|
||||||
description: "",
|
description: "",
|
||||||
links: ["", ""]
|
links: ["", ""]
|
||||||
})
|
})
|
||||||
@@ -139,8 +136,20 @@
|
|||||||
formRef.value
|
formRef.value
|
||||||
.validate()
|
.validate()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log(formData)
|
const data = {
|
||||||
emit("submit")
|
// userId: 0,
|
||||||
|
shopName: formData.storeName,
|
||||||
|
// avatar: "",
|
||||||
|
// brandBanner: "",
|
||||||
|
ownerName: formData.fullName,
|
||||||
|
email: formData.email,
|
||||||
|
mobile: formData.mobile,
|
||||||
|
description: formData.description,
|
||||||
|
socialLinks: JSON.stringify(formData.links.filter((v) => v))
|
||||||
|
}
|
||||||
|
Https.axiosPost(Https.httpUrls.submitSellerApply, data).then((res) => {
|
||||||
|
emit("submit")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
console.log("validate failed")
|
console.log("validate failed")
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="seller-review">
|
<div class="seller-review">
|
||||||
<img class="success" src="@/assets/images/seller/success-1.png" />
|
<img class="success" src="@/assets/images/seller/success-1.png" />
|
||||||
<div class="title">Application Submitted</div>
|
<div class="title">{{ $t("ApplySeller.applicationSubmitted") }}</div>
|
||||||
<div class="tip">
|
<div
|
||||||
Our team will review your application and get back to you within 1–3 business days.
|
class="tip"
|
||||||
You'll receive a notification in your email once a decision has been made.
|
v-html="$t('ApplySeller.applicationSubmittedTip', { click: 'onPersonalCenter' })"
|
||||||
</div>
|
></div>
|
||||||
<div class="step-list">
|
<div class="step-list">
|
||||||
<div v-for="v in list" :key="v.title" class="step-item">
|
<div v-for="v in list" :key="v.title" class="step-item">
|
||||||
<img v-show="!v.active" src="@/assets/images/seller/success-0.png" />
|
<img v-show="!v.active" src="@/assets/images/seller/success-0.png" />
|
||||||
@@ -16,35 +16,49 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="home-btn" @click="onBackToHome">Back to Homepage</button>
|
<button class="home-btn" @click="onBackToHome">
|
||||||
|
{{ $t("ApplySeller.backToHomepage") }}
|
||||||
|
</button>
|
||||||
|
<div class="tip">ID: {{ userId }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from "vue"
|
import { ref, computed } from "vue"
|
||||||
import { useRoute, useRouter } from "vue-router"
|
import { useRoute, useRouter } from "vue-router"
|
||||||
|
import { useStore } from "vuex"
|
||||||
|
import { ApplyStatus } from "@/store/seller/index.d"
|
||||||
|
import { useI18n } from "vue-i18n"
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const list = ref([
|
const store = useStore()
|
||||||
|
const userId = computed(() => store.state.UserHabit.userDetail.userId)
|
||||||
|
const applyStatus = computed(() => store.state.seller.applyStatus)
|
||||||
|
const list = computed(() => [
|
||||||
{
|
{
|
||||||
title: "Step 1: Submit Application",
|
title: t("ApplySeller.auditStatus1_title"),
|
||||||
tip: "Fill out the seller information form and agree to our terms",
|
tip: t("ApplySeller.auditStatus1_tip"),
|
||||||
active: true
|
active: [ApplyStatus.Pending, ApplyStatus.Approved].includes(applyStatus.value)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Step 2: Review & Verification",
|
title: t("ApplySeller.auditStatus2_title"),
|
||||||
tip: "Our team will review your application (typically 1-3 business days)",
|
tip: t("ApplySeller.auditStatus2_tip"),
|
||||||
active: false
|
active: applyStatus.value === ApplyStatus.Approved
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Step 3: Start Selling",
|
title: t("ApplySeller.auditStatus3_title"),
|
||||||
tip: "Once approved, access your seller dashboard and start listing products ",
|
tip: t("ApplySeller.auditStatus3_tip"),
|
||||||
active: false
|
active: applyStatus.value === ApplyStatus.Approved
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
const onBackToHome = () => {
|
const onBackToHome = () => {
|
||||||
router.push({ name: "home" })
|
router.push({ name: "home" })
|
||||||
}
|
}
|
||||||
|
window.onPersonalCenter = () => {
|
||||||
|
router.push("/home/account")
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.seller-review {
|
.seller-review {
|
||||||
@@ -69,11 +83,15 @@
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
> .tip {
|
> .tip {
|
||||||
font-family: pingfang_medium;
|
font-family: pingfang_regular;
|
||||||
font-size: 1.8rem;
|
font-size: 1.8rem;
|
||||||
line-height: 170%;
|
line-height: 170%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #585858;
|
color: #585858;
|
||||||
|
&:deep(span) {
|
||||||
|
color: #585858;
|
||||||
|
font-family: pingfang_heavy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
> .step-list {
|
> .step-list {
|
||||||
margin: 2.6rem 0;
|
margin: 2.6rem 0;
|
||||||
|
|||||||
@@ -2,53 +2,53 @@
|
|||||||
<div class="brand-info">
|
<div class="brand-info">
|
||||||
<a-form :model="formData" :rules="isEdit ? formRules : {}" layout="vertical" ref="formRef">
|
<a-form :model="formData" :rules="isEdit ? formRules : {}" layout="vertical" ref="formRef">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<a-form-item label="Store Name" name="storeName">
|
<a-form-item :label="$t('Seller.storeName')" name="shopName">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData.storeName"
|
v-model:value="formData.shopName"
|
||||||
placeholder="Enter the store name"
|
:placeholder="$t('Seller.storeNameDesc')"
|
||||||
:maxlength="80"
|
:maxlength="80"
|
||||||
:readonly="!isEdit"
|
:readonly="!isEdit"
|
||||||
/>
|
/>
|
||||||
<span v-show="isEdit" class="tip-length"
|
<span v-show="isEdit" class="tip-length"
|
||||||
>{{ formData.storeName.length }}/80</span
|
>{{ formData.shopName.length }}/80</span
|
||||||
>
|
>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Owner’s Full Name" name="fullName">
|
<a-form-item :label="$t('Seller.ownerName')" name="ownerName">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:value="formData.fullName"
|
v-model:value="formData.ownerName"
|
||||||
placeholder="Enter store owner's full name"
|
:placeholder="$t('Seller.ownerNameDesc')"
|
||||||
:readonly="!isEdit"
|
:readonly="!isEdit"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<a-form-item label="Email" name="email">
|
<a-form-item :label="$t('Seller.email')" name="email">
|
||||||
<a-input
|
<a-input
|
||||||
type="email"
|
type="email"
|
||||||
v-model:value="formData.email"
|
v-model:value="formData.email"
|
||||||
placeholder="Enter email"
|
:placeholder="$t('Seller.emailDesc')"
|
||||||
:readonly="!isEdit"
|
:readonly="!isEdit"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Phone Number" name="phoneNumber">
|
<a-form-item :label="$t('Seller.mobile')" name="mobile">
|
||||||
<a-input
|
<a-input
|
||||||
type="tel"
|
type="tel"
|
||||||
v-model:value="formData.phoneNumber"
|
v-model:value="formData.mobile"
|
||||||
placeholder="Enter phone number"
|
:placeholder="$t('Seller.mobileDesc')"
|
||||||
:readonly="!isEdit"
|
:readonly="!isEdit"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<a-form-item label="Portfoilo/Social Media Links">
|
<a-form-item :label="$t('Seller.links')">
|
||||||
<a-input
|
<a-input
|
||||||
placeholder="https://"
|
placeholder="https://"
|
||||||
v-for="(v, i) in formData.links"
|
v-for="(v, i) in formData.socialLinks"
|
||||||
:key="i"
|
:key="i"
|
||||||
v-model:value="formData.links[i]"
|
v-model:value="formData.socialLinks[i]"
|
||||||
:readonly="!isEdit"
|
:readonly="!isEdit"
|
||||||
>
|
>
|
||||||
<template #prefix>Link {{ i + 1 }}</template>
|
<template #prefix>{{ $t("Seller.link", { index: i + 1 }) }}</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
<a-input
|
<a-input
|
||||||
placeholder="https://"
|
placeholder="https://"
|
||||||
@@ -63,10 +63,10 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="Store Description" name="description">
|
<a-form-item :label="$t('Seller.storeDescription')" name="description">
|
||||||
<a-textarea
|
<a-textarea
|
||||||
v-model:value="formData.description"
|
v-model:value="formData.description"
|
||||||
placeholder="Briefly describe your design style and store features..."
|
:placeholder="$t('Seller.storeDescriptionDesc')"
|
||||||
:maxlength="500"
|
:maxlength="500"
|
||||||
:readonly="!isEdit"
|
:readonly="!isEdit"
|
||||||
/>
|
/>
|
||||||
@@ -82,6 +82,12 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, watch } from "vue"
|
import { ref, reactive, watch } from "vue"
|
||||||
import { useRoute, useRouter } from "vue-router"
|
import { useRoute, useRouter } from "vue-router"
|
||||||
|
import { useStore } from "vuex"
|
||||||
|
import { useI18n } from "vue-i18n"
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const store = useStore()
|
||||||
|
const designerInfo = computed(() => store.state.seller.designerInfo)
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -91,38 +97,53 @@
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
const formRules = {
|
const formRules = {
|
||||||
storeName: [{ required: true, message: "Enter the store name" }],
|
shopName: [{ required: true, message: t("Seller.storeNameDesc") }],
|
||||||
fullName: [{ required: true, message: "Enter store owner's full name" }],
|
ownerName: [{ required: true, message: t("Seller.ownerNameDesc") }],
|
||||||
email: [{ required: true, message: "Enter email" }],
|
email: [{ required: true, message: t("Seller.emailDesc") }],
|
||||||
phoneNumber: [{ required: true, message: "Enter phone number" }],
|
mobile: [{ required: true, message: t("Seller.mobileDesc") }],
|
||||||
description: [{ required: true, message: "Enter store description" }]
|
description: [{ required: true, message: t("Seller.storeDescriptionErr") }]
|
||||||
}
|
}
|
||||||
|
|
||||||
const formRef = ref(null)
|
const formRef = ref(null)
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
storeName: "",
|
shopName: "",
|
||||||
fullName: "",
|
ownerName: "",
|
||||||
email: "",
|
email: "",
|
||||||
phoneNumber: "",
|
mobile: "",
|
||||||
description: "",
|
description: "",
|
||||||
links: ["", ""]
|
socialLinks: ["", ""]
|
||||||
})
|
})
|
||||||
const newLink = ref("")
|
const newLink = ref("")
|
||||||
const addLink = () => {
|
const addLink = () => {
|
||||||
formData.links.push(newLink.value)
|
formData.socialLinks.push(newLink.value)
|
||||||
newLink.value = ""
|
newLink.value = ""
|
||||||
}
|
}
|
||||||
|
watch(
|
||||||
|
() => designerInfo.value,
|
||||||
|
(v) => updateFormData()
|
||||||
|
)
|
||||||
|
const updateFormData = () => {
|
||||||
|
formData.shopName = designerInfo.value.shopName
|
||||||
|
formData.ownerName = designerInfo.value.ownerName
|
||||||
|
formData.email = designerInfo.value.email
|
||||||
|
formData.mobile = designerInfo.value.mobile
|
||||||
|
formData.description = designerInfo.value.description
|
||||||
|
formData.socialLinks = JSON.parse(JSON.stringify(designerInfo.value.socialLinks))
|
||||||
|
}
|
||||||
|
updateFormData()
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.isEdit,
|
() => props.isEdit,
|
||||||
(v) => (v ? edit() : cancel())
|
(v) => (v ? edit() : cancel())
|
||||||
)
|
)
|
||||||
const edit = () => {}
|
const edit = () => {}
|
||||||
const cancel = () => {}
|
const cancel = () => {
|
||||||
|
formRef.value.clearValidate()
|
||||||
|
updateFormData()
|
||||||
|
}
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
const valid = await formRef.value.validate()
|
await formRef.value.validate()
|
||||||
if (!valid) return Promise.reject(false)
|
return JSON.parse(JSON.stringify(formData))
|
||||||
console.log(valid)
|
|
||||||
return valid
|
|
||||||
}
|
}
|
||||||
defineExpose({
|
defineExpose({
|
||||||
submit
|
submit
|
||||||
|
|||||||
346
src/views/SellerDashboard/BrandProfile/image-clip-dialog.vue
Normal file
@@ -0,0 +1,346 @@
|
|||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
class="image-clip-dialog generalModel"
|
||||||
|
:class="{ 'is-product': data.isProduct }"
|
||||||
|
v-model:visible="show"
|
||||||
|
:footer="null"
|
||||||
|
width="70%"
|
||||||
|
:maskClosable="false"
|
||||||
|
:centered="true"
|
||||||
|
:closable="false"
|
||||||
|
wrapClassName="#app"
|
||||||
|
:keyboard="false"
|
||||||
|
:destroyOnClose="true"
|
||||||
|
>
|
||||||
|
<div class="image-clip-dialog-box">
|
||||||
|
<div class="header" :class="{ 'is-product': data.isProduct }">
|
||||||
|
<div class="title">{{ data.title }}</div>
|
||||||
|
<div class="right flex">
|
||||||
|
<div v-if="coverOrigin.length > 1" class="origin-container flex align-center">
|
||||||
|
<span>{{ $t("Seller.cropFrom") }}</span>
|
||||||
|
<div class="origin-select flex align-center">
|
||||||
|
<div
|
||||||
|
class="origin-item sketch"
|
||||||
|
:class="{ selected: currentOrigin === 'sketch' }"
|
||||||
|
@click="handleChangeOrigin('sketch')"
|
||||||
|
>
|
||||||
|
{{ $t("Seller.sketch") }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="origin-item product"
|
||||||
|
:class="{ selected: currentOrigin === 'mainProductImage' }"
|
||||||
|
@click="handleChangeOrigin('mainProductImage')"
|
||||||
|
>
|
||||||
|
{{ $t("Seller.mainProductImage") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="submit" v-if="!data.isPreview" @click="onSubmit">
|
||||||
|
<svg-icon name="seller-dui" size="24" />
|
||||||
|
</div>
|
||||||
|
<button @click="onCancel">{{ $t("Seller.cancel") }}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="content" :class="{ 'is-product': data.isProduct }">
|
||||||
|
<div class="crop-wrapper">
|
||||||
|
<div v-if="data.isProduct" class="tips">{{ tips }}</div>
|
||||||
|
<image-clip
|
||||||
|
ref="imageClipRef"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:ratio="data.ratio"
|
||||||
|
:isProduct="isProduct"
|
||||||
|
:url="data.url"
|
||||||
|
:type="type"
|
||||||
|
@change="(v) => (data.preview_url = v)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="preview"
|
||||||
|
:class="{
|
||||||
|
'is-product': data.isProduct,
|
||||||
|
'is-apparel': type === 'apparel',
|
||||||
|
'is-cover': type === 'cover'
|
||||||
|
}"
|
||||||
|
v-if="data.isPreview"
|
||||||
|
>
|
||||||
|
<div class="title">
|
||||||
|
<span class="icon"><svg-icon name="seller-preview" size="24" /></span>
|
||||||
|
<span class="label">{{ $t("Seller.cropPreview") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="preview-image">
|
||||||
|
<img :src="data.preview_url" />
|
||||||
|
</div>
|
||||||
|
<div class="submit" @click="onSubmit">
|
||||||
|
<svg-icon name="seller-dui" size="24" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, computed } from "vue"
|
||||||
|
import ImageClip from "./image-clip.vue"
|
||||||
|
import { useI18n } from "vue-i18n"
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
isProduct: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const tips = computed(() => {
|
||||||
|
if (props.type === "cover") {
|
||||||
|
return t("Seller.imageClipCoverTip")
|
||||||
|
}
|
||||||
|
if (props.type === "mainProductImage") {
|
||||||
|
return t("Seller.imageClipMainProductImageTip")
|
||||||
|
}
|
||||||
|
if (props.type === "sketch") {
|
||||||
|
return t("Seller.imageClipSketchTip")
|
||||||
|
}
|
||||||
|
if (props.type === "apparel") {
|
||||||
|
return t("Seller.imageClipApparelTip")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = reactive({
|
||||||
|
url: "",
|
||||||
|
title: "Crop Image",
|
||||||
|
preview_url: "",
|
||||||
|
ratio: [1, 1],
|
||||||
|
isPreview: true,
|
||||||
|
callback: null,
|
||||||
|
isProduct: false // 是否商品编辑
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentOrigin = ref("sketch")
|
||||||
|
const coverOrigin = ref([])
|
||||||
|
const handleChangeOrigin = (type) => {
|
||||||
|
const targetOrigin = coverOrigin.value.find((el) => el.type === type)
|
||||||
|
if (!targetOrigin) return
|
||||||
|
|
||||||
|
currentOrigin.value = type
|
||||||
|
data.url = targetOrigin.url
|
||||||
|
}
|
||||||
|
|
||||||
|
const show = ref(false)
|
||||||
|
const open = (url, callback, options, origin) => {
|
||||||
|
if (!props.isProduct) {
|
||||||
|
if (!url || !callback) return
|
||||||
|
}
|
||||||
|
|
||||||
|
coverOrigin.value = []
|
||||||
|
data.url = null
|
||||||
|
currentOrigin.value = "sketch"
|
||||||
|
|
||||||
|
data.url = url
|
||||||
|
data.callback = callback
|
||||||
|
data.ratio = options.ratio || [1, 1]
|
||||||
|
data.isPreview = true
|
||||||
|
data.preview_url = ""
|
||||||
|
data.title = options.title || "Crop Image"
|
||||||
|
if (options) {
|
||||||
|
if (options.hasOwnProperty("isPreview")) data.isPreview = options.isPreview
|
||||||
|
data.isProduct = options.isProduct
|
||||||
|
}
|
||||||
|
if (origin?.length) {
|
||||||
|
coverOrigin.value = origin
|
||||||
|
const defaultOrigin = origin.find((el) => el.type === options?.coverFrom) || origin[0]
|
||||||
|
currentOrigin.value = defaultOrigin.type
|
||||||
|
data.url = defaultOrigin.url
|
||||||
|
}
|
||||||
|
show.value = true
|
||||||
|
}
|
||||||
|
const onCancel = () => {
|
||||||
|
show.value = false
|
||||||
|
}
|
||||||
|
const imageClipRef = ref(null)
|
||||||
|
const onSubmit = () => {
|
||||||
|
imageClipRef.value.getCropBlob().then((blob) => {
|
||||||
|
if (data.callback) data.callback(blobToFile(blob, "image.png"), currentOrigin.value)
|
||||||
|
onCancel()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 将blob转换为file对象
|
||||||
|
const blobToFile = (blob, fileName) => {
|
||||||
|
return new File([blob], fileName, { type: blob.type })
|
||||||
|
}
|
||||||
|
defineExpose({
|
||||||
|
open
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.image-clip-dialog-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.submit {
|
||||||
|
width: 4rem;
|
||||||
|
height: 4rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #262626;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
> .header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 5rem;
|
||||||
|
&.is-product {
|
||||||
|
margin-bottom: 2.4rem;
|
||||||
|
}
|
||||||
|
> .title {
|
||||||
|
font-family: pingfang_heavy;
|
||||||
|
font-size: 2.4rem;
|
||||||
|
color: #595959;
|
||||||
|
}
|
||||||
|
> .right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 2rem;
|
||||||
|
> button {
|
||||||
|
width: 10rem;
|
||||||
|
height: 4.8rem;
|
||||||
|
border-radius: 4rem;
|
||||||
|
border: none;
|
||||||
|
background: #e4e5eb;
|
||||||
|
font-family: pingfang_heavy;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.origin-container {
|
||||||
|
font-weight: 400;
|
||||||
|
color: #000;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
.origin-select {
|
||||||
|
margin-left: 1.2rem;
|
||||||
|
height: 4.8rem;
|
||||||
|
border: 1px solid #c7c7c7;
|
||||||
|
border-radius: 3rem;
|
||||||
|
column-gap: 1.2rem;
|
||||||
|
padding: 0.8rem;
|
||||||
|
.origin-item {
|
||||||
|
height: 3.2rem;
|
||||||
|
line-height: 3.2rem;
|
||||||
|
border-radius: 2rem;
|
||||||
|
cursor: pointer;
|
||||||
|
&.selected {
|
||||||
|
background-color: #000;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
&.sketch {
|
||||||
|
padding: 0 1.9rem;
|
||||||
|
}
|
||||||
|
&.product {
|
||||||
|
padding: 0 2.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .content {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
.crop-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 1.2rem;
|
||||||
|
.tips {
|
||||||
|
text-align: center;
|
||||||
|
color: #585858;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.is-product {
|
||||||
|
column-gap: 18.6rem;
|
||||||
|
.crop-wrapper {
|
||||||
|
width: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .image-clip {
|
||||||
|
flex: 1;
|
||||||
|
&.is-product {
|
||||||
|
width: initial;
|
||||||
|
flex: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .preview {
|
||||||
|
margin-left: 6rem;
|
||||||
|
width: 28rem;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2.4rem;
|
||||||
|
min-height: 0;
|
||||||
|
|
||||||
|
> .title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1.2rem;
|
||||||
|
> .label {
|
||||||
|
font-family: pingfang_heavy;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .preview-image {
|
||||||
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
> .preview-image > img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
> .submit {
|
||||||
|
margin-top: auto;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
&.is-product {
|
||||||
|
margin-left: 0;
|
||||||
|
> .preview-image > img {
|
||||||
|
width: 20.8rem;
|
||||||
|
height: 36.7rem;
|
||||||
|
box-shadow: 4px 4px 16px 0px #0000000f;
|
||||||
|
border: 1px solid #ededed;
|
||||||
|
}
|
||||||
|
&.is-cover {
|
||||||
|
> .preview-image > img {
|
||||||
|
width: 29.7rem;
|
||||||
|
height: 37.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.is-apparel {
|
||||||
|
> .preview-image > img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
391
src/views/SellerDashboard/BrandProfile/image-clip.vue
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
<template>
|
||||||
|
<div class="image-clip" :class="{ 'is-product': isProduct }" :data-crop-type="type || ''">
|
||||||
|
<div class="image-clip-body" :class="{ 'is-cover': type === 'cover' }" ref="imageClipBody">
|
||||||
|
<VueCropper
|
||||||
|
ref="cropper"
|
||||||
|
:img="url"
|
||||||
|
crossOrigin="Anonymous"
|
||||||
|
:autoCrop="true"
|
||||||
|
:fixedNumber="ratio"
|
||||||
|
:fixed="isProduct ? type !== 'apparel' : true"
|
||||||
|
movable
|
||||||
|
@realTime="onChange"
|
||||||
|
outputType="png"
|
||||||
|
:full="true"
|
||||||
|
></VueCropper>
|
||||||
|
</div>
|
||||||
|
<div class="clip_opterate">
|
||||||
|
<div class="item" @click="rotateLeft()">
|
||||||
|
<span class="icon iconfont icon-chexiao operate_icon"></span>
|
||||||
|
</div>
|
||||||
|
<div class="item" @click="rotateRight()">
|
||||||
|
<span class="icon iconfont icon-chexiao operate_icon icon_chexiao_sec"></span>
|
||||||
|
</div>
|
||||||
|
<div class="item" @click="changeScale(-0.1)">
|
||||||
|
<span class="operate_icon icon_font">-</span>
|
||||||
|
</div>
|
||||||
|
<div class="item" @click="changeScale(0.1)">
|
||||||
|
<span class="operate_icon icon_font">+</span>
|
||||||
|
</div>
|
||||||
|
<div class="item" @click="refreshCrop()">
|
||||||
|
<span class="icon iconfont icon-shuaxin operate_icon"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref, useAttrs, onMounted, onBeforeUnmount, computed, nextTick, watch } from "vue"
|
||||||
|
import "vue-cropper/dist/index.css"
|
||||||
|
import { VueCropper } from "vue-cropper"
|
||||||
|
const props = defineProps({
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
ratio: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [1, 1]
|
||||||
|
},
|
||||||
|
isProduct: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
fixedBox: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: () => ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const attrs = useAttrs()
|
||||||
|
|
||||||
|
const autoCropHeight = computed(() => {
|
||||||
|
let height = 426
|
||||||
|
if (props.type === "cover") height = 375
|
||||||
|
else if (props.type === "apparel") height = 320
|
||||||
|
return height
|
||||||
|
})
|
||||||
|
|
||||||
|
const onChange = (data) => {
|
||||||
|
if (attrs.onChange) {
|
||||||
|
getCropUrl().then((url) => attrs.onChange(url))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const cropper = ref(null)
|
||||||
|
const imageClipBody = ref(null)
|
||||||
|
let injectLabelFrame = 0
|
||||||
|
const observer = new ResizeObserver((entries) => {
|
||||||
|
refreshCrop()
|
||||||
|
})
|
||||||
|
|
||||||
|
const clearCropLabels = (cropperBox) => {
|
||||||
|
if (!cropperBox) return
|
||||||
|
cropperBox.querySelectorAll(".cropper-line-label").forEach((node) => node.remove())
|
||||||
|
}
|
||||||
|
|
||||||
|
const createCropLabel = ({ text, top, className }) => {
|
||||||
|
const label = document.createElement("div")
|
||||||
|
label.className = `cropper-line-label ${className}`
|
||||||
|
label.textContent = text
|
||||||
|
label.style.top = top
|
||||||
|
label.style.left = className === "label-v" ? "50%" : "0"
|
||||||
|
label.style.transform =
|
||||||
|
className === "label-v" ? "translate(-50%, -50%)" : "translateY(-50%)"
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
|
||||||
|
const centerLabelTop = "8px"
|
||||||
|
|
||||||
|
const cropLabelMap = {
|
||||||
|
cover: [
|
||||||
|
{ text: "crown", top: "2.67%", className: "label-h" },
|
||||||
|
{ text: "hip line", top: "63.47%", className: "label-h" },
|
||||||
|
{ text: "mid-thigh", top: "92.8%", className: "label-h" },
|
||||||
|
{ text: "center", top: centerLabelTop, className: "label-v" }
|
||||||
|
],
|
||||||
|
mainProductImage: [
|
||||||
|
{ text: "crown", top: "2.67%", className: "label-h" },
|
||||||
|
{ text: "footbase", top: "97.6%", className: "label-h" },
|
||||||
|
{ text: "center", top: centerLabelTop, className: "label-v" }
|
||||||
|
],
|
||||||
|
sketch: [
|
||||||
|
{ text: "crown", top: "2.67%", className: "label-h" },
|
||||||
|
{ text: "footbase", top: "97.6%", className: "label-h" },
|
||||||
|
{ text: "center", top: centerLabelTop, className: "label-v" }
|
||||||
|
],
|
||||||
|
apparel: [{ text: "center", top: centerLabelTop, className: "label-v" }]
|
||||||
|
}
|
||||||
|
|
||||||
|
const injectCropLabel = () => {
|
||||||
|
const cropperBox = imageClipBody.value?.querySelector(".cropper-view-box")
|
||||||
|
|
||||||
|
if (!cropperBox) return false
|
||||||
|
|
||||||
|
clearCropLabels(cropperBox)
|
||||||
|
;(cropLabelMap[props.type] || []).forEach((config) => {
|
||||||
|
cropperBox.appendChild(createCropLabel(config))
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const scheduleInjectCropLabel = (retry = 0) => {
|
||||||
|
cancelAnimationFrame(injectLabelFrame)
|
||||||
|
injectLabelFrame = requestAnimationFrame(() => {
|
||||||
|
if (!injectCropLabel() && retry < 10) {
|
||||||
|
scheduleInjectCropLabel(retry + 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
observer.observe(imageClipBody.value)
|
||||||
|
scheduleInjectCropLabel()
|
||||||
|
})
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
observer.disconnect()
|
||||||
|
cancelAnimationFrame(injectLabelFrame)
|
||||||
|
})
|
||||||
|
const rotateLeft = () => {
|
||||||
|
cropper.value.rotateLeft()
|
||||||
|
}
|
||||||
|
const rotateRight = () => {
|
||||||
|
cropper.value.rotateRight()
|
||||||
|
}
|
||||||
|
const refreshCrop = () => {
|
||||||
|
cropper.value.refresh()
|
||||||
|
}
|
||||||
|
const changeScale = (num = 1) => {
|
||||||
|
cropper.value.changeScale(num)
|
||||||
|
}
|
||||||
|
const getCropUrl = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
cropper.value.getCropData(resolve)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getCropBlob = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
cropper.value.getCropBlob(resolve)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
[() => props.type, () => props.url],
|
||||||
|
async () => {
|
||||||
|
await nextTick()
|
||||||
|
scheduleInjectCropLabel()
|
||||||
|
},
|
||||||
|
{ flush: "post" }
|
||||||
|
)
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
getCropUrl,
|
||||||
|
getCropBlob
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.image-clip {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
// height: 100%;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: calc(2rem * 1.2);
|
||||||
|
padding: calc(1.3rem * 1.2) calc(1.3rem * 1.2) calc(2rem * 1.2);
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
.image-clip-body {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(40rem * 1.2);
|
||||||
|
// height: 53rem;
|
||||||
|
background: yellow;
|
||||||
|
:deep(.cropper-box) {
|
||||||
|
.cropper-box-canvas {
|
||||||
|
background-color: #ffffff;
|
||||||
|
|
||||||
|
// img {
|
||||||
|
// height: 100%;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.is-cover {
|
||||||
|
:deep(.vue-cropper) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
// :deep(.cropper-box-canvas) {
|
||||||
|
// width: 31.1rem !important;
|
||||||
|
// left: 50% !important;
|
||||||
|
// transform: translateX(-50%) !important;
|
||||||
|
// img {
|
||||||
|
// display: none;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.clip_opterate {
|
||||||
|
margin: calc(2.7rem * 1.2) auto 0;
|
||||||
|
border-radius: calc(1.6rem * 1.2);
|
||||||
|
display: flex;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #e2e2e4;
|
||||||
|
width: calc(24rem * 1.2);
|
||||||
|
|
||||||
|
.item {
|
||||||
|
width: calc(4.7rem * 1.2);
|
||||||
|
height: calc(4rem * 1.2);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-right: 0.1rem solid #e6e8ea;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.icon_chexiao_sec {
|
||||||
|
transform: rotateY(180deg); /* 垂直镜像翻转 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.operate_icon {
|
||||||
|
font-size: calc(1.8rem * 1.2);
|
||||||
|
color: rgba(102, 102, 102, 1);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon_font {
|
||||||
|
font-size: calc(2.5rem * 1.2);
|
||||||
|
position: relative;
|
||||||
|
top: calc(-0.3rem * 1.2);
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-shuaxin {
|
||||||
|
font-size: calc(1.4rem * 1.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-product {
|
||||||
|
.image-clip-body {
|
||||||
|
width: 45.7rem;
|
||||||
|
height: 45.7rem;
|
||||||
|
:deep(.cropper-modal) {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
:deep(.vue-cropper .cropper-view-box) {
|
||||||
|
position: relative;
|
||||||
|
overflow: visible !important;
|
||||||
|
/* 原有的蓝色边框(outline)由组件控制,这里不干涉 */
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.vue-cropper .cropper-view-box::after) {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid rgba(75, 165, 255, 0.85);
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 9; /* 位于图片之上,但在控制点之下 */
|
||||||
|
background-image: none;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
:deep(.vue-cropper .crop-point) {
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-crop-type="cover"] {
|
||||||
|
.image-clip-body {
|
||||||
|
:deep(.vue-cropper .cropper-view-box::after) {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(to right, #4ba5ff 50%, transparent 50%),
|
||||||
|
linear-gradient(to right, #4ba5ff 50%, transparent 50%),
|
||||||
|
linear-gradient(to right, #4ba5ff 50%, transparent 50%),
|
||||||
|
linear-gradient(to bottom, #4ba5ff 50%, transparent 50%);
|
||||||
|
background-repeat: repeat-x, repeat-x, repeat-x, repeat-y;
|
||||||
|
background-size:
|
||||||
|
8px 1px,
|
||||||
|
8px 1px,
|
||||||
|
8px 1px,
|
||||||
|
1px 8px;
|
||||||
|
background-position:
|
||||||
|
0 2.67%,
|
||||||
|
0 63.47%,
|
||||||
|
0 92.8%,
|
||||||
|
50% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-crop-type="mainProductImage"],
|
||||||
|
&[data-crop-type="sketch"] {
|
||||||
|
.image-clip-body {
|
||||||
|
:deep(.vue-cropper .cropper-view-box::after) {
|
||||||
|
background-image:
|
||||||
|
linear-gradient(to right, #4ba5ff 50%, transparent 50%),
|
||||||
|
linear-gradient(to right, #4ba5ff 50%, transparent 50%),
|
||||||
|
linear-gradient(to bottom, #4ba5ff 50%, transparent 50%);
|
||||||
|
background-repeat: repeat-x, repeat-x, repeat-y;
|
||||||
|
background-size:
|
||||||
|
8px 1px,
|
||||||
|
8px 1px,
|
||||||
|
1px 8px;
|
||||||
|
background-position:
|
||||||
|
0 2.67%,
|
||||||
|
0 97.6%,
|
||||||
|
50% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-crop-type="apparel"] {
|
||||||
|
.image-clip-body {
|
||||||
|
:deep(.vue-cropper .cropper-view-box::after) {
|
||||||
|
background-image: linear-gradient(to bottom, #4ba5ff 50%, transparent 50%);
|
||||||
|
background-repeat: repeat-y;
|
||||||
|
background-size: 1px 8px;
|
||||||
|
background-position: 50% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.cropper-line-label {
|
||||||
|
position: absolute;
|
||||||
|
color: #4ba5ff; /* 统一颜色 */
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
background: rgba(255, 255, 255); /* 浅色背景确保在深色图片上可见 */
|
||||||
|
// padding: 0 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
white-space: nowrap;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 10;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 水平线名称:放在线段上方 2px */
|
||||||
|
.label-h {
|
||||||
|
transform: translateY(-100%);
|
||||||
|
margin-top: -2px;
|
||||||
|
left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 垂直线名称:放在裁剪框顶部边缘上方 */
|
||||||
|
.label-v {
|
||||||
|
transform: translateX(-50%);
|
||||||
|
top: -20px;
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="brand-profile-index">
|
<div class="brand-profile-index mini-scrollbar">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="bg">
|
<div class="bg">
|
||||||
<img v-if="banner" :src="banner" />
|
<img v-if="banner" :src="banner" />
|
||||||
<div v-else class="null">
|
<div v-else class="null">
|
||||||
<span class="icon"><svg-icon name="seller-picture" size="60" /></span>
|
<span class="icon"><svg-icon name="seller-picture" size="60" /></span>
|
||||||
<span class="tip">Your brand banner has not been set up yet.</span>
|
<span class="tip">{{ $t("Seller.brandProfileBgNullTip") }}</span>
|
||||||
</div>
|
</div>
|
||||||
<button>Change Brand Banner</button>
|
<button @click="onChangeBanner">{{ $t("Seller.changeBrandBanner") }}</button>
|
||||||
</div>
|
</div>
|
||||||
<!-- 头像 -->
|
<!-- 头像 -->
|
||||||
<div class="avatar">
|
<div class="avatar">
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
<div v-else class="null">
|
<div v-else class="null">
|
||||||
<svg-icon name="seller-user" size="48" />
|
<svg-icon name="seller-user" size="48" />
|
||||||
</div>
|
</div>
|
||||||
<span class="icon">
|
<span class="icon" @click="onChangeAvatar">
|
||||||
<svg-icon name="seller-camera" size="24" />
|
<svg-icon name="seller-camera" size="24" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -25,40 +25,112 @@
|
|||||||
<div class="and-profile-footer">
|
<div class="and-profile-footer">
|
||||||
<template v-if="isEdit">
|
<template v-if="isEdit">
|
||||||
<div class="btns">
|
<div class="btns">
|
||||||
<button class="cancel" @click="onCancel">Cancel</button>
|
<button class="cancel" @click="onCancel()">{{ $t("Seller.cancel") }}</button>
|
||||||
<button class="submit" @click="onSubmit">Save Change</button>
|
<button class="submit" @click="onSubmit()">{{ $t("Seller.saveChange") }}</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="tip">Changes will be reflected on your Stylish Parade brand page.</p>
|
<p class="tip">{{ $t("Seller.brandProfileEditTip") }}</p>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="btns">
|
<div class="btns">
|
||||||
<button class="edit" @click="onEdit">Edit</button>
|
<button class="edit" @click="onEdit">{{ $t("Seller.edit") }}</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="tip"> </p>
|
<p class="tip"> </p>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
<image-clip-dialog ref="imageClipDialogRef" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from "vue"
|
import { Https } from "@/tool/https"
|
||||||
|
import { ref, computed } from "vue"
|
||||||
import BrandInfo from "./brand-info.vue"
|
import BrandInfo from "./brand-info.vue"
|
||||||
const banner = ref("http://118.31.39.42:3000/falls/5bd8065cbb396eb5a8ef0a142605139358734e57.png")
|
import ImageClipDialog from "./image-clip-dialog.vue"
|
||||||
const avatar = ref("http://118.31.39.42:3000/falls/20251024140128_10355_1.jpg")
|
import { useStore } from "vuex"
|
||||||
|
import { useI18n } from "vue-i18n"
|
||||||
|
const { t } = useI18n()
|
||||||
|
const store = useStore()
|
||||||
|
store.dispatch("seller/get_designerInfo")
|
||||||
|
const designerInfo = computed(() => store.state.seller.designerInfo)
|
||||||
|
const avatar = computed(() => designerInfo.value.avatar)
|
||||||
|
const banner = computed(() => designerInfo.value.brandBanner)
|
||||||
const isEdit = ref(false)
|
const isEdit = ref(false)
|
||||||
const brandInfoRef = ref(null)
|
const brandInfoRef = ref(null)
|
||||||
|
const imageClipDialogRef = ref(null)
|
||||||
|
|
||||||
|
// 选择本机图片
|
||||||
|
const uploadImg = (onChange) => {
|
||||||
|
const input = document.createElement("input")
|
||||||
|
input.type = "file"
|
||||||
|
input.accept = "image/*"
|
||||||
|
// 监听文件输入框的变化事件
|
||||||
|
input.addEventListener("change", (event) => {
|
||||||
|
event.preventDefault()
|
||||||
|
const file = event.target.files[0]
|
||||||
|
const url = URL.createObjectURL(file)
|
||||||
|
onChange({ url, file })
|
||||||
|
})
|
||||||
|
input.click()
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadFile = async (file) => {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append("file", file)
|
||||||
|
return Https.axiosPost(Https.httpUrls.sellerUploadFile, formData, {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "multipart/form-data"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onChangeBanner = () => {
|
||||||
|
uploadImg(({ url }) => {
|
||||||
|
imageClipDialogRef.value.open(
|
||||||
|
url,
|
||||||
|
async (file) => {
|
||||||
|
store.commit("set_loading", true)
|
||||||
|
const res = await uploadFile(file)
|
||||||
|
onSubmit({ brandBanner: res })
|
||||||
|
store.commit("set_loading", false)
|
||||||
|
},
|
||||||
|
{ ratio: [40, 7], isPreview: false, title: t("Seller.cropBrandBanner") }
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const onChangeAvatar = () => {
|
||||||
|
uploadImg(({ url }) => {
|
||||||
|
imageClipDialogRef.value.open(
|
||||||
|
url,
|
||||||
|
async (file) => {
|
||||||
|
store.commit("set_loading", true)
|
||||||
|
const res = await uploadFile(file)
|
||||||
|
onSubmit({ avatar: res })
|
||||||
|
store.commit("set_loading", false)
|
||||||
|
},
|
||||||
|
{ ratio: [1, 1], isPreview: true, title: t("Seller.cropAvatar") }
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
const onEdit = () => {
|
const onEdit = () => {
|
||||||
isEdit.value = true
|
isEdit.value = true
|
||||||
}
|
}
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
isEdit.value = false
|
isEdit.value = false
|
||||||
}
|
}
|
||||||
const onSubmit = () => {
|
const onSubmit = async (value = null) => {
|
||||||
brandInfoRef.value
|
const res = value ? value : await brandInfoRef.value.submit()
|
||||||
.submit()
|
const data = {
|
||||||
.then(() => {
|
...designerInfo.value,
|
||||||
isEdit.value = false
|
...res
|
||||||
})
|
}
|
||||||
.catch(() => {})
|
try {
|
||||||
|
data.socialLinks = JSON.stringify(data.socialLinks)
|
||||||
|
} catch (error) {
|
||||||
|
data.socialLinks = JSON.stringify([])
|
||||||
|
}
|
||||||
|
Https.axiosPut(Https.httpUrls.updateDesignerInfo, data).then((res) => {
|
||||||
|
isEdit.value = false
|
||||||
|
store.commit("seller/set_designerInfo", data)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@@ -72,6 +144,7 @@
|
|||||||
margin-bottom: 6rem;
|
margin-bottom: 6rem;
|
||||||
> .bg {
|
> .bg {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
min-height: 15rem;
|
||||||
> img {
|
> img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|||||||
74
src/views/SellerDashboard/MyListings/EditDetail/Status.vue
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
<div class="status-wrapper flex flex-col flex-1">
|
||||||
|
<seller-header
|
||||||
|
class="edit-detail-header"
|
||||||
|
/>
|
||||||
|
<div class="status-container flex flex-col flex-1 flex-center">
|
||||||
|
<img src="@/assets/images/seller/success-0.png" class="icon" alt="" />
|
||||||
|
<div class="title">{{ $t(title) }}</div>
|
||||||
|
<div class="desc">
|
||||||
|
{{ $t(desc) }}
|
||||||
|
</div>
|
||||||
|
<div class="btn" @click="handleBack">Back to My Listings</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed } from "vue"
|
||||||
|
import { useRoute, useRouter } from "vue-router"
|
||||||
|
import SellerHeader from "../../seller-header.vue"
|
||||||
|
const ROUTE = useRoute()
|
||||||
|
const ROUTER = useRouter()
|
||||||
|
const title = computed(() => {
|
||||||
|
if (ROUTE.params.status === "publish") return "SellerListEdit.listingLive"
|
||||||
|
if (ROUTE.params.status === "draft") return "SellerListEdit.draftSaved"
|
||||||
|
})
|
||||||
|
|
||||||
|
const desc = computed(() => {
|
||||||
|
if (ROUTE.params.status === "publish") return "SellerListEdit.publishDesc"
|
||||||
|
if (ROUTE.params.status === "draft") return "SellerListEdit.draftDesc"
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
ROUTER.push({ name: "myListingsIndex" })
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.status-wrapper {
|
||||||
|
.status-container {
|
||||||
|
row-gap: 2.4rem;
|
||||||
|
font-weight: 400;
|
||||||
|
.title {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
}
|
||||||
|
.icon {
|
||||||
|
width: 8.33rem;
|
||||||
|
height: 8.33rem;
|
||||||
|
}
|
||||||
|
.desc {
|
||||||
|
width: 58.2rem;
|
||||||
|
text-align: center;
|
||||||
|
white-space: pre-line;
|
||||||
|
color: #585858;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
margin-top: 3.6rem;
|
||||||
|
height: 6rem;
|
||||||
|
width: 30rem;
|
||||||
|
border-radius: 4rem;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 6rem;
|
||||||
|
padding: 0 2rem;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
column-gap: 0.8rem;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #000;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
115
src/views/SellerDashboard/MyListings/EditDetail/agents.md
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
# EditDetail Page Agent Notes
|
||||||
|
|
||||||
|
This directory owns the seller listing edit/create detail page.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `index.vue`: route-level container. Keep orchestration here: history-state entry mode, API calls, page switching, validation, save/publish navigation, image crop dialog wiring.
|
||||||
|
- `api.ts`: API wrappers for listing detail, sketch detail, listing batch save, status update, and file upload.
|
||||||
|
- `types.ts`: shared page-local TypeScript types. Add new cross-component page types here instead of duplicating interfaces in child components.
|
||||||
|
- `components/TopImageSection.vue`: presentational block for `sketch`, `mainProductImage`, and `cover`.
|
||||||
|
- `components/ProductImageList.vue`: presentational product-image selector and selected/main badge display.
|
||||||
|
- `components/ApparelSketchList.vue`: presentational apparel sketch list and crop trigger.
|
||||||
|
- `components/ListingForm.vue`: presentational listing form. Emits field updates; does not call APIs.
|
||||||
|
- `components/Radio.vue`: local radio/multi-select button component.
|
||||||
|
- `Status.vue`: save/publish result status page.
|
||||||
|
|
||||||
|
## Component Boundaries
|
||||||
|
|
||||||
|
- Keep `index.vue` as the single source of truth for `selectList`, `currentPage`, `currentListing`, per-listing `firstSelectedIndex`, and crop/save behavior.
|
||||||
|
- Child components should receive props and emit events only. Do not import listing APIs or mutate parent state directly from children.
|
||||||
|
- If a new visual section is added to this page, prefer a new child component under `components/` plus shared types in `types.ts`.
|
||||||
|
|
||||||
|
## Vue SFC Order
|
||||||
|
|
||||||
|
- Vue single-file components must keep sections in this order: `<template>` first, then `<script setup lang="ts">`, then `<style>`.
|
||||||
|
- When creating or refactoring `.vue` files in this page, preserve that order even if external Vue guidance suggests another layout.
|
||||||
|
|
||||||
|
## Image Category Mapping
|
||||||
|
|
||||||
|
Detail API images are mapped by `category`:
|
||||||
|
|
||||||
|
- `cover` -> `currentListing.cover`
|
||||||
|
- `cover_from` -> `currentListing.coverFrom`; `imageUrl` stores the source image URL, not the literal source key. Resolve it against `sketch` and `mainProductImage` when hydrating. Keep backward compatibility for old rows whose `imageUrl` is `sketch` or `mainProductImage`.
|
||||||
|
- `sketch` -> `currentListing.sketch`
|
||||||
|
- `mainProductImage` or `main_product` -> `currentListing.mainProductImage`
|
||||||
|
- `product` -> non-video entries in `currentListing.prodImageList`
|
||||||
|
- `firstFrame`, `gif`, and `video` -> one video entry in `currentListing.prodImageList` when the three rows share the same `sortOrder`
|
||||||
|
- `apparel` -> `currentListing.sketchList`
|
||||||
|
|
||||||
|
When saving, preserve the backend's expected image categories. Confirm backend naming before changing `main_product`, `product`, `firstFrame`, `gif`, `video`, or `mainProductImage`.
|
||||||
|
|
||||||
|
中文补充:
|
||||||
|
|
||||||
|
- 详情接口返回的 `images` 要按 `category` 回填到页面状态,不要只按数组顺序猜类型。
|
||||||
|
- `cover_from` 不是封面图本身,而是记录封面裁剪来源。它的 `imageUrl` 传来源图片链接,回显时用这个 URL 和 `sketch`、`mainProductImage` 比较,恢复裁剪弹窗里的来源选择。
|
||||||
|
- `main_product` 表示页面右上方的主产品图 URL;普通 `product` 只表示产品图列表里的非视频图片。
|
||||||
|
- 视频不要保存成 `product`。视频必须拆成 `firstFrame`、`gif`、`video` 三类,并在回显时按相同 `sortOrder` 合并成一个视频项。
|
||||||
|
|
||||||
|
## Product Image Rules
|
||||||
|
|
||||||
|
- The `main` badge represents the first selected product image, not the most recently selected one.
|
||||||
|
- `firstSelectedIndex` is stored on each `ListingItem` and passed to `ProductImageList.vue`.
|
||||||
|
- Hydrating detail data must only set `mainProductImage` from explicit `main_product` or `mainProductImage` rows. Never infer it from selected `product` rows.
|
||||||
|
- Selecting a product image should only set `mainProductImage` when no main image is currently tracked by that listing's `firstSelectedIndex`.
|
||||||
|
- Unselecting the current main product image clears `mainProductImage` and resets `firstSelectedIndex`.
|
||||||
|
- Videos can be selected and saved, but they cannot become `mainProductImage`, must not set `firstSelectedIndex`, and must not display the `main` badge.
|
||||||
|
|
||||||
|
中文补充:
|
||||||
|
|
||||||
|
- `main` 标识只给图片,不给视频。
|
||||||
|
- 数据回显时,只有接口明确返回 `main_product` / `mainProductImage` 才能设置主图。不要因为某个 `product` 是已选中状态,就自动把它当成 `mainProductImage` 或显示 `main`。
|
||||||
|
- 第一次选择视频时可以弹 warning,但视频本身仍然要保持选中;只是不要把它写入 `mainProductImage`,也不要更新 `firstSelectedIndex`。
|
||||||
|
- 如果先选中视频,再选中图片,图片仍然可以成为第一个主图。
|
||||||
|
- 如果取消的是当前主图图片,需要清空 `mainProductImage` 和 `firstSelectedIndex`;取消普通图片或视频不应影响主图。
|
||||||
|
|
||||||
|
## Save Image Ordering
|
||||||
|
|
||||||
|
- Every saved image row must include `sortOrder`.
|
||||||
|
- `sortOrder` is scoped per category; each category starts its own sequence.
|
||||||
|
- For `product` rows, save the image currently used as `mainProductImage` first, selected non-main images next, and unselected images last.
|
||||||
|
- Save video media as three rows with categories `firstFrame`, `gif`, and `video`. The three rows from the same video item must share the same `sortOrder`.
|
||||||
|
- When hydrating detail data, group `firstFrame`, `gif`, and `video` rows by matching `sortOrder` and restore the combined video item, including its selected state. Accept `isSelected`, old typo `isSeleted`, and `selected` from the API.
|
||||||
|
|
||||||
|
中文补充:
|
||||||
|
|
||||||
|
- `sortOrder` 是按 category 分开排的,不同 category 之间不要共用一个全局序号。
|
||||||
|
- `product` 的排序规则是:当前作为 `mainProductImage` 的图片第一,其他已选图片其次,未选图片最后。
|
||||||
|
- 同一个视频拆出的 `firstFrame`、`gif`、`video` 三条数据必须使用同一个 `sortOrder`。例如第一个视频三条都是 `sortOrder: 1`,第二个视频三条都是 `sortOrder: 2`。
|
||||||
|
- 回显视频时,用相同 `sortOrder` 找回一组 `firstFrame/gif/video`。三条里任意一条带选中标记,都应恢复为这个视频已选中。
|
||||||
|
- 选中字段要兼容 `isSelected`、历史拼写 `isSeleted`、以及 `selected`。
|
||||||
|
|
||||||
|
## Crop Flow
|
||||||
|
|
||||||
|
- `TopImageSection.vue` and `ApparelSketchList.vue` emit `crop`.
|
||||||
|
- `index.vue` handles `handleClickCrop`, opens `ImageClipDialog`, uploads with `uploadFile`, then writes the returned URL into the correct field/list item.
|
||||||
|
- Keep cover crop ratio at `[4, 5]`; other crop types use `[9, 16]`.
|
||||||
|
- Cover crop can be based on `sketch` or `mainProductImage`. Store the chosen source in `coverFrom`, save it via `cover_from.imageUrl` as the source image URL, and pass it back into `ImageClipDialog` so reopening cover crop restores the selected source.
|
||||||
|
|
||||||
|
中文补充:
|
||||||
|
|
||||||
|
- cover 裁剪弹窗会在 `sketch` 和 `mainProductImage` 之间切来源。用户保存 cover 时,父组件需要同时保存裁剪后的 cover URL 和本次使用的来源。
|
||||||
|
- 下次重新打开 cover 裁剪时,应该按 `coverFrom` 恢复来源选择,并用对应的原图作为裁剪图,不要直接拿已裁好的 cover 图再次裁。
|
||||||
|
- 如果只有一个来源图可用,就按可用来源打开;如果两个来源都可用,要显示来源切换。
|
||||||
|
|
||||||
|
## Form Flow
|
||||||
|
|
||||||
|
- `ListingForm.vue` accepts scalar form props and emits `update:*` events.
|
||||||
|
- `index.vue` writes those events back into `currentListing`.
|
||||||
|
- Category options are derived from current gender and Vuex `UserHabit` state.
|
||||||
|
|
||||||
|
## Validation And Navigation
|
||||||
|
|
||||||
|
- `validatePublishRequired()` validates each listing before publish.
|
||||||
|
- Draft currently requires `cover` before save.
|
||||||
|
- After save/publish, routing goes to `Status` with route param `status`.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- Run `npm run build` after behavior or type changes.
|
||||||
|
- Build can fail before code bundling completes if the existing `feedbackSurvey.vue` Google Fonts import cannot be fetched. If the failure is only `fonts.googleapis.com` socket/DNS related, retry when network is available.
|
||||||
|
- Project ESLint currently fails before linting files because `.eslintrc.js` contains invalid env key `se6`; do not treat that as a page-specific regression.
|
||||||
|
|
||||||
|
## Known Caution
|
||||||
|
|
||||||
|
- This page has active local edits. Before broad refactors, inspect both staged and unstaged diffs.
|
||||||
62
src/views/SellerDashboard/MyListings/EditDetail/api.ts
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import { Https } from "@/tool/https"
|
||||||
|
import type { ListingImageCategory, SketchDetailResponse } from "./types"
|
||||||
|
|
||||||
|
// 编辑时根据ID获取信息
|
||||||
|
export const fetchListingDetailById = (id) => {
|
||||||
|
return Https.axiosGet("/seller/listing/detail", { params: { id } })
|
||||||
|
}
|
||||||
|
|
||||||
|
type SketchIDs = Array<number | string>
|
||||||
|
// 获取designItemId对应的产品图
|
||||||
|
export const fetchSketchDetail = (data: SketchIDs): Promise<SketchDetailResponse[]> => {
|
||||||
|
let params = "?"
|
||||||
|
data.forEach((id, index) => {
|
||||||
|
if (index === data.length - 1) {
|
||||||
|
params += `designItemIds=${id}`
|
||||||
|
} else {
|
||||||
|
params += `designItemIds=${id}&`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return Https.axiosGet(`/aida/api/seller/sketchDetail${params}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImageObj {
|
||||||
|
id?: number // 图片id,有值会更新,没有会自动新增
|
||||||
|
category: ListingImageCategory // 图片类型
|
||||||
|
imageUrl?: string | null
|
||||||
|
isSelected?: number
|
||||||
|
sortOrder?: number
|
||||||
|
}
|
||||||
|
interface DetailData {
|
||||||
|
id: number | string // 商品Id
|
||||||
|
title: string // 商品名
|
||||||
|
description: string // 商品描述
|
||||||
|
price: number | string // 价格
|
||||||
|
stock?: number // 库存
|
||||||
|
viewCount?: number // 浏览量
|
||||||
|
status: 0 | 1 | 2 // 0草稿 1发布 2删除
|
||||||
|
images: ImageObj[]
|
||||||
|
designFor: "male" | "female"
|
||||||
|
productCategory: string[] | null
|
||||||
|
}
|
||||||
|
// 保存/更新表单
|
||||||
|
export const fetchUpdateListing = (data: DetailData[]) => {
|
||||||
|
return Https.axiosPost("/seller/listing/batch", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StatusData {
|
||||||
|
id: number | string
|
||||||
|
status: 0 | 1 | 2 // 0草稿 1发布 2删除
|
||||||
|
}
|
||||||
|
// 设置商品状态
|
||||||
|
export const fetchChangeStatus = (data: StatusData) => {
|
||||||
|
return Https.axiosPut("/seller/listing/status", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const uploadFile = (file) => {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append("file", file)
|
||||||
|
return Https.axiosPost("/seller/file/upload", formData, {
|
||||||
|
headers: { "Content-Type": "multipart/form-data", Accept: "*/*" }
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
<template>
|
||||||
|
<div class="apparel-container">
|
||||||
|
<div class="title">
|
||||||
|
<span class="main-title">{{ $t("SellerListEdit.apparelSketchTitle") }}</span>
|
||||||
|
<span class="sub-title">{{ $t("SellerListEdit.apparelSketchSubTitle") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sketch-list-container flex">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in sketchList"
|
||||||
|
:key="index"
|
||||||
|
class="sketch-element flex flex-center"
|
||||||
|
>
|
||||||
|
<img class="img-src" :src="item.url || ''" alt="" />
|
||||||
|
<div
|
||||||
|
class="crop-tool flex flex-center"
|
||||||
|
@click="emit('crop', item.url, 'apparel', index)"
|
||||||
|
>
|
||||||
|
<SvgIcon name="CCrop" color="#fff" size="12" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { ListingItem } from "../types"
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
sketchList: ListingItem["sketchList"]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "crop", data: string | null, type: "apparel", index?: number): void
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.apparel-container {
|
||||||
|
margin-top: 3rem;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin-bottom: 0.8rem;
|
||||||
|
|
||||||
|
.main-title {
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: bold;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "*";
|
||||||
|
color: #df2b2c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sketch-list-container {
|
||||||
|
column-gap: 1rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.sketch-element {
|
||||||
|
width: 10rem;
|
||||||
|
height: 14.6rem;
|
||||||
|
border: 0.15rem solid #c7c7c7;
|
||||||
|
border-radius: 1.2rem;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.img-src {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crop-tool {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.4rem;
|
||||||
|
right: 0.4rem;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,222 @@
|
|||||||
|
<template>
|
||||||
|
<div class="form-container flex flex-col">
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="form-item-label required">
|
||||||
|
{{ $t("SellerListEdit.productName") }}
|
||||||
|
</div>
|
||||||
|
<div class="form-item-value product-name">
|
||||||
|
<a-input
|
||||||
|
:value="productName"
|
||||||
|
show-count
|
||||||
|
placeholder="Enter product name"
|
||||||
|
:bordered="false"
|
||||||
|
:maxlength="60"
|
||||||
|
@update:value="emit('update:productName', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="form-item-label required">{{ $t("SellerListEdit.price") }}</div>
|
||||||
|
<div class="form-item-value price flex align-center">
|
||||||
|
<span>HK$</span>
|
||||||
|
<a-input
|
||||||
|
:value="price"
|
||||||
|
placeholder="0.00"
|
||||||
|
:bordered="false"
|
||||||
|
@update:value="emit('update:price', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="form-item-label required">
|
||||||
|
{{ $t("SellerListEdit.productDescription") }}
|
||||||
|
</div>
|
||||||
|
<div class="form-item-value desc">
|
||||||
|
<a-textarea
|
||||||
|
:value="desc"
|
||||||
|
show-count
|
||||||
|
:rows="4"
|
||||||
|
placeholder="Enter product description"
|
||||||
|
:bordered="false"
|
||||||
|
:maxlength="500"
|
||||||
|
@update:value="emit('update:desc', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="form-item-label required">
|
||||||
|
{{ $t("SellerListEdit.designFor") }}
|
||||||
|
</div>
|
||||||
|
<div class="form-item-value no-border">
|
||||||
|
<Radio
|
||||||
|
:options="genderOptions"
|
||||||
|
:model-value="gender"
|
||||||
|
@update:model-value="emit('update:gender', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-item">
|
||||||
|
<div class="form-item-label with-tip">
|
||||||
|
<span class="required">{{ $t("SellerListEdit.productCategory") }}</span>
|
||||||
|
<span class="help-text">{{ $t("SellerListEdit.categoryTips") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="form-item-value no-border">
|
||||||
|
<Radio
|
||||||
|
multiple
|
||||||
|
:options="categoryOptions"
|
||||||
|
:model-value="category"
|
||||||
|
@update:model-value="emit('update:category', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="license-note flex align-center">
|
||||||
|
<img src="@/assets/images/seller/tips.png" class="info-icon" />
|
||||||
|
<div class="note-copy">
|
||||||
|
{{ $t("SellerListEdit.policy") }}
|
||||||
|
<a href="javascript:void(0)">{{ $t("SellerListEdit.learnMore") }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import Radio from "./Radio.vue"
|
||||||
|
import type { RadioOption } from "../types"
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
productName: string
|
||||||
|
price: string
|
||||||
|
desc: string
|
||||||
|
gender: string
|
||||||
|
category: string[] | null
|
||||||
|
genderOptions: RadioOption[]
|
||||||
|
categoryOptions: RadioOption[]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "update:productName", value: string): void
|
||||||
|
(e: "update:price", value: string): void
|
||||||
|
(e: "update:desc", value: string): void
|
||||||
|
(e: "update:gender", value: string): void
|
||||||
|
(e: "update:category", value: string[] | null): void
|
||||||
|
}>()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.required {
|
||||||
|
&::after {
|
||||||
|
content: "*";
|
||||||
|
color: #df2b2c;
|
||||||
|
margin-left: 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-container {
|
||||||
|
row-gap: 3rem;
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
.form-item-label {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: bold;
|
||||||
|
margin-bottom: 0.6rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
&.with-tip {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
column-gap: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-text {
|
||||||
|
font-size: 1rem;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-item-value {
|
||||||
|
border: 0.16rem solid #d1d1d1;
|
||||||
|
border-radius: 1.2rem;
|
||||||
|
position: relative;
|
||||||
|
padding: 1.6rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
&.no-border {
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.price {
|
||||||
|
column-gap: 0.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-input),
|
||||||
|
:deep(.ant-input-affix-wrapper),
|
||||||
|
:deep(.ant-input-textarea textarea) {
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #000;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-input) {
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-input-show-count-suffix) {
|
||||||
|
color: #df2c2c;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(textarea.ant-input) {
|
||||||
|
resize: none;
|
||||||
|
min-height: 5.4rem;
|
||||||
|
padding-bottom: 1.8rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-input-textarea-show-count) {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
float: none;
|
||||||
|
position: absolute;
|
||||||
|
color: #df2c2c;
|
||||||
|
bottom: 0;
|
||||||
|
right: 1.6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.license-note {
|
||||||
|
padding: 1.6rem;
|
||||||
|
column-gap: 1.6rem;
|
||||||
|
background: #f7f7f7;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
|
||||||
|
.info-icon {
|
||||||
|
width: 2.4rem;
|
||||||
|
height: 2.4rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-copy {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #000;
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: medium;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #0080ed;
|
||||||
|
text-decoration: underline;
|
||||||
|
margin-left: 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,238 @@
|
|||||||
|
<template>
|
||||||
|
<div class="product-image-list-container">
|
||||||
|
<div class="title flex align-center space-between">
|
||||||
|
<div class="title-left">
|
||||||
|
<span class="main-title">{{ $t("SellerListEdit.productImageMainTitle") }}</span>
|
||||||
|
<span class="sub-title">{{ $t("SellerListEdit.productImageSubTitle") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="title-right">{{ selectedCount }}/{{ imageList.length }} selected</div>
|
||||||
|
</div>
|
||||||
|
<div class="product-image-list flex">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in imageList"
|
||||||
|
:key="index"
|
||||||
|
class="product-image-item flex flex-center"
|
||||||
|
:class="{ selected: item.selected, video: item.isVideo }"
|
||||||
|
@click="emit('select', index)"
|
||||||
|
@mouseenter="handleMouseEnter(index, item)"
|
||||||
|
@mouseleave="handleMouseLeave(index, item)"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
v-if="item.selected"
|
||||||
|
src="@/assets/images/seller/checked.png"
|
||||||
|
class="checked"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<img class="img-src" :src="getDisplayUrl(item, index)" alt="" />
|
||||||
|
<div v-if="item.isVideo && durationMap[index]" class="video-duration">
|
||||||
|
{{ durationMap[index] }}
|
||||||
|
</div>
|
||||||
|
<div v-if="item.selected && index === firstSelectedIndex && !item.isVideo" class="main-pic">
|
||||||
|
main
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed, ref, watch } from "vue"
|
||||||
|
import type { ListingItem, ProductMediaItem } from "../types"
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
imageList: ListingItem["prodImageList"]
|
||||||
|
firstSelectedIndex: number | null
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "select", index: number): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const selectedCount = computed(() => props.imageList.filter((item) => item.selected).length)
|
||||||
|
const hoveredVideoIndex = ref<number | null>(null)
|
||||||
|
const durationMap = ref<Record<number, string>>({})
|
||||||
|
const videoSourceKey = computed(() =>
|
||||||
|
props.imageList
|
||||||
|
.map((item) => `${item.videoUrl || ""}::${item.url || ""}`)
|
||||||
|
.join("|")
|
||||||
|
)
|
||||||
|
|
||||||
|
const getDisplayUrl = (item: ProductMediaItem, index: number) => {
|
||||||
|
if (item.isVideo && hoveredVideoIndex.value === index && item.gifUrl) {
|
||||||
|
return item.gifUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.url
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseEnter = (index: number, item: ProductMediaItem) => {
|
||||||
|
if (!item.isVideo || !item.gifUrl) return
|
||||||
|
hoveredVideoIndex.value = index
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleMouseLeave = (index: number, item: ProductMediaItem) => {
|
||||||
|
if (!item.isVideo) return
|
||||||
|
if (hoveredVideoIndex.value === index) hoveredVideoIndex.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatVideoDuration = (duration: number) => {
|
||||||
|
if (!Number.isFinite(duration) || duration <= 0) return ""
|
||||||
|
|
||||||
|
const totalSeconds = Math.round(duration)
|
||||||
|
const minutes = Math.floor(totalSeconds / 60)
|
||||||
|
const seconds = totalSeconds % 60
|
||||||
|
|
||||||
|
return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadVideoDurations = () => {
|
||||||
|
durationMap.value = {}
|
||||||
|
props.imageList.forEach((item, index) => {
|
||||||
|
if (!item.isVideo || !item.videoUrl) return
|
||||||
|
|
||||||
|
const video = document.createElement("video")
|
||||||
|
video.preload = "metadata"
|
||||||
|
video.src = item.videoUrl
|
||||||
|
video.onloadedmetadata = () => {
|
||||||
|
durationMap.value = {
|
||||||
|
...durationMap.value,
|
||||||
|
[index]: formatVideoDuration(video.duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
video.onerror = () => {
|
||||||
|
video.src = ""
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
videoSourceKey,
|
||||||
|
() => {
|
||||||
|
hoveredVideoIndex.value = null
|
||||||
|
loadVideoDurations()
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.product-image-list-container {
|
||||||
|
margin-top: 3rem;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin-bottom: 1.2rem;
|
||||||
|
|
||||||
|
.main-title {
|
||||||
|
font-weight: 400;
|
||||||
|
font-style: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-right {
|
||||||
|
color: #585858;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-image-list {
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
column-gap: 0.8rem;
|
||||||
|
max-width: 80.2rem;
|
||||||
|
padding-bottom: 1.2rem;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
height: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background: #d9d9d9;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background: #000000;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.product-image-item {
|
||||||
|
width: 11.6rem;
|
||||||
|
height: 20.6rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
border: 0.15rem solid #c7c7c7;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
content: "";
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
opacity: 0.7;
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
border-color: #000;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.checked {
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
position: absolute;
|
||||||
|
top: 0.8rem;
|
||||||
|
right: 0.8rem;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-src {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-duration {
|
||||||
|
position: absolute;
|
||||||
|
right: 0.8rem;
|
||||||
|
bottom: 0.8rem;
|
||||||
|
z-index: 1;
|
||||||
|
padding: 0 0.8rem;
|
||||||
|
height: 2.4rem;
|
||||||
|
line-height: 2.4rem;
|
||||||
|
border-radius: 1.2rem;
|
||||||
|
background: rgba(0, 0, 0, 0.8);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-pic {
|
||||||
|
position: absolute;
|
||||||
|
height: 2.4rem;
|
||||||
|
line-height: 2.4rem;
|
||||||
|
left: 0.8rem;
|
||||||
|
right: 0.8rem;
|
||||||
|
bottom: 0.8rem;
|
||||||
|
z-index: 1;
|
||||||
|
background: rgba(0, 0, 0, 0.8);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
border-radius: 1.2rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<div class="radio-button-group">
|
||||||
|
<button
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.key"
|
||||||
|
type="button"
|
||||||
|
:class="[
|
||||||
|
'radio-button',
|
||||||
|
{
|
||||||
|
'is-active': multiple
|
||||||
|
? selectedValues.includes(normalizeValue(item.key))
|
||||||
|
: modelValue === item.key
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
@click="selectOption(item.key)"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from "vue"
|
||||||
|
|
||||||
|
interface Option {
|
||||||
|
name: string | number
|
||||||
|
value: string | number | boolean
|
||||||
|
key: string
|
||||||
|
optype: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue:
|
||||||
|
| string
|
||||||
|
| number
|
||||||
|
| boolean
|
||||||
|
| Array<string | number | boolean | null | undefined>
|
||||||
|
| null
|
||||||
|
options: Option[] // 按钮选项数组
|
||||||
|
multiple?: boolean // 是否支持多选,默认为 false
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "update:modelValue", value: any): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const multiple = props.multiple === true
|
||||||
|
|
||||||
|
const normalizeValue = (value: any) =>
|
||||||
|
typeof value === "string" ? value.toLocaleLowerCase() : value
|
||||||
|
|
||||||
|
const selectedValues = computed(() => {
|
||||||
|
if (!multiple) {
|
||||||
|
return typeof props.modelValue === "undefined" || props.modelValue === null
|
||||||
|
? []
|
||||||
|
: [props.modelValue]
|
||||||
|
}
|
||||||
|
|
||||||
|
return Array.isArray(props.modelValue)
|
||||||
|
? props.modelValue
|
||||||
|
.filter((value) => value !== null && typeof value !== "undefined")
|
||||||
|
.map(normalizeValue)
|
||||||
|
: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const selectOption = (value: any) => {
|
||||||
|
if (multiple) {
|
||||||
|
const selectedValue = normalizeValue(value)
|
||||||
|
const current = Array.isArray(props.modelValue)
|
||||||
|
? props.modelValue
|
||||||
|
.filter((item) => item !== null && typeof item !== "undefined")
|
||||||
|
.map(normalizeValue)
|
||||||
|
: []
|
||||||
|
const index = current.indexOf(selectedValue)
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
current.splice(index, 1)
|
||||||
|
} else {
|
||||||
|
current.push(selectedValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
emit("update:modelValue", current.length ? current : null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.modelValue !== value) {
|
||||||
|
emit("update:modelValue", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.radio-button-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-button {
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
height: 3.2rem;
|
||||||
|
min-width: 8rem;
|
||||||
|
padding: 0 1.7rem;
|
||||||
|
color: #000;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 2rem;
|
||||||
|
outline: none;
|
||||||
|
background-color: #fff;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-button:hover {
|
||||||
|
border-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.radio-button.is-active {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #000;
|
||||||
|
border-color: #000;
|
||||||
|
font-family: pingfang_medium;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
<template>
|
||||||
|
<div class="main-image-container flex">
|
||||||
|
<div
|
||||||
|
v-for="type in topImageList"
|
||||||
|
:key="type"
|
||||||
|
:class="`main-image-item flex flex-col align-center ${type}`"
|
||||||
|
>
|
||||||
|
<div class="title" :class="{ required: type !== 'mainProductImage' }">
|
||||||
|
{{ $t(topImageTitleMap[type]) }}
|
||||||
|
</div>
|
||||||
|
<div class="sketch-item flex flex-center" :class="type">
|
||||||
|
<div
|
||||||
|
v-if="images[type]"
|
||||||
|
class="crop-tool flex flex-center"
|
||||||
|
@click="emit('crop', images[type], type)"
|
||||||
|
>
|
||||||
|
<SvgIcon name="CCrop" color="#fff" size="12" />
|
||||||
|
</div>
|
||||||
|
<img
|
||||||
|
v-if="images[type]"
|
||||||
|
:src="images[type] || ''"
|
||||||
|
class="sketch-img"
|
||||||
|
:class="type"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
<div v-else class="trigger flex flex-col align-center">
|
||||||
|
<div
|
||||||
|
v-if="type === 'cover'"
|
||||||
|
class="cover-trigger flex flex-col align-center"
|
||||||
|
@click="emit('crop', null, 'cover')"
|
||||||
|
>
|
||||||
|
<SvgIcon class="trigger-icon" name="CCrop" color="#585858" size="24" />
|
||||||
|
<div class="trigger-tips">
|
||||||
|
{{ $t("SellerListEdit.cropDesc") }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template v-else>
|
||||||
|
<div class="trigger-img placeholder"></div>
|
||||||
|
<div class="trigger-tips">
|
||||||
|
{{ $t("SellerListEdit.productImageDesc") }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { TopImageType } from "../types"
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
images: Record<TopImageType, string | null>
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: "crop", data: string | null, type: TopImageType): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const topImageList: TopImageType[] = ["sketch", "mainProductImage", "cover"]
|
||||||
|
const topImageTitleMap: Record<TopImageType, string> = {
|
||||||
|
sketch: "SellerListEdit.sketch",
|
||||||
|
mainProductImage: "SellerListEdit.mainProductImage",
|
||||||
|
cover: "SellerListEdit.cover"
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.c-svg {
|
||||||
|
width: initial;
|
||||||
|
height: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.required {
|
||||||
|
&::after {
|
||||||
|
content: "*";
|
||||||
|
color: #df2b2c;
|
||||||
|
margin-left: 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-image-container {
|
||||||
|
column-gap: 3.5rem;
|
||||||
|
|
||||||
|
.main-image-item {
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin-bottom: 0.8rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sketch-item {
|
||||||
|
width: 11.6rem;
|
||||||
|
height: 20.4rem;
|
||||||
|
border: 0.15rem solid #d1d1d1;
|
||||||
|
border-radius: 1rem;
|
||||||
|
position: relative;
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&.cover {
|
||||||
|
width: 16.2rem;
|
||||||
|
background-image: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' rx='11' ry='11' fill='none' stroke='%23D1D1D1' stroke-width='1.5' stroke-dasharray='8%2c 5' stroke-linecap='square'/%3e%3c/svg%3e");
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crop-tool {
|
||||||
|
position: absolute;
|
||||||
|
top: 0.8rem;
|
||||||
|
right: 0.8rem;
|
||||||
|
width: 2rem;
|
||||||
|
height: 2rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #000000;
|
||||||
|
z-index: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sketch-img {
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
height: 100%;
|
||||||
|
&.sketch {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger {
|
||||||
|
cursor: pointer;
|
||||||
|
height: 100%;
|
||||||
|
padding: 6rem 2rem 0;
|
||||||
|
|
||||||
|
&,
|
||||||
|
.cover-trigger {
|
||||||
|
row-gap: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
width: 2.4rem;
|
||||||
|
height: 2.4rem;
|
||||||
|
border-radius: 0.6rem;
|
||||||
|
background: linear-gradient(135deg, #efefef 0%, #cdcdcd 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger-tips {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
text-align: center;
|
||||||
|
color: #585858;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,88 +1,741 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="edit-detail-wrapper">
|
<div class="edit-detail-wrapper flex-1">
|
||||||
<seller-header
|
<seller-header class="edit-detail-header">
|
||||||
title="Edit Listing Details"
|
|
||||||
:breadcrumbs="[
|
|
||||||
{ title: 'My Listings', name: 'myListingsIndex' },
|
|
||||||
{ title: 'Select Collection', name: 'myListingsSelect' },
|
|
||||||
{ title: 'Select Sketch', name: 'myListingsSelectItem' },
|
|
||||||
{ title: 'Edit Listing Details', name: 'EditDetail' }
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<template #right>
|
<template #right>
|
||||||
<div class="operate-menu flex">
|
<div class="operate-menu flex">
|
||||||
<div class="menu-btn flex align-center save">
|
<div class="menu-btn flex align-center save" @click="handleClickMenu('draft')">
|
||||||
<span>Save Draft</span>
|
<span>{{ $t("SellerListEdit.saveDraft") }}</span>
|
||||||
<SvgIcon name="CSave" color="#000000" size="16" />
|
<SvgIcon name="CSave" size="16" />
|
||||||
</div>
|
</div>
|
||||||
<div class="menu-btn flex align-center publish">
|
<div
|
||||||
<span>Publish</span>
|
class="menu-btn flex align-center publish"
|
||||||
<SvgIcon name="CPublish" color="#ffffff" size="16" />
|
@click="handleClickMenu('publish')"
|
||||||
|
>
|
||||||
|
<span>{{ $t("SellerListEdit.publish") }}</span>
|
||||||
|
<SvgIcon name="CPublish" size="16" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</seller-header>
|
</seller-header>
|
||||||
<div class="edit-detail-content flex space-between">
|
<div class="edit-detail-content flex">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="main-image-container flex">
|
<TopImageSection :images="previewImageMap" @crop="handleClickCrop" />
|
||||||
<div class="sketch"></div>
|
<ProductImageList
|
||||||
|
:image-list="prodImgList"
|
||||||
|
:first-selected-index="currentListing.firstSelectedIndex"
|
||||||
|
@select="handleSelectProdImg"
|
||||||
|
/>
|
||||||
|
<ApparelSketchList
|
||||||
|
:sketch-list="currentListing.sketchList"
|
||||||
|
@crop="handleClickCrop"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<ListingForm
|
||||||
|
:product-name="currentListing.productName"
|
||||||
|
:price="currentListing.price"
|
||||||
|
:desc="currentListing.desc"
|
||||||
|
:gender="currentListing.gender"
|
||||||
|
:category="currentListing.category"
|
||||||
|
:gender-options="genderOptions"
|
||||||
|
:category-options="categoryOptions"
|
||||||
|
@update:product-name="currentListing.productName = $event"
|
||||||
|
@update:price="currentListing.price = $event"
|
||||||
|
@update:desc="currentListing.desc = $event"
|
||||||
|
@update:gender="handleUpdateGender"
|
||||||
|
@update:category="currentListing.category = $event"
|
||||||
|
/>
|
||||||
|
<div class="page-control flex align-center" v-if="selectList.length > 1">
|
||||||
|
<a-pagination
|
||||||
|
v-model:current="currentPage"
|
||||||
|
:total="selectList.length"
|
||||||
|
:page-size="1"
|
||||||
|
showQuickJumper
|
||||||
|
showLessItems
|
||||||
|
responsive
|
||||||
|
:showSizeChanger="false"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ImageClipDialog
|
||||||
|
ref="imageClipDialogRef"
|
||||||
|
fixedBox
|
||||||
|
isProduct
|
||||||
|
:info="false"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:type="cropType"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from "vue"
|
import { computed, ref, onMounted } from "vue"
|
||||||
import SellerHeader from "../../seller-header.vue"
|
import { useRouter } from "vue-router"
|
||||||
|
import { useI18n } from "vue-i18n"
|
||||||
|
import { message } from "ant-design-vue"
|
||||||
|
import SellerHeader from "../../seller-header.vue"
|
||||||
|
import ImageClipDialog from "../../BrandProfile/image-clip-dialog.vue"
|
||||||
|
import ApparelSketchList from "./components/ApparelSketchList.vue"
|
||||||
|
import ListingForm from "./components/ListingForm.vue"
|
||||||
|
import ProductImageList from "./components/ProductImageList.vue"
|
||||||
|
import TopImageSection from "./components/TopImageSection.vue"
|
||||||
|
import { useStore } from "vuex"
|
||||||
|
import {
|
||||||
|
fetchSketchDetail,
|
||||||
|
uploadFile,
|
||||||
|
fetchListingDetailById,
|
||||||
|
fetchUpdateListing
|
||||||
|
} from "./api"
|
||||||
|
import type {
|
||||||
|
CoverSourceType,
|
||||||
|
CropType,
|
||||||
|
ListingDetailImage,
|
||||||
|
ListingDetailResponse,
|
||||||
|
ListingImageCategory,
|
||||||
|
ListingItem,
|
||||||
|
ProductMediaItem,
|
||||||
|
RadioOption,
|
||||||
|
SketchDetailResponse,
|
||||||
|
SketchDetailVideo,
|
||||||
|
StatusType
|
||||||
|
} from "./types"
|
||||||
|
|
||||||
const currentIndex = ref(0)
|
const ROUTER = useRouter()
|
||||||
const selectList = ref([
|
const { t } = useI18n()
|
||||||
{
|
|
||||||
sketch: "",
|
const imageClipDialogRef = ref<InstanceType<typeof ImageClipDialog> | null>(null)
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: "EditDetail"
|
||||||
|
})
|
||||||
|
|
||||||
|
const STORE = useStore()
|
||||||
|
|
||||||
|
const createListingItem = (
|
||||||
|
sketch: string | null = null,
|
||||||
|
designItemId: number | string | null = null
|
||||||
|
): ListingItem => ({
|
||||||
|
designItemId,
|
||||||
|
sketch,
|
||||||
mainProductImage: "",
|
mainProductImage: "",
|
||||||
cover: "",
|
cover: "",
|
||||||
productImage: [],
|
productImage: [],
|
||||||
apparelSketch: [],
|
apparelSketch: [],
|
||||||
productName: "",
|
productName: "",
|
||||||
price: "",
|
price: "",
|
||||||
desc: '',
|
desc: "",
|
||||||
gender: '',
|
gender: "FEMALE",
|
||||||
category:''
|
category: null,
|
||||||
|
coverFrom: "sketch",
|
||||||
|
firstSelectedIndex: null,
|
||||||
|
prodImageList: [],
|
||||||
|
sketchList: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const genderOptions = computed(() => {
|
||||||
|
return STORE.state.UserHabit?.sex.value
|
||||||
|
})
|
||||||
|
|
||||||
|
const fallbackCategoryOptions: Record<string, RadioOption[]> = {
|
||||||
|
MALE: STORE.state.UserHabit?.MalePosition || [],
|
||||||
|
FEMALE: STORE.state.UserHabit?.FemalePosition || []
|
||||||
}
|
}
|
||||||
])
|
|
||||||
|
const currentPage = ref(1)
|
||||||
|
const currentIndex = computed(() => currentPage.value - 1)
|
||||||
|
|
||||||
|
const itemId = ref("")
|
||||||
|
const selectList = ref<ListingItem[]>([createListingItem()])
|
||||||
|
|
||||||
|
const prodImgList = computed(() => currentListing.value.prodImageList || [])
|
||||||
|
|
||||||
|
const categoryOptions = computed(() => {
|
||||||
|
const gender = selectList.value[currentIndex.value].gender
|
||||||
|
return fallbackCategoryOptions[gender] || []
|
||||||
|
})
|
||||||
|
|
||||||
|
const currentListing = computed(() => selectList.value[currentIndex.value])
|
||||||
|
|
||||||
|
const handleUpdateGender = (gender: string) => {
|
||||||
|
if (currentListing.value.gender === gender) return
|
||||||
|
|
||||||
|
currentListing.value.gender = gender
|
||||||
|
currentListing.value.category = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const previewImageMap = computed(() => ({
|
||||||
|
sketch: currentListing.value.sketch,
|
||||||
|
mainProductImage: currentListing.value.mainProductImage,
|
||||||
|
cover: currentListing.value.cover
|
||||||
|
}))
|
||||||
|
|
||||||
|
const getSortedDetailImages = (images: ListingDetailImage[] = []) => {
|
||||||
|
return [...images].sort((prev, next) => (prev.sortOrder ?? 0) - (next.sortOrder ?? 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
const getImageSelected = (value: ListingDetailImage["isSelected"]) => {
|
||||||
|
if (value === true || value === 1 || value === "1") return true
|
||||||
|
if (typeof value === "string") return value.toLowerCase() === "true"
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDetailImageSelected = (image: ListingDetailImage) =>
|
||||||
|
getImageSelected(image.isSelected) ||
|
||||||
|
getImageSelected(image.isSeleted) ||
|
||||||
|
getImageSelected(image.selected)
|
||||||
|
|
||||||
|
const normalizeCoverSource = (value: unknown): CoverSourceType =>
|
||||||
|
value === "mainProductImage" ? "mainProductImage" : "sketch"
|
||||||
|
|
||||||
|
const isCoverSource = (value: unknown): value is CoverSourceType =>
|
||||||
|
value === "sketch" || value === "mainProductImage"
|
||||||
|
|
||||||
|
const resolveCoverSourceFromImageUrl = (
|
||||||
|
imageUrl: string,
|
||||||
|
listing: ListingItem
|
||||||
|
): CoverSourceType => {
|
||||||
|
if (imageUrl === listing.mainProductImage) return "mainProductImage"
|
||||||
|
if (imageUrl === listing.sketch) return "sketch"
|
||||||
|
|
||||||
|
return normalizeCoverSource(imageUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
const videoImageCategories = ["firstFrame", "gif", "video"] as const
|
||||||
|
type VideoImageCategory = (typeof videoImageCategories)[number]
|
||||||
|
|
||||||
|
const isVideoImageCategory = (
|
||||||
|
category: ListingDetailImage["category"]
|
||||||
|
): category is VideoImageCategory =>
|
||||||
|
videoImageCategories.includes(category as VideoImageCategory)
|
||||||
|
|
||||||
|
const normalizeDetailGender = (value: ListingDetailResponse["designFor"]) => {
|
||||||
|
const gender = String(value || "").toUpperCase()
|
||||||
|
return gender === "MALE" || gender === "FEMALE" ? gender : "FEMALE"
|
||||||
|
}
|
||||||
|
|
||||||
|
const getListingDesignFor = (gender: ListingItem["gender"]): "male" | "female" =>
|
||||||
|
gender === "MALE" ? "male" : "female"
|
||||||
|
|
||||||
|
const normalizeDetailCategory = (
|
||||||
|
value: ListingDetailResponse["productCategory"]
|
||||||
|
): ListingItem["category"] => {
|
||||||
|
const categories = Array.isArray(value) ? value : value ? [value] : []
|
||||||
|
const normalized = categories
|
||||||
|
.filter((category) => category !== null && typeof category !== "undefined")
|
||||||
|
.map((category) => String(category).toLowerCase())
|
||||||
|
|
||||||
|
return normalized.length ? normalized : null
|
||||||
|
}
|
||||||
|
|
||||||
|
const createListingItemFromDetail = (detail: ListingDetailResponse): ListingItem => {
|
||||||
|
const listing = createListingItem()
|
||||||
|
let coverFromImageUrl = ""
|
||||||
|
const videoGroupMap = new Map<
|
||||||
|
number,
|
||||||
|
{
|
||||||
|
sortOrder: number
|
||||||
|
firstFrameUrl?: string
|
||||||
|
gifUrl?: string
|
||||||
|
videoUrl?: string
|
||||||
|
selected: boolean
|
||||||
|
}
|
||||||
|
>()
|
||||||
|
|
||||||
|
listing.productName = detail.title || ""
|
||||||
|
listing.price =
|
||||||
|
detail.price === null || typeof detail.price === "undefined" ? "" : String(detail.price)
|
||||||
|
listing.desc = detail.description || ""
|
||||||
|
listing.gender = normalizeDetailGender(detail.designFor)
|
||||||
|
listing.category = normalizeDetailCategory(detail.productCategory)
|
||||||
|
|
||||||
|
getSortedDetailImages(detail.images || []).forEach((image) => {
|
||||||
|
if (image.category === "cover_from") {
|
||||||
|
coverFromImageUrl = image.imageUrl || ""
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const imageUrl = image.imageUrl || ""
|
||||||
|
if (!imageUrl) return
|
||||||
|
|
||||||
|
if (image.category === "cover") {
|
||||||
|
listing.cover = imageUrl
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.category === "sketch") {
|
||||||
|
listing.sketch = imageUrl
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.category === "mainProductImage" || image.category === "main_product") {
|
||||||
|
listing.mainProductImage = imageUrl
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.category === "product") {
|
||||||
|
listing.prodImageList.push({
|
||||||
|
url: imageUrl,
|
||||||
|
selected: getDetailImageSelected(image)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isVideoImageCategory(image.category)) {
|
||||||
|
if (image.sortOrder === null || typeof image.sortOrder === "undefined") return
|
||||||
|
|
||||||
|
const sortOrder = Number(image.sortOrder)
|
||||||
|
if (!Number.isFinite(sortOrder)) return
|
||||||
|
|
||||||
|
const group = videoGroupMap.get(sortOrder) || {
|
||||||
|
sortOrder,
|
||||||
|
selected: false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.category === "firstFrame") group.firstFrameUrl = imageUrl
|
||||||
|
if (image.category === "gif") group.gifUrl = imageUrl
|
||||||
|
if (image.category === "video") group.videoUrl = imageUrl
|
||||||
|
group.selected = group.selected || getDetailImageSelected(image)
|
||||||
|
videoGroupMap.set(sortOrder, group)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image.category === "apparel") {
|
||||||
|
listing.sketchList.push({ url: imageUrl })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
Array.from(videoGroupMap.values())
|
||||||
|
.sort((prev, next) => prev.sortOrder - next.sortOrder)
|
||||||
|
.forEach((video) => {
|
||||||
|
const videoItem = createProductVideoItem(video, video.selected)
|
||||||
|
if (videoItem) listing.prodImageList.push(videoItem)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (coverFromImageUrl) {
|
||||||
|
listing.coverFrom = resolveCoverSourceFromImageUrl(coverFromImageUrl, listing)
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainProductIndex = listing.prodImageList.findIndex(
|
||||||
|
(item) => !item.isVideo && item.url === listing.mainProductImage
|
||||||
|
)
|
||||||
|
listing.firstSelectedIndex = mainProductIndex === -1 ? null : mainProductIndex
|
||||||
|
|
||||||
|
listing.productImage = listing.prodImageList.map((item) => item.url)
|
||||||
|
listing.apparelSketch = listing.sketchList
|
||||||
|
.map((item) => item.url)
|
||||||
|
.filter((url): url is string => Boolean(url))
|
||||||
|
|
||||||
|
return listing
|
||||||
|
}
|
||||||
|
|
||||||
|
const createProductVideoItem = (
|
||||||
|
video: SketchDetailVideo,
|
||||||
|
selected = false
|
||||||
|
): ProductMediaItem | null => {
|
||||||
|
const firstFrameUrl = video?.firstFrameUrl || ""
|
||||||
|
const gifUrl = video?.gifUrl || ""
|
||||||
|
const videoUrl = video?.videoUrl || ""
|
||||||
|
|
||||||
|
if (!firstFrameUrl || !videoUrl) return null
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: firstFrameUrl,
|
||||||
|
firstFrameUrl,
|
||||||
|
gifUrl,
|
||||||
|
videoUrl,
|
||||||
|
isVideo: true,
|
||||||
|
selected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSelectProdImg = (index: number) => {
|
||||||
|
const listing = currentListing.value
|
||||||
|
const target = prodImgList.value[index]
|
||||||
|
const willSelect = !target.selected
|
||||||
|
|
||||||
|
target.selected = willSelect
|
||||||
|
|
||||||
|
if (willSelect && listing.firstSelectedIndex === null) {
|
||||||
|
if (target.isVideo) {
|
||||||
|
message.warning(t("Seller.VideoWarning"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
listing.mainProductImage = target.url
|
||||||
|
listing.firstSelectedIndex = index
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!willSelect && listing.mainProductImage === target.url) {
|
||||||
|
listing.firstSelectedIndex = null
|
||||||
|
listing.mainProductImage = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getCoverOriginList = (item: ListingItem) => {
|
||||||
|
const origin: Array<{ type: CoverSourceType; url: string }> = []
|
||||||
|
if (item.sketch) {
|
||||||
|
origin.push({ type: "sketch", url: item.sketch })
|
||||||
|
}
|
||||||
|
if (item.mainProductImage) {
|
||||||
|
origin.push({ type: "mainProductImage", url: item.mainProductImage })
|
||||||
|
}
|
||||||
|
|
||||||
|
return origin
|
||||||
|
}
|
||||||
|
|
||||||
|
const cropType = ref<CropType | "">("")
|
||||||
|
const handleClickCrop = (
|
||||||
|
data: string | null,
|
||||||
|
type: CropType,
|
||||||
|
paramThree: number | unknown[] = []
|
||||||
|
) => {
|
||||||
|
// 处理来自TopImageSection的调用: (data, type, list)
|
||||||
|
// 处理来自ApparelSketchList的调用: (data, type, index)
|
||||||
|
const index = typeof paramThree === "number" ? paramThree : undefined
|
||||||
|
|
||||||
|
// console.log(data, type)
|
||||||
|
// console.log(selectList.value[currentIndex.value])
|
||||||
|
const currentItem = selectList.value[currentIndex.value]
|
||||||
|
const origin = type === "cover" ? getCoverOriginList(currentItem) : []
|
||||||
|
const titleList: Record<CropType, string> = {
|
||||||
|
sketch: "Crop Sketch",
|
||||||
|
mainProductImage: "Crop Main Product Image",
|
||||||
|
cover: "Crop Cover",
|
||||||
|
apparel: "Crop Apparel Sketch"
|
||||||
|
}
|
||||||
|
const ratio = type === "cover" ? [4, 5] : [9, 16]
|
||||||
|
cropType.value = type
|
||||||
|
imageClipDialogRef.value.open(
|
||||||
|
data,
|
||||||
|
(file: File, coverFrom?: CoverSourceType) => {
|
||||||
|
// console.log(file)
|
||||||
|
uploadFile(file).then((res) => {
|
||||||
|
if (type === "apparel" && typeof index !== "undefined") {
|
||||||
|
selectList.value[currentIndex.value].sketchList[index].url = res
|
||||||
|
} else if (type === "cover") {
|
||||||
|
selectList.value[currentIndex.value].cover = res
|
||||||
|
if (isCoverSource(coverFrom)) {
|
||||||
|
selectList.value[currentIndex.value].coverFrom = coverFrom
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selectList.value[currentIndex.value][type] = res
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ratio,
|
||||||
|
isPreview: true,
|
||||||
|
title: titleList[type],
|
||||||
|
isProduct: true,
|
||||||
|
coverFrom: currentItem.coverFrom
|
||||||
|
},
|
||||||
|
origin
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasValue = (value: unknown) =>
|
||||||
|
value !== null && value !== undefined && String(value).trim() !== ""
|
||||||
|
|
||||||
|
const getMissingRequiredField = (item: ListingItem) => {
|
||||||
|
const requiredFields = [
|
||||||
|
{ value: item.sketch, label: t("SellerListEdit.sketch") },
|
||||||
|
{ value: item.cover, label: t("SellerListEdit.cover") },
|
||||||
|
{ value: item.productName, label: t("SellerListEdit.productName") },
|
||||||
|
{ value: item.price, label: t("SellerListEdit.price") },
|
||||||
|
{ value: item.desc, label: t("SellerListEdit.productDescription") },
|
||||||
|
{ value: item.gender, label: t("SellerListEdit.designFor") },
|
||||||
|
{ value: item.category, label: t("SellerListEdit.productCategory") }
|
||||||
|
]
|
||||||
|
const missingField = requiredFields.find((field) => !hasValue(field.value))
|
||||||
|
if (missingField) return missingField.label
|
||||||
|
|
||||||
|
const missingSketchIndex = item.sketchList.findIndex((sketch) => !hasValue(sketch.url))
|
||||||
|
if (item.sketchList.length === 0 || missingSketchIndex !== -1) {
|
||||||
|
return `${t("SellerListEdit.apparelSketchTitle").trim()} ${
|
||||||
|
missingSketchIndex === -1 ? 1 : missingSketchIndex + 1
|
||||||
|
}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
const validatePublishRequired = () => {
|
||||||
|
for (let index = 0; index < selectList.value.length; index += 1) {
|
||||||
|
const field = getMissingRequiredField(selectList.value[index])
|
||||||
|
if (!field) continue
|
||||||
|
|
||||||
|
currentPage.value = index + 1
|
||||||
|
message.warning(
|
||||||
|
t(
|
||||||
|
selectList.value.length > 1
|
||||||
|
? "SellerListEdit.requiredFieldTipsWithPage"
|
||||||
|
: "SellerListEdit.requiredFieldTips",
|
||||||
|
{ index: index + 1, field }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type SaveListingImage = {
|
||||||
|
category: ListingImageCategory
|
||||||
|
imageUrl: string | null
|
||||||
|
isSelected: number
|
||||||
|
sortOrder: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const isMainProductMedia = (item: ListingItem, media: ProductMediaItem, index: number) =>
|
||||||
|
!media.isVideo &&
|
||||||
|
(item.firstSelectedIndex === index ||
|
||||||
|
(Boolean(item.mainProductImage) && item.mainProductImage === media.url))
|
||||||
|
|
||||||
|
const getSortedProductMedia = (item: ListingItem) => {
|
||||||
|
return item.prodImageList
|
||||||
|
.map((media, index) => ({ media, index }))
|
||||||
|
.filter(({ media }) => !media.isVideo)
|
||||||
|
.sort((prev, next) => {
|
||||||
|
const prevRank = isMainProductMedia(item, prev.media, prev.index)
|
||||||
|
? 0
|
||||||
|
: prev.media.selected
|
||||||
|
? 1
|
||||||
|
: 2
|
||||||
|
const nextRank = isMainProductMedia(item, next.media, next.index)
|
||||||
|
? 0
|
||||||
|
: next.media.selected
|
||||||
|
? 1
|
||||||
|
: 2
|
||||||
|
|
||||||
|
return prevRank - nextRank || prev.index - next.index
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildListingImages = (item: ListingItem) => {
|
||||||
|
const images: SaveListingImage[] = []
|
||||||
|
const sortOrderMap: Partial<Record<ListingImageCategory, number>> = {}
|
||||||
|
const getNextSortOrder = (category: ListingImageCategory) => {
|
||||||
|
const sortOrder = (sortOrderMap[category] || 0) + 1
|
||||||
|
sortOrderMap[category] = sortOrder
|
||||||
|
return sortOrder
|
||||||
|
}
|
||||||
|
const pushImage = (
|
||||||
|
category: ListingImageCategory,
|
||||||
|
imageUrl: string | null,
|
||||||
|
isSelected = 1,
|
||||||
|
sortOrder = getNextSortOrder(category)
|
||||||
|
) => {
|
||||||
|
images.push({
|
||||||
|
category,
|
||||||
|
imageUrl,
|
||||||
|
isSelected,
|
||||||
|
sortOrder
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const getCoverFromImageUrl = () => {
|
||||||
|
if (item.coverFrom === "mainProductImage") return item.mainProductImage || null
|
||||||
|
return item.sketch
|
||||||
|
}
|
||||||
|
|
||||||
|
pushImage("sketch", item.sketch)
|
||||||
|
pushImage("cover", item.cover)
|
||||||
|
pushImage("cover_from", getCoverFromImageUrl())
|
||||||
|
|
||||||
|
if (item.mainProductImage) {
|
||||||
|
pushImage("main_product", item.mainProductImage)
|
||||||
|
}
|
||||||
|
|
||||||
|
getSortedProductMedia(item).forEach(({ media }) => {
|
||||||
|
pushImage("product", media.url, Number(!!media.selected))
|
||||||
|
})
|
||||||
|
|
||||||
|
item.sketchList.forEach((sketch) => {
|
||||||
|
pushImage("apparel", sketch.url)
|
||||||
|
})
|
||||||
|
|
||||||
|
let videoSortOrder = 0
|
||||||
|
item.prodImageList
|
||||||
|
.filter((media) => media.isVideo)
|
||||||
|
.forEach((media) => {
|
||||||
|
videoSortOrder += 1
|
||||||
|
const isSelected = Number(!!media.selected)
|
||||||
|
|
||||||
|
pushImage(
|
||||||
|
"firstFrame",
|
||||||
|
media.firstFrameUrl || media.url,
|
||||||
|
isSelected,
|
||||||
|
videoSortOrder
|
||||||
|
)
|
||||||
|
pushImage("gif", media.gifUrl || "", isSelected, videoSortOrder)
|
||||||
|
pushImage("video", media.videoUrl || "", isSelected, videoSortOrder)
|
||||||
|
})
|
||||||
|
|
||||||
|
return images
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSaveForm = async (type: StatusType) => {
|
||||||
|
const paramsList = selectList.value.map((item: ListingItem) => {
|
||||||
|
return {
|
||||||
|
id: itemId.value,
|
||||||
|
title: item.productName,
|
||||||
|
description: item.desc,
|
||||||
|
price: item.price,
|
||||||
|
status: type === "draft" ? 0 : 1,
|
||||||
|
images: buildListingImages(item),
|
||||||
|
designFor: getListingDesignFor(item.gender),
|
||||||
|
productCategory: item.category
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await fetchUpdateListing(paramsList)
|
||||||
|
}
|
||||||
|
const handleClickMenu = async (status: StatusType) => {
|
||||||
|
if (!validatePublishRequired()) return
|
||||||
|
|
||||||
|
await handleSaveForm(status)
|
||||||
|
if (status === "draft") {
|
||||||
|
ROUTER.push({
|
||||||
|
name: "Status",
|
||||||
|
params: { status: "draft" },
|
||||||
|
state: {
|
||||||
|
type: history.state?.type,
|
||||||
|
collectionId: history.state?.collectionId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (status === "publish") {
|
||||||
|
ROUTER.push({
|
||||||
|
name: "Status",
|
||||||
|
params: { status: "publish" },
|
||||||
|
state: {
|
||||||
|
type: history.state?.type,
|
||||||
|
collectionId: history.state?.collectionId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleFetchItemDetial = (list) => {
|
||||||
|
fetchSketchDetail(list).then((res: SketchDetailResponse[]) => {
|
||||||
|
res.forEach((item, index) => {
|
||||||
|
if (!selectList.value[index]) return
|
||||||
|
selectList.value[index].sketchList = (item.clothes || []).map((el) => ({ url: el }))
|
||||||
|
const imageItems = (item.toProductImageUrls || []).map((el) => ({
|
||||||
|
url: el,
|
||||||
|
selected: false
|
||||||
|
}))
|
||||||
|
const videoItems = (item.videos || [])
|
||||||
|
.map((video) => createProductVideoItem(video))
|
||||||
|
.filter((video): video is ProductMediaItem => Boolean(video))
|
||||||
|
selectList.value[index].prodImageList = [...imageItems, ...videoItems]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleGetDetailById = () => {
|
||||||
|
fetchListingDetailById(itemId.value).then((res: ListingDetailResponse) => {
|
||||||
|
const listing = createListingItemFromDetail(res)
|
||||||
|
|
||||||
|
currentPage.value = 1
|
||||||
|
selectList.value = [listing]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const data = history.state
|
||||||
|
if (data?.type === "edit") {
|
||||||
|
itemId.value = history.state?.id
|
||||||
|
handleGetDetailById()
|
||||||
|
} else {
|
||||||
|
const designItemIds = history.state?.designItemIds || []
|
||||||
|
|
||||||
|
if (!designItemIds.length) return
|
||||||
|
|
||||||
|
currentPage.value = 1
|
||||||
|
selectList.value = designItemIds.map((item) =>
|
||||||
|
createListingItem(item.designOutfitUrl, item.designItemId)
|
||||||
|
)
|
||||||
|
const list = designItemIds.map((el) => el.designItemId)
|
||||||
|
// console.log("list", list.length, list)
|
||||||
|
handleFetchItemDetial(list)
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.c-svg {
|
.c-svg {
|
||||||
width: initial;
|
width: initial;
|
||||||
}
|
height: initial;
|
||||||
|
|
||||||
.edit-detail-wrapper {
|
|
||||||
.menu-btn {
|
|
||||||
height: 6rem;
|
|
||||||
border: 0.15rem solid #000000;
|
|
||||||
border-radius: 4rem;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 6rem;
|
|
||||||
padding: 0 2rem;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 1.6rem;
|
|
||||||
column-gap: 0.8rem;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.operate-menu {
|
.edit-detail-wrapper {
|
||||||
column-gap: 2rem;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
margin-top: -1rem;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
.publish {
|
&::-webkit-scrollbar {
|
||||||
background-color: #000000;
|
display: none;
|
||||||
color: #ffffff;
|
}
|
||||||
|
|
||||||
|
.menu-btn {
|
||||||
|
height: 6rem;
|
||||||
|
border: 0.15rem solid #000000;
|
||||||
|
border-radius: 4rem;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 6rem;
|
||||||
|
padding: 0 2rem;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
column-gap: 0.8rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.25s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #000;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// &.publish:hover {
|
||||||
|
// background: #fff;
|
||||||
|
// color: #000;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-detail-header {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operate-menu {
|
||||||
|
column-gap: 2rem;
|
||||||
|
|
||||||
|
// .publish {
|
||||||
|
// background-color: #000000;
|
||||||
|
// color: #ffffff;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-detail-content {
|
.edit-detail-content {
|
||||||
padding-right: 6.4rem;
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
width: 55.2rem;
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.page-control {
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
82
src/views/SellerDashboard/MyListings/EditDetail/types.ts
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
export type RadioOption = {
|
||||||
|
name: string | number
|
||||||
|
value: string | number | boolean
|
||||||
|
key: string
|
||||||
|
optype: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TopImageType = "sketch" | "mainProductImage" | "cover"
|
||||||
|
export type CropType = TopImageType | "apparel"
|
||||||
|
export type CoverSourceType = "sketch" | "mainProductImage"
|
||||||
|
export type ListingImageCategory =
|
||||||
|
| "cover"
|
||||||
|
| "cover_from"
|
||||||
|
| "main_product"
|
||||||
|
| "mainProductImage"
|
||||||
|
| "product"
|
||||||
|
| "sketch"
|
||||||
|
| "apparel"
|
||||||
|
| "firstFrame"
|
||||||
|
| "gif"
|
||||||
|
| "video"
|
||||||
|
|
||||||
|
export type ProductMediaItem = {
|
||||||
|
url: string
|
||||||
|
selected?: boolean
|
||||||
|
isVideo?: boolean
|
||||||
|
videoUrl?: string
|
||||||
|
gifUrl?: string
|
||||||
|
firstFrameUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ListingItem = {
|
||||||
|
designItemId: number | string | null
|
||||||
|
sketch: string | null
|
||||||
|
mainProductImage: string
|
||||||
|
cover: string
|
||||||
|
productImage: string[]
|
||||||
|
apparelSketch: string[]
|
||||||
|
productName: string
|
||||||
|
price: string
|
||||||
|
desc: string
|
||||||
|
gender: string
|
||||||
|
category: string[] | null
|
||||||
|
coverFrom: CoverSourceType
|
||||||
|
firstSelectedIndex: number | null
|
||||||
|
prodImageList: ProductMediaItem[]
|
||||||
|
sketchList: Array<{ url: string | null }>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ListingDetailImage = {
|
||||||
|
category?: ListingImageCategory | string | null
|
||||||
|
imageUrl?: string | null
|
||||||
|
isSelected?: boolean | number | string | null
|
||||||
|
isSeleted?: boolean | number | string | null
|
||||||
|
selected?: boolean | number | string | null
|
||||||
|
sortOrder?: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ListingDetailResponse = {
|
||||||
|
id?: number | string | null
|
||||||
|
title?: string | null
|
||||||
|
description?: string | null
|
||||||
|
price?: number | string | null
|
||||||
|
designFor?: string | null
|
||||||
|
productCategory?: string | string[] | null
|
||||||
|
images?: ListingDetailImage[] | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SketchDetailVideo = {
|
||||||
|
firstFrameUrl?: string | null
|
||||||
|
gifUrl?: string | null
|
||||||
|
videoUrl?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SketchDetailResponse = {
|
||||||
|
clothes?: string[] | null
|
||||||
|
designItemId?: number | string | null
|
||||||
|
toProductImageUrls?: string[] | null
|
||||||
|
videos?: SketchDetailVideo[] | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StatusType = "draft" | "publish"
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
||||||
|
import { Https } from '@/tool/https'
|
||||||
|
import { setPubDate } from "@/tool/util";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useStore } from "vuex";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
getCollectionListData: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const emit = defineEmits([
|
||||||
|
'selectCollectionItem',
|
||||||
|
])
|
||||||
|
const {t} = useI18n()
|
||||||
|
const store = useStore()
|
||||||
|
const page = ref(1)
|
||||||
|
const size = ref(6)
|
||||||
|
const total = ref(0)
|
||||||
|
const list = ref([
|
||||||
|
|
||||||
|
])
|
||||||
|
const getListData = ()=>{
|
||||||
|
return {
|
||||||
|
...props.getCollectionListData,
|
||||||
|
page: page.value,
|
||||||
|
size: size.value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getCreateList = ()=>{
|
||||||
|
let data = getListData()
|
||||||
|
store.commit("set_loading", true)
|
||||||
|
Https.axiosPost(Https.httpUrls.historyProject, data).then((rv)=>{
|
||||||
|
list.value = rv.content || []
|
||||||
|
total.value = rv.total || 0
|
||||||
|
store.commit("set_loading", false)
|
||||||
|
}).catch(()=>{
|
||||||
|
store.commit("set_loading", false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const selectCollectionItem = (item:any)=>{
|
||||||
|
console.log(item)
|
||||||
|
if(item.userLikeGroupVO?.groupDetails?.length > 0){
|
||||||
|
emit('selectCollectionItem',item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(()=>{
|
||||||
|
getCreateList()
|
||||||
|
})
|
||||||
|
onUnmounted(()=>{
|
||||||
|
})
|
||||||
|
defineExpose({getCreateList})
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="historyList">
|
||||||
|
<div class="list">
|
||||||
|
<div v-for="(item,index) in list" :key="index" class="item" @click="selectCollectionItem(item)">
|
||||||
|
<div class="imgList">
|
||||||
|
<div v-if="item.userLikeGroupVO?.groupDetails?.length > 0" v-for="(img,index) in item.userLikeGroupVO?.groupDetails.slice(0, 4)" :key="index" class="img">
|
||||||
|
<img :src="img.url" alt="">
|
||||||
|
</div>
|
||||||
|
<div v-else class="img null">
|
||||||
|
<img src="@/assets/images/seller/selectCollectionNullStatus.png" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="detail">
|
||||||
|
<div class="name">{{item.name}}</div>
|
||||||
|
<div class="bottom">
|
||||||
|
<div>{{item.userLikeGroupVO?.groupDetails?.length || 0}} {{ $t('Seller.sketchs') }}</div>
|
||||||
|
<div>{{setPubDate(item.updateTime,t)}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="type" :class="item.type">
|
||||||
|
{{item.process == "SERIES_DESIGN"?"Series":"Single"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="pagination">
|
||||||
|
<a-pagination v-model:current="page" @change="getCreateList" :pageSize="6" :showSizeChanger="false" show-quick-jumper :total="total" show-less-items />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.historyList{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 3rem;
|
||||||
|
> .list{
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
row-gap: 2.4rem; /* 垂直间距 3px */
|
||||||
|
column-gap: 3.2rem; /* 横向间距 2px */
|
||||||
|
align-content: start;
|
||||||
|
overflow-y: auto;
|
||||||
|
&::-webkit-scrollbar{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
> .item{
|
||||||
|
width: 42.6rem;
|
||||||
|
height: auto;
|
||||||
|
// height: 27.6rem;
|
||||||
|
border: 1.5px solid #C7C7C7;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 2rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all .3s;
|
||||||
|
> .imgList{
|
||||||
|
background-color: #eaeaea;
|
||||||
|
height: 19.2rem;
|
||||||
|
padding: 1rem 1.3rem;
|
||||||
|
display: flex;
|
||||||
|
gap: .4rem;
|
||||||
|
justify-content: center;
|
||||||
|
> .img{
|
||||||
|
width: 9.7rem;
|
||||||
|
height: 17.2rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #fff;
|
||||||
|
&.null{
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
> img{
|
||||||
|
object-fit: contain;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .detail{
|
||||||
|
padding: 2rem 2.4rem;
|
||||||
|
> .name{
|
||||||
|
font-family: pingfang_heavy;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 1.797rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
> .bottom{
|
||||||
|
display: flex;
|
||||||
|
margin-top: .8rem;
|
||||||
|
justify-content: space-between;
|
||||||
|
> div{
|
||||||
|
font-size: 1.2rem;
|
||||||
|
font-family: pingfang_regular;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
line-height: 1;
|
||||||
|
color: #585858;
|
||||||
|
}
|
||||||
|
> div:nth-child(2){
|
||||||
|
color: #979797;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .type{
|
||||||
|
width: 7.6rem;
|
||||||
|
height: 3rem;
|
||||||
|
border-radius: 2rem;
|
||||||
|
border: 1px solid #727070;
|
||||||
|
background: #7E7C7C;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
line-height: 150%;
|
||||||
|
color: #fff;
|
||||||
|
position: absolute;
|
||||||
|
top: .5rem;
|
||||||
|
right: .5rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
&.Series{
|
||||||
|
|
||||||
|
}
|
||||||
|
&.Single{
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #727070;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
border: 1.5px solid #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .pagination{
|
||||||
|
margin-top: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,37 +1,73 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
import { ref, onMounted, onUnmounted, reactive, toRefs } from "vue";
|
||||||
import sellerHeader from "../../seller-header.vue"
|
import sellerHeader from "../../seller-header.vue"
|
||||||
|
import historyList from "./historyList.vue"
|
||||||
|
import { useRouter } from "vue-router"
|
||||||
|
|
||||||
|
|
||||||
//const props = defineProps({
|
//const props = defineProps({
|
||||||
//})
|
//})
|
||||||
//const emit = defineEmits([
|
//const emit = defineEmits([
|
||||||
//])
|
//])
|
||||||
let data = reactive({
|
const router = useRouter()
|
||||||
|
let getCollectionListData = reactive({
|
||||||
|
process: [],
|
||||||
|
projectName: '',
|
||||||
|
|
||||||
})
|
})
|
||||||
|
const isShowMark = ref(false)
|
||||||
|
const historyListRef = ref(null) as any
|
||||||
|
const handleSearch = () => {
|
||||||
|
historyListRef.value.getCreateList()
|
||||||
|
}
|
||||||
|
const setProcess = (type:any) => {
|
||||||
|
if(type){
|
||||||
|
getCollectionListData.process = [type]
|
||||||
|
}else{
|
||||||
|
getCollectionListData.process = []
|
||||||
|
}
|
||||||
|
historyListRef.value.getCreateList()
|
||||||
|
}
|
||||||
|
const selectCollectionItem = (item:any) => {
|
||||||
|
router.push({path:'/home/seller/myListings/select/'+item.id})
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
})
|
})
|
||||||
onUnmounted(()=>{
|
onUnmounted(()=>{
|
||||||
})
|
})
|
||||||
defineExpose({})
|
defineExpose({})
|
||||||
const {} = toRefs(data);
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="myListings-seller">
|
<div class="create-select">
|
||||||
<seller-header
|
<seller-header />
|
||||||
title="Select Collection"
|
|
||||||
:breadcrumbs="[
|
|
||||||
{title:'My Listings', name:'myListingsIndex'},
|
|
||||||
{title:'Select Collection', name: 'myListingsSelect' }
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
</seller-header>
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
1231222aaa
|
<div class="title">
|
||||||
|
<div class="left">
|
||||||
|
<div :class="{active:!getCollectionListData.process?.[0]}" @click="setProcess('')">{{$t('Seller.All')}}</div>
|
||||||
|
<div :class="{active:getCollectionListData.process[0] == 'SERIES_DESIGN'}" @click="setProcess('SERIES_DESIGN')">{{$t('Seller.SeriesDesign')}}</div>
|
||||||
|
<div :class="{active:getCollectionListData.process[0] == 'SINGLE_DESIGN'}" @click="setProcess('SINGLE_DESIGN')">{{$t('Seller.SingleDesign')}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<div class="search_input flex flex-align-center">
|
||||||
|
<input
|
||||||
|
class="search_input_inner"
|
||||||
|
v-model="getCollectionListData.projectName"
|
||||||
|
:bordered="false"
|
||||||
|
@keydown.enter="handleSearch"
|
||||||
|
placeholder="Search"
|
||||||
|
/>
|
||||||
|
<!-- <SearchOutlined class="search_input_icon" @click="handleSearch" /> -->
|
||||||
|
<SvgIcon name="CSearch" size="20" class="search_input_icon" @click="handleSearch" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<historyList ref="historyListRef" :getCollectionListData="getCollectionListData" @selectCollectionItem="selectCollectionItem"></historyList>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.myListings-seller {
|
.create-select {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@@ -42,6 +78,71 @@ const {} = toRefs(data);
|
|||||||
margin-top: 2rem;
|
margin-top: 2rem;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
padding: 2.4rem 3rem;
|
||||||
|
background-color: #f9fafa;
|
||||||
|
border-radius: 2rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
> .title{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
> .left{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1.2rem;
|
||||||
|
> div{
|
||||||
|
min-width: 9rem;
|
||||||
|
padding: .4rem 2.6rem;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 4rem;
|
||||||
|
border: 1px solid #000000;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 1.6rem;
|
||||||
|
line-height: 150%;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover{
|
||||||
|
color: #fff;
|
||||||
|
background-color: #000;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .active{
|
||||||
|
color: #fff;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> .right{
|
||||||
|
.search_input {
|
||||||
|
height: 3.2rem;
|
||||||
|
width: 27rem; // 默认宽度
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #000;
|
||||||
|
border-radius: 3rem;
|
||||||
|
// column-gap: 3rem;
|
||||||
|
padding: 0 2rem;
|
||||||
|
.search_input_inner {
|
||||||
|
border: none;
|
||||||
|
height: 100%;
|
||||||
|
width: calc(100% - 2rem);
|
||||||
|
padding: .6rem 0;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
&::placeholder {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
&::-webkit-input-placeholder{
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.search_input_icon {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
color: #000;
|
||||||
|
width: initial;
|
||||||
|
height: initial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||