Merge branch 'main' of ssh://18.167.251.121:10002/aidlab/FiDA_Front
This commit is contained in:
41
src/api/depth-canvas.ts
Normal file
41
src/api/depth-canvas.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取深度画布
|
||||||
|
* @param id depth id
|
||||||
|
* @returns 深度画布数据
|
||||||
|
*/
|
||||||
|
export const getDepthCanvas = (id: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/api/deep-canvas/${id}`,
|
||||||
|
method: 'get',
|
||||||
|
loading: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存深度画布
|
||||||
|
* @param data 保存depth的画布数据
|
||||||
|
* @returns 保存结果
|
||||||
|
*/
|
||||||
|
export const saveDepthCanvas = (data: object) => {
|
||||||
|
return request({
|
||||||
|
url: `/api/deep-canvas/update`,
|
||||||
|
method: 'put',
|
||||||
|
data,
|
||||||
|
loading: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除深度画布
|
||||||
|
* @param id depth id
|
||||||
|
* @returns 删除结果
|
||||||
|
*/
|
||||||
|
export const deleteDepthCanvas = (id: string) => {
|
||||||
|
return request({
|
||||||
|
url: `/api/deep-canvas/${id}`,
|
||||||
|
method: 'delete',
|
||||||
|
loading: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
4
src/assets/icons/canvas-mode-2.svg
Normal file
4
src/assets/icons/canvas-mode-2.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.00048 3.33301C9.00048 2.98775 8.73787 2.70359 8.40152 2.6696L8.33381 2.66634H7.66715C7.29896 2.66634 7.00048 2.96482 7.00048 3.33301V5.11296C7.00048 5.35112 6.8734 5.57134 6.66715 5.69043C6.46092 5.8095 6.20673 5.80944 6.00048 5.69043L4.45881 4.80046C4.14019 4.61654 3.73288 4.72564 3.54866 5.0446H3.54801L3.21532 5.62142C3.03109 5.94051 3.14031 6.34826 3.45881 6.53223L4.99983 7.42155C5.20601 7.5406 5.33309 7.76093 5.33316 7.99902C5.33316 8.23709 5.20596 8.45737 4.99983 8.5765L3.45881 9.46712C3.14031 9.65109 3.03109 10.0588 3.21532 10.3779L3.54801 10.9548H3.54866L3.58577 11.012C3.78349 11.2862 4.16011 11.3713 4.45881 11.1989L6.00048 10.3083C6.20669 10.1893 6.46093 10.1892 6.66715 10.3083C6.87339 10.4274 7.00048 10.6476 7.00048 10.8857V12.6663L7.00374 12.7347C7.03796 13.0708 7.32203 13.333 7.66715 13.333H8.33381C8.70196 13.3329 9.00048 13.0345 9.00048 12.6663V10.8857C9.00048 10.6475 9.1275 10.4273 9.33381 10.3083C9.54007 10.1892 9.79426 10.1892 10.0005 10.3083L11.5421 11.1989L11.6027 11.2301C11.9107 11.3685 12.2797 11.2538 12.4523 10.9548L12.7856 10.3779C12.9698 10.0589 12.8605 9.65117 12.5421 9.46712L11.0005 8.5765C10.7943 8.45738 10.6671 8.23713 10.6671 7.99902C10.6672 7.76086 10.7942 7.54058 11.0005 7.42155L12.5421 6.53223L12.5994 6.49512C12.873 6.29748 12.9583 5.92044 12.7856 5.62142L12.4523 5.0446C12.2682 4.72566 11.8608 4.61662 11.5421 4.80046L10.0005 5.69043C9.79426 5.80947 9.54004 5.80943 9.33381 5.69043C9.12755 5.57134 9.00048 5.35113 9.00048 5.11296V3.33301ZM10.3338 3.95801L10.8755 3.64551C11.8322 3.0934 13.0551 3.42161 13.6073 4.37793H13.6066L13.9399 4.95475H13.9406C14.4926 5.91099 14.1654 7.13469 13.2088 7.68717H13.2082L12.6671 7.99902L13.2088 8.31217L13.2967 8.36621C14.1849 8.94119 14.4753 10.1183 13.9406 11.0446H13.9399L13.6073 11.6214C13.0551 12.5777 11.8322 12.906 10.8755 12.3538L10.3338 12.0407V12.6663C10.3338 13.7364 9.49335 14.6101 8.43668 14.6637L8.33381 14.6663H7.66715C6.56258 14.6663 5.66715 13.7709 5.66715 12.6663V12.0407L5.12548 12.3538C4.19859 12.8888 3.02167 12.5976 2.44709 11.7093L2.39371 11.6214L2.06038 11.0446C1.50835 10.0884 1.83501 8.86475 2.7915 8.31217L3.33251 7.99902L2.79215 7.68717C1.83545 7.13468 1.50829 5.911 2.06038 4.95475L2.39371 4.37793L2.44709 4.29004C3.02167 3.40179 4.1986 3.1105 5.12548 3.64551L5.66715 3.95801V3.33301C5.66715 2.22844 6.56258 1.33301 7.66715 1.33301H8.33381L8.43668 1.33561C9.49335 1.38923 10.3338 2.26296 10.3338 3.33301V3.95801Z" fill="#0D0D0D"/>
|
||||||
|
<path d="M14.6187 0.93143C14.7484 0.578846 15.2469 0.578846 15.3806 0.93143L15.5914 1.50286C15.6319 1.61228 15.7211 1.70144 15.8305 1.74197L16.4019 1.95271C16.7545 2.08239 16.7545 2.58087 16.4019 2.71461L15.8305 2.92535C15.7211 2.96588 15.6319 3.05504 15.5914 3.16446L15.3806 3.73589C15.2509 4.08847 14.7525 4.08847 14.6187 3.73589L14.408 3.16446C14.3675 3.05504 14.2783 2.96588 14.1689 2.92535L13.5974 2.71461C13.2449 2.58493 13.2449 2.08644 13.5974 1.95271L14.1689 1.74197C14.2783 1.70144 14.3675 1.61228 14.408 1.50286L14.6187 0.93143Z" fill="#FF7A51"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
4
src/assets/icons/canvas-mode.svg
Normal file
4
src/assets/icons/canvas-mode.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M11.2494 4.16797C11.2494 3.73639 10.9211 3.3812 10.5007 3.3387L10.416 3.33464H9.58271C9.12248 3.33464 8.74938 3.70773 8.74938 4.16797V6.3929C8.74938 6.69061 8.59052 6.96588 8.33271 7.11475C8.07493 7.26358 7.75719 7.26351 7.49938 7.11475L5.5723 6.00228C5.17401 5.77239 4.66488 5.90876 4.4346 6.30745H4.43379L4.01793 7.02848C3.78765 7.42735 3.92416 7.93703 4.3223 8.16699L6.24857 9.27865C6.50629 9.42746 6.66514 9.70287 6.66523 10.0005C6.66523 10.2981 6.50622 10.5734 6.24857 10.7223L4.3223 11.8356C3.92416 12.0656 3.78764 12.5752 4.01793 12.9741L4.43379 13.6951H4.4346L4.48099 13.7668C4.72814 14.1094 5.19891 14.2158 5.5723 14.0003L7.49938 12.887C7.75714 12.7383 8.07495 12.7383 8.33271 12.887C8.59052 13.0359 8.74938 13.3112 8.74938 13.6089V15.8346L8.75345 15.9201C8.79623 16.3402 9.15132 16.668 9.58271 16.668H10.416C10.8762 16.6679 11.2494 16.2948 11.2494 15.8346V13.6089C11.2494 13.3111 11.4082 13.0359 11.666 12.887C11.9239 12.7383 12.2416 12.7382 12.4994 12.887L14.4265 14.0003L14.5021 14.0394C14.8872 14.2123 15.3484 14.0689 15.5642 13.6951L15.9808 12.9741C16.211 12.5754 16.0744 12.0657 15.6765 11.8356L13.7494 10.7223C13.4916 10.5734 13.3327 10.2981 13.3327 10.0005C13.3328 9.70279 13.4915 9.42743 13.7494 9.27865L15.6765 8.16699L15.7481 8.12061C16.0901 7.87355 16.1966 7.40226 15.9808 7.02848L15.5642 6.30745C15.334 5.90878 14.8248 5.77249 14.4265 6.00228L12.4994 7.11475C12.2416 7.26355 11.9238 7.2635 11.666 7.11475C11.4082 6.96588 11.2494 6.69062 11.2494 6.3929V4.16797ZM12.916 4.94922L13.5931 4.55859C14.789 3.86845 16.3177 4.27872 17.0078 5.47412H17.007L17.4237 6.19515H17.4245C18.1145 7.39045 17.7055 8.92007 16.5098 9.61068H16.509L15.8327 10.0005L16.5098 10.3919L16.6197 10.4595C17.7299 11.1782 18.0929 12.6496 17.4245 13.8075H17.4237L17.0078 14.5285C16.3177 15.7239 14.789 16.1342 13.5931 15.444L12.916 15.0526V15.8346C12.916 17.1722 11.8655 18.2644 10.5446 18.3314L10.416 18.3346H9.58271C8.202 18.3346 7.08271 17.2153 7.08271 15.8346V15.0526L6.40563 15.444C5.24702 16.1128 3.77587 15.7487 3.05765 14.6383L2.99092 14.5285L2.57425 13.8075C1.88421 12.6123 2.29255 11.0826 3.48815 10.3919L4.16442 10.0005L3.48896 9.61068C2.2931 8.92005 1.88414 7.39045 2.57425 6.19515L2.99092 5.47412L3.05765 5.36426C3.77587 4.25395 5.24703 3.88984 6.40563 4.55859L7.08271 4.94922V4.16797C7.08271 2.78726 8.202 1.66797 9.58271 1.66797H10.416L10.5446 1.67122C11.8655 1.73824 12.916 2.83041 12.916 4.16797V4.94922Z" fill="white"/>
|
||||||
|
<path d="M18.2722 1.16258C18.4343 0.721849 19.0574 0.721849 19.2246 1.16258L19.488 1.87686C19.5386 2.01364 19.6501 2.12509 19.7869 2.17575L20.5012 2.43917C20.9419 2.60128 20.9419 3.22438 20.5012 3.39156L19.7869 3.65498C19.6501 3.70564 19.5386 3.81709 19.488 3.95387L19.2246 4.66815C19.0625 5.10888 18.4394 5.10888 18.2722 4.66815L18.0088 3.95387C17.9581 3.81709 17.8466 3.70564 17.7099 3.65498L16.9956 3.39156C16.5549 3.22945 16.5549 2.60635 16.9956 2.43917L17.7099 2.17575C17.8466 2.12509 17.9581 2.01364 18.0088 1.87686L18.2722 1.16258Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
3
src/assets/icons/dc/add.svg
Normal file
3
src/assets/icons/dc/add.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M3.42857 0V1.14286H12.5714V0H16V3.42857H14.8571V12.5714H16V16H12.5714V14.8571H3.42857V16H0V12.5714H1.14286V3.42857H0V0H3.42857ZM2.28571 13.7143H1.14286V14.8571H2.28571V13.7143ZM14.8571 13.7143H13.7143V14.8571H14.8571V13.7143ZM12.5714 2.28571H3.42857V3.42857H2.28571V12.5714H3.42857V13.7143H12.5714V12.5714H13.7143V3.42857H12.5714V2.28571ZM8 4.57143C8.15155 4.57143 8.2969 4.63163 8.40406 4.7388C8.51123 4.84596 8.57143 4.9913 8.57143 5.14286V7.42857H10.8571C11.0087 7.42857 11.154 7.48878 11.2612 7.59594C11.3684 7.7031 11.4286 7.84845 11.4286 8C11.4286 8.15155 11.3684 8.2969 11.2612 8.40406C11.154 8.51123 11.0087 8.57143 10.8571 8.57143H8.57143V10.8571C8.57143 11.0087 8.51123 11.154 8.40406 11.2612C8.2969 11.3684 8.15155 11.4286 8 11.4286C7.84845 11.4286 7.7031 11.3684 7.59594 11.2612C7.48878 11.154 7.42857 11.0087 7.42857 10.8571V8.57143H5.14286C4.9913 8.57143 4.84596 8.51123 4.7388 8.40406C4.63163 8.2969 4.57143 8.15155 4.57143 8C4.57143 7.84845 4.63163 7.7031 4.7388 7.59594C4.84596 7.48878 4.9913 7.42857 5.14286 7.42857H7.42857V5.14286C7.42857 4.9913 7.48878 4.84596 7.59594 4.7388C7.7031 4.63163 7.84845 4.57143 8 4.57143ZM14.8571 1.14286H13.7143V2.28571H14.8571V1.14286ZM2.28571 1.14286H1.14286V2.28571H2.28571V1.14286Z" fill="#0D0D0D"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
3
src/assets/icons/dc/remove.svg
Normal file
3
src/assets/icons/dc/remove.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M3.42857 0V1.14286H12.5714V0H16V3.42857H14.8571V12.5714H16V16H12.5714V14.8571H3.42857V16H0V12.5714H1.14286V3.42857H0V0H3.42857ZM2.28571 13.7143H1.14286V14.8571H2.28571V13.7143ZM14.8571 13.7143H13.7143V14.8571H14.8571V13.7143ZM12.5714 2.28571H3.42857V3.42857H2.28571V12.5714H3.42857V13.7143H12.5714V12.5714H13.7143V3.42857H12.5714V2.28571ZM10.8571 7.42857C11.0087 7.42857 11.154 7.48878 11.2612 7.59594C11.3684 7.7031 11.4286 7.84845 11.4286 8C11.4286 8.15155 11.3684 8.2969 11.2612 8.40406C11.154 8.51123 11.0087 8.57143 10.8571 8.57143H5.14286C4.9913 8.57143 4.84596 8.51123 4.7388 8.40406C4.63163 8.2969 4.57143 8.15155 4.57143 8C4.57143 7.84845 4.63163 7.7031 4.7388 7.59594C4.84596 7.48878 4.9913 7.42857 5.14286 7.42857H10.8571ZM14.8571 1.14286H13.7143V2.28571H14.8571V1.14286ZM2.28571 1.14286H1.14286V2.28571H2.28571V1.14286Z" fill="#0D0D0D"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 962 B |
4
src/assets/icons/fast-mode-2.svg
Normal file
4
src/assets/icons/fast-mode-2.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="17" height="16" viewBox="0 0 17 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.00048 3.33301C9.00048 2.98775 8.73787 2.70359 8.40152 2.6696L8.33381 2.66634H7.66715C7.29896 2.66634 7.00048 2.96482 7.00048 3.33301V5.11296C7.00048 5.35112 6.8734 5.57134 6.66715 5.69043C6.46092 5.8095 6.20673 5.80944 6.00048 5.69043L4.45881 4.80046C4.14019 4.61654 3.73288 4.72564 3.54866 5.0446H3.54801L3.21532 5.62142C3.03109 5.94051 3.14031 6.34826 3.45881 6.53223L4.99983 7.42155C5.20601 7.5406 5.33309 7.76093 5.33316 7.99902C5.33316 8.23709 5.20596 8.45737 4.99983 8.5765L3.45881 9.46712C3.14031 9.65109 3.03109 10.0588 3.21532 10.3779L3.54801 10.9548H3.54866L3.58577 11.012C3.78349 11.2862 4.16011 11.3713 4.45881 11.1989L6.00048 10.3083C6.20669 10.1893 6.46093 10.1892 6.66715 10.3083C6.87339 10.4274 7.00048 10.6476 7.00048 10.8857V12.6663L7.00374 12.7347C7.03796 13.0708 7.32203 13.333 7.66715 13.333H8.33381C8.70196 13.3329 9.00048 13.0345 9.00048 12.6663V10.8857C9.00048 10.6475 9.1275 10.4273 9.33381 10.3083C9.54007 10.1892 9.79426 10.1892 10.0005 10.3083L11.5421 11.1989L11.6027 11.2301C11.9107 11.3685 12.2797 11.2538 12.4523 10.9548L12.7856 10.3779C12.9698 10.0589 12.8605 9.65117 12.5421 9.46712L11.0005 8.5765C10.7943 8.45738 10.6671 8.23713 10.6671 7.99902C10.6672 7.76086 10.7942 7.54058 11.0005 7.42155L12.5421 6.53223L12.5994 6.49512C12.873 6.29748 12.9583 5.92044 12.7856 5.62142L12.4523 5.0446C12.2682 4.72566 11.8608 4.61662 11.5421 4.80046L10.0005 5.69043C9.79426 5.80947 9.54004 5.80943 9.33381 5.69043C9.12755 5.57134 9.00048 5.35113 9.00048 5.11296V3.33301ZM10.3338 3.95801L10.8755 3.64551C11.8322 3.0934 13.0551 3.42161 13.6073 4.37793H13.6066L13.9399 4.95475H13.9406C14.4926 5.91099 14.1654 7.13469 13.2088 7.68717H13.2082L12.6671 7.99902L13.2088 8.31217L13.2967 8.36621C14.1849 8.94119 14.4753 10.1183 13.9406 11.0446H13.9399L13.6073 11.6214C13.0551 12.5777 11.8322 12.906 10.8755 12.3538L10.3338 12.0407V12.6663C10.3338 13.7364 9.49335 14.6101 8.43668 14.6637L8.33381 14.6663H7.66715C6.56258 14.6663 5.66715 13.7709 5.66715 12.6663V12.0407L5.12548 12.3538C4.19859 12.8888 3.02167 12.5976 2.44709 11.7093L2.39371 11.6214L2.06038 11.0446C1.50835 10.0884 1.83501 8.86475 2.7915 8.31217L3.33251 7.99902L2.79215 7.68717C1.83545 7.13468 1.50829 5.911 2.06038 4.95475L2.39371 4.37793L2.44709 4.29004C3.02167 3.40179 4.1986 3.1105 5.12548 3.64551L5.66715 3.95801V3.33301C5.66715 2.22844 6.56258 1.33301 7.66715 1.33301H8.33381L8.43668 1.33561C9.49335 1.38923 10.3338 2.26296 10.3338 3.33301V3.95801Z" fill="#0D0D0D"/>
|
||||||
|
<path d="M14.6187 0.93143C14.7484 0.578846 15.2469 0.578846 15.3806 0.93143L15.5914 1.50286C15.6319 1.61228 15.7211 1.70144 15.8305 1.74197L16.4019 1.95271C16.7545 2.08239 16.7545 2.58087 16.4019 2.71461L15.8305 2.92535C15.7211 2.96588 15.6319 3.05504 15.5914 3.16446L15.3806 3.73589C15.2509 4.08847 14.7525 4.08847 14.6187 3.73589L14.408 3.16446C14.3675 3.05504 14.2783 2.96588 14.1689 2.92535L13.5974 2.71461C13.2449 2.58493 13.2449 2.08644 13.5974 1.95271L14.1689 1.74197C14.2783 1.70144 14.3675 1.61228 14.408 1.50286L14.6187 0.93143Z" fill="#FF7A51"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
4
src/assets/icons/fast-mode.svg
Normal file
4
src/assets/icons/fast-mode.svg
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M11.2494 4.16797C11.2494 3.73639 10.9211 3.3812 10.5007 3.3387L10.416 3.33464H9.58271C9.12248 3.33464 8.74938 3.70773 8.74938 4.16797V6.3929C8.74938 6.69061 8.59052 6.96588 8.33271 7.11475C8.07493 7.26358 7.75719 7.26351 7.49938 7.11475L5.5723 6.00228C5.17401 5.77239 4.66488 5.90876 4.4346 6.30745H4.43379L4.01793 7.02848C3.78765 7.42735 3.92416 7.93703 4.3223 8.16699L6.24857 9.27865C6.50629 9.42746 6.66514 9.70287 6.66523 10.0005C6.66523 10.2981 6.50622 10.5734 6.24857 10.7223L4.3223 11.8356C3.92416 12.0656 3.78764 12.5752 4.01793 12.9741L4.43379 13.6951H4.4346L4.48099 13.7668C4.72814 14.1094 5.19891 14.2158 5.5723 14.0003L7.49938 12.887C7.75714 12.7383 8.07495 12.7383 8.33271 12.887C8.59052 13.0359 8.74938 13.3112 8.74938 13.6089V15.8346L8.75345 15.9201C8.79623 16.3402 9.15132 16.668 9.58271 16.668H10.416C10.8762 16.6679 11.2494 16.2948 11.2494 15.8346V13.6089C11.2494 13.3111 11.4082 13.0359 11.666 12.887C11.9239 12.7383 12.2416 12.7382 12.4994 12.887L14.4265 14.0003L14.5021 14.0394C14.8872 14.2123 15.3484 14.0689 15.5642 13.6951L15.9808 12.9741C16.211 12.5754 16.0744 12.0657 15.6765 11.8356L13.7494 10.7223C13.4916 10.5734 13.3327 10.2981 13.3327 10.0005C13.3328 9.70279 13.4915 9.42743 13.7494 9.27865L15.6765 8.16699L15.7481 8.12061C16.0901 7.87355 16.1966 7.40226 15.9808 7.02848L15.5642 6.30745C15.334 5.90878 14.8248 5.77249 14.4265 6.00228L12.4994 7.11475C12.2416 7.26355 11.9238 7.2635 11.666 7.11475C11.4082 6.96588 11.2494 6.69062 11.2494 6.3929V4.16797ZM12.916 4.94922L13.5931 4.55859C14.789 3.86845 16.3177 4.27872 17.0078 5.47412H17.007L17.4237 6.19515H17.4245C18.1145 7.39045 17.7055 8.92007 16.5098 9.61068H16.509L15.8327 10.0005L16.5098 10.3919L16.6197 10.4595C17.7299 11.1782 18.0929 12.6496 17.4245 13.8075H17.4237L17.0078 14.5285C16.3177 15.7239 14.789 16.1342 13.5931 15.444L12.916 15.0526V15.8346C12.916 17.1722 11.8655 18.2644 10.5446 18.3314L10.416 18.3346H9.58271C8.202 18.3346 7.08271 17.2153 7.08271 15.8346V15.0526L6.40563 15.444C5.24702 16.1128 3.77587 15.7487 3.05765 14.6383L2.99092 14.5285L2.57425 13.8075C1.88421 12.6123 2.29255 11.0826 3.48815 10.3919L4.16442 10.0005L3.48896 9.61068C2.2931 8.92005 1.88414 7.39045 2.57425 6.19515L2.99092 5.47412L3.05765 5.36426C3.77587 4.25395 5.24703 3.88984 6.40563 4.55859L7.08271 4.94922V4.16797C7.08271 2.78726 8.202 1.66797 9.58271 1.66797H10.416L10.5446 1.67122C11.8655 1.73824 12.916 2.83041 12.916 4.16797V4.94922Z" fill="white"/>
|
||||||
|
<path d="M18.2722 1.16258C18.4343 0.721849 19.0574 0.721849 19.2246 1.16258L19.488 1.87686C19.5386 2.01364 19.6501 2.12509 19.7869 2.17575L20.5012 2.43917C20.9419 2.60128 20.9419 3.22438 20.5012 3.39156L19.7869 3.65498C19.6501 3.70564 19.5386 3.81709 19.488 3.95387L19.2246 4.66815C19.0625 5.10888 18.4394 5.10888 18.2722 4.66815L18.0088 3.95387C17.9581 3.81709 17.8466 3.70564 17.7099 3.65498L16.9956 3.39156C16.5549 3.22945 16.5549 2.60635 16.9956 2.43917L17.7099 2.17575C17.8466 2.12509 17.9581 2.01364 18.0088 1.87686L18.2722 1.16258Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1,76 @@
|
|||||||
|
<template>
|
||||||
|
<transition name="fade">
|
||||||
|
<div v-if="show" class="ai-selectbox-panel">
|
||||||
|
<div>
|
||||||
|
<span class="icon"><svg-icon name="dc-add" size="16" /></span>
|
||||||
|
<span class="label">Add</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="icon"><svg-icon name="dc-remove" size="16" /></span>
|
||||||
|
<span class="label">Remove</span>
|
||||||
|
</div>
|
||||||
|
<button>创建</button>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, inject, computed, watch } from 'vue'
|
||||||
|
import depthSlider from './tools/depth-slider.vue'
|
||||||
|
import { OperationType } from '../tools/layerHelper'
|
||||||
|
const props = defineProps({
|
||||||
|
currentTool: { required: true, type: [String, null] }
|
||||||
|
})
|
||||||
|
const stateManager = inject('stateManager') as any
|
||||||
|
const toolManager = inject('toolManager') as any
|
||||||
|
const showTools = [OperationType.SELECTBOX]
|
||||||
|
const show = computed(() => showTools.includes(props.currentTool))
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
// 淡入淡出动画
|
||||||
|
.fade-enter-active,
|
||||||
|
.fade-leave-active {
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
.fade-enter-from,
|
||||||
|
.fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-selectbox-panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 8.8rem;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
height: 4.1rem;
|
||||||
|
padding: 0 1.7rem;
|
||||||
|
border: 0.2rem solid #ebebeb;
|
||||||
|
background: #ffffff;
|
||||||
|
border-radius: 1.1rem;
|
||||||
|
box-shadow: 0 1.66rem 2.33rem 0 rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
user-select: none;
|
||||||
|
gap: 1rem;
|
||||||
|
> div {
|
||||||
|
display: flex;
|
||||||
|
cursor: pointer;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 2.6rem;
|
||||||
|
padding: 0 0.7rem;
|
||||||
|
border-radius: 0.3rem;
|
||||||
|
gap: 1rem;
|
||||||
|
> .label {
|
||||||
|
font-size: 1.4rem;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
&.active,
|
||||||
|
&:hover {
|
||||||
|
background: rgba(235, 235, 235, 0.9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -178,8 +178,8 @@
|
|||||||
}
|
}
|
||||||
const onWorkbench = async () => {
|
const onWorkbench = async () => {
|
||||||
exportCanvasToImage(canvasManager.canvas).then((url) => {
|
exportCanvasToImage(canvasManager.canvas).then((url) => {
|
||||||
const json = canvasManager.getCanvasJSON()
|
const { canvas, images } = canvasManager.getCanvasDisUrlJSON()
|
||||||
emit('workbench', { url, json })
|
emit('workbench', { url, canvas, images })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,8 +6,10 @@
|
|||||||
<template v-if="isReady">
|
<template v-if="isReady">
|
||||||
<layer-panel />
|
<layer-panel />
|
||||||
<details-panel />
|
<details-panel />
|
||||||
<depth-header-tools @export="exportCanvas" @workbench="(v) => emit('workbench', v)" />
|
|
||||||
<brush-control-panel :currentTool="toolManager.currentTool.value" />
|
<brush-control-panel :currentTool="toolManager.currentTool.value" />
|
||||||
|
<ai-selectbox-panel :currentTool="toolManager.currentTool.value" />
|
||||||
|
<depth-header-tools @export="exportCanvas" @workbench="(v) => emit('workbench', v)" />
|
||||||
|
|
||||||
<zoom
|
<zoom
|
||||||
:zoom="canvasManager.currentZoom.value / 100"
|
:zoom="canvasManager.currentZoom.value / 100"
|
||||||
is-home
|
is-home
|
||||||
@@ -30,6 +32,7 @@
|
|||||||
import depthHeaderTools from './components/depth-header-tools.vue'
|
import depthHeaderTools from './components/depth-header-tools.vue'
|
||||||
import zoom from '../components/zoom.vue'
|
import zoom from '../components/zoom.vue'
|
||||||
import brushControlPanel from './components/brush-control-panel.vue'
|
import brushControlPanel from './components/brush-control-panel.vue'
|
||||||
|
import aiSelectboxPanel from './components/ai-selectbox-panel.vue'
|
||||||
|
|
||||||
// 管理器
|
// 管理器
|
||||||
import { StateManager } from './manager/StateManager'
|
import { StateManager } from './manager/StateManager'
|
||||||
@@ -60,8 +63,8 @@
|
|||||||
provide('stateManager', stateManager)
|
provide('stateManager', stateManager)
|
||||||
|
|
||||||
// 画布管理器
|
// 画布管理器
|
||||||
const canvasManager = new CanvasManager({ stateManager })
|
const canvasManager = new CanvasManager({ stateManager, props })
|
||||||
stateManager.setManager({ canvasManager, canvasRef })
|
stateManager.setManager({ canvasManager })
|
||||||
provide('canvasManager', canvasManager)
|
provide('canvasManager', canvasManager)
|
||||||
|
|
||||||
// 图层管理器
|
// 图层管理器
|
||||||
@@ -89,16 +92,19 @@
|
|||||||
globalStore.setLoading(true)
|
globalStore.setLoading(true)
|
||||||
keyEventManager.registerEvents()
|
keyEventManager.registerEvents()
|
||||||
const url = props.config.url || ''
|
const url = props.config.url || ''
|
||||||
const json = props.config.json || ''
|
const canvasData = props.config.canvasData || ''
|
||||||
await canvasManager.initCanvas({
|
await canvasManager.initCanvas({
|
||||||
canvasRef,
|
canvasRef,
|
||||||
canvasViewWidth: canvasContainerRef.value.clientWidth,
|
canvasViewWidth: canvasContainerRef.value.clientWidth,
|
||||||
canvasViewHeight: canvasContainerRef.value.clientHeight,
|
canvasViewHeight: canvasContainerRef.value.clientHeight,
|
||||||
canvasWidth: props.config.width || 750,
|
canvasWidth: props.config.width || 750,
|
||||||
canvasHeight: props.config.height || 600,
|
canvasHeight: props.config.height || 600,
|
||||||
url: json ? '' : url
|
url: canvasData ? '' : url
|
||||||
})
|
})
|
||||||
if (json) await canvasManager.loadJSON(json)
|
if (canvasData) {
|
||||||
|
const json = canvasManager.processCanvasDisUrlJSON(canvasData)
|
||||||
|
await canvasManager.loadJSON(json)
|
||||||
|
}
|
||||||
globalStore.setLoading(false)
|
globalStore.setLoading(false)
|
||||||
|
|
||||||
stateManager.onMounted()
|
stateManager.onMounted()
|
||||||
|
|||||||
@@ -9,33 +9,54 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { base64Tofile } from '../tools/tools'
|
import { base64Tofile } from '../tools/tools'
|
||||||
import { uploadImage } from '@/api/upload'
|
import { uploadImage } from '@/api/upload'
|
||||||
|
import { getDepthCanvas, saveDepthCanvas } from '@/api/depth-canvas'
|
||||||
import FullscreenDialog from '../components/fullscreen-dialog.vue'
|
import FullscreenDialog from '../components/fullscreen-dialog.vue'
|
||||||
import depthCanvas from './depth-canvas.vue'
|
import depthCanvas from './depth-canvas.vue'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
const config = ref({
|
const config = ref({
|
||||||
id: '',
|
canvasId: '',
|
||||||
|
sketchId: '',
|
||||||
url: '',
|
url: '',
|
||||||
json: ''
|
canvasData: '' as any,
|
||||||
|
onWorkbench(options) {},
|
||||||
|
onClose() {}
|
||||||
})
|
})
|
||||||
|
|
||||||
const open = (options) => {
|
const open = async (options) => {
|
||||||
config.value = options
|
config.value = options
|
||||||
console.log(config.value)
|
if (config.value.canvasId) {
|
||||||
config.value.json = sessionStorage.getItem('canvasJson_' + config.value.id)
|
const res = await getDepthCanvas(config.value.canvasId)
|
||||||
|
const canvas = res.deepCanvasDetail
|
||||||
|
const images = res.images
|
||||||
|
if (canvas && images) {
|
||||||
|
config.value.canvasData = { canvas: JSON.stringify(canvas), images }
|
||||||
|
} else {
|
||||||
|
config.value.canvasData = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
// 工作区
|
// 工作区
|
||||||
const onWorkbench = async (options) => {
|
const onWorkbench = async (options: { canvas: string; images: Object; url: string }) => {
|
||||||
const json = options.json
|
// 保存画布数据
|
||||||
|
const data = {
|
||||||
sessionStorage.setItem('canvasJson_' + config.value.id, json)
|
deepCanvasDetail: JSON.parse(options.canvas),
|
||||||
|
images: options.images,
|
||||||
|
sketchId: config.value.sketchId,
|
||||||
|
id: config.value.canvasId || null
|
||||||
|
}
|
||||||
|
const sData = await saveDepthCanvas(data)
|
||||||
|
|
||||||
|
const canvasId = sData.id
|
||||||
|
// base64 转 file 上传转换为 url
|
||||||
const file = base64Tofile(options.url, 'canvas.png')
|
const file = base64Tofile(options.url, 'canvas.png')
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('file', file)
|
formData.append('file', file)
|
||||||
const url = await uploadImage(formData)
|
const url = await uploadImage(formData, true)
|
||||||
config.value.onWorkbench?.({ url })
|
config.value.onWorkbench?.({ url, canvasId })
|
||||||
|
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
}
|
}
|
||||||
// 关闭
|
// 关闭
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { fabric } from 'fabric-with-all'
|
import { fabric } from 'fabric-with-all'
|
||||||
|
import { createId } from '../../tools/tools'
|
||||||
|
|
||||||
/** 智能框选工具管理器 */
|
/** 智能框选工具管理器 */
|
||||||
export class AISelectboxToolManager {
|
export class AISelectboxToolManager {
|
||||||
// 管理器
|
// 管理器
|
||||||
@@ -14,6 +16,7 @@ export class AISelectboxToolManager {
|
|||||||
this.canvasManager = options.canvasManager
|
this.canvasManager = options.canvasManager
|
||||||
this.stateManager = options.stateManager
|
this.stateManager = options.stateManager
|
||||||
this.layerManager = options.layerManager
|
this.layerManager = options.layerManager
|
||||||
|
|
||||||
}
|
}
|
||||||
mouseDownEvent(e) {
|
mouseDownEvent(e) {
|
||||||
this.isDragging = true
|
this.isDragging = true
|
||||||
@@ -39,11 +42,11 @@ export class AISelectboxToolManager {
|
|||||||
var height = e.absolutePointer.y - this.startY
|
var height = e.absolutePointer.y - this.startY
|
||||||
var left = this.startX
|
var left = this.startX
|
||||||
var top = this.startY
|
var top = this.startY
|
||||||
if(width < 0) {
|
if (width < 0) {
|
||||||
left += width
|
left += width
|
||||||
width = -width
|
width = -width
|
||||||
}
|
}
|
||||||
if(height < 0) {
|
if (height < 0) {
|
||||||
top += height
|
top += height
|
||||||
height = -height
|
height = -height
|
||||||
}
|
}
|
||||||
@@ -60,6 +63,249 @@ export class AISelectboxToolManager {
|
|||||||
this.canvasManager.canvas.remove(this.demoObject)
|
this.canvasManager.canvas.remove(this.demoObject)
|
||||||
this.canvasManager.canvas.renderAll()
|
this.canvasManager.canvas.renderAll()
|
||||||
|
|
||||||
|
this.createSelectbox()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
loadImageToObject(url) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
fabric.Image.fromURL(url, (img) => {
|
||||||
|
resolve(img);
|
||||||
|
}, { crossOrigin: "anonymous" });// 防止污染
|
||||||
|
});
|
||||||
|
}
|
||||||
|
rgba = { r: 0, g: 255, b: 0, a: 200 };
|
||||||
|
selectionStyle = {
|
||||||
|
stroke: "rgba(255, 77, 71, 1)",
|
||||||
|
strokeWidth: 1.5,
|
||||||
|
strokeDashArray: [4, 4],
|
||||||
|
fill: "rgba(255, 186, 186, 0.5)",
|
||||||
|
strokeUniform: true, // 保持描边宽度不随缩放改变
|
||||||
|
// strokeLineCap: "round",// 折线端点样式
|
||||||
|
// strokeLineJoin: "bevel", // 折线连接样式
|
||||||
|
// selectable: false,
|
||||||
|
// evented: false,
|
||||||
|
excludeFromExport: true,
|
||||||
|
hoverCursor: "default",
|
||||||
|
moveCursor: "default",
|
||||||
|
};
|
||||||
|
async createSelectbox() {
|
||||||
|
const url = "http://118.31.39.42:3000/falls/1a48ed3a-1faa-4fcd-bf07-765dba1702c5.png"
|
||||||
|
const image = await this.loadImageToObject(url)
|
||||||
|
const canvas = getObjectAlphaToCanvas(image, null, 0, this.rgba);
|
||||||
|
const fobject = this.canvasManager.canvas.clipPath
|
||||||
|
// const top = fobject.top - fobject.height * scaleY / 2;
|
||||||
|
// const left = fobject.left - fobject.width * scaleX / 2;
|
||||||
|
const scaleY = fobject.scaleY
|
||||||
|
const scaleX = fobject.scaleX
|
||||||
|
const top = fobject.top
|
||||||
|
const left = fobject.left
|
||||||
|
const arr = traceImageContour(canvas);
|
||||||
|
let minX = fobject.width;
|
||||||
|
let minY = fobject.height;
|
||||||
|
const str = arr.map((v) => {
|
||||||
|
if (v.x < minX) minX = v.x;
|
||||||
|
if (v.y < minY) minY = v.y;
|
||||||
|
return `${v.x} ${v.y}`
|
||||||
|
}).join(" L ");
|
||||||
|
const path = new fabric.Path(`M ${str} z`);
|
||||||
|
path.set({
|
||||||
|
left: left + minX * scaleX,
|
||||||
|
top: top + minY * scaleY,
|
||||||
|
scaleX: scaleX,
|
||||||
|
scaleY: scaleY,
|
||||||
|
...this.selectionStyle,
|
||||||
|
});
|
||||||
|
const rect1 = new fabric.Rect({
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
fill: '#f00',
|
||||||
|
info: {
|
||||||
|
id: createId("rect"),
|
||||||
|
name: '矩形图层',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const rect2 = new fabric.Rect({
|
||||||
|
left: 200,
|
||||||
|
top: 200,
|
||||||
|
width: 100,
|
||||||
|
height: 100,
|
||||||
|
fill: '#ff0',
|
||||||
|
info: {
|
||||||
|
id: createId("rect"),
|
||||||
|
name: '矩形图层',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.layerManager.createGroupLayer({
|
||||||
|
child: [rect1, rect2],
|
||||||
|
})
|
||||||
|
// this.canvasManager.canvas.add(path)
|
||||||
|
// this.canvasManager.canvas.renderAll()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dispose() { }
|
dispose() { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取对象黑白通道画布
|
||||||
|
* @param {fabric.Object} object - 要处理的 fabric 对象
|
||||||
|
* @param {ImageData} revData - 相反的ImageData,白通道的相同位置是否为透明,revData为白色为透明,黑色为不透明
|
||||||
|
* @param {number} diff - 差值,默认 25
|
||||||
|
* @param {Object} rgba - 自定义 rgba 值,默认 { r: 255, g: 255, b: 255, a: 255 }
|
||||||
|
* @param {boolean} isMerge - 是否合并,true=合并revData,false=反转revData
|
||||||
|
* @returns {HTMLCanvasElement|null} 包含黑白通道的画布,或 null 如果失败
|
||||||
|
*/
|
||||||
|
export function getObjectAlphaToCanvas(object, revData, diff = 30, rgba = { r: 255, g: 255, b: 255, a: 255 }, isMerge = false) {
|
||||||
|
const image = object.getElement();
|
||||||
|
if (image.nodeName !== "IMG" && image.nodeName !== "CANVAS") {
|
||||||
|
console.warn("对象不是图片");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const { width, height } = image;
|
||||||
|
if (!width || !height) {
|
||||||
|
console.warn("对象没有元素");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
ctx.drawImage(image, 0, 0, width, height);
|
||||||
|
const data = ctx.getImageData(0, 0, width, height);
|
||||||
|
for (let i = 0; i < data.data.length; i += 4) {
|
||||||
|
const r = data.data[i + 0];
|
||||||
|
const g = data.data[i + 1];
|
||||||
|
const b = data.data[i + 2];
|
||||||
|
const a = data.data[i + 3];
|
||||||
|
const revR = revData?.data[i + 0] || 0;
|
||||||
|
const revG = revData?.data[i + 1] || 0;
|
||||||
|
const revB = revData?.data[i + 2] || 0;
|
||||||
|
const revA = revData?.data[i + 3] || 0;
|
||||||
|
let isHave = false;
|
||||||
|
if (r || g || b || a) {
|
||||||
|
if (revR > diff || revG > diff || revB > diff || revA > diff) {
|
||||||
|
isHave = false;
|
||||||
|
} else {
|
||||||
|
isHave = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isMerge && (revR || revG || revB || revA)) isHave = true;
|
||||||
|
if (isHave) {
|
||||||
|
data.data[i + 0] = rgba.r;
|
||||||
|
data.data[i + 1] = rgba.g;
|
||||||
|
data.data[i + 2] = rgba.b;
|
||||||
|
data.data[i + 3] = rgba.a;
|
||||||
|
} else {
|
||||||
|
data.data[i + 0] = 0;
|
||||||
|
data.data[i + 1] = 0;
|
||||||
|
data.data[i + 2] = 0;
|
||||||
|
data.data[i + 3] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
ctx.putImageData(data, 0, 0);
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片边界跟踪算法(透明底)
|
||||||
|
* @param {HTMLCanvasElement} canvas - canvas元素
|
||||||
|
* @param {Number} scale - 缩放比例
|
||||||
|
* @returns {Array} 边界点数组 [{x, y}, ...]
|
||||||
|
*/
|
||||||
|
export function traceImageContour(canvas) {
|
||||||
|
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
||||||
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
const data = imageData.data;
|
||||||
|
const width = canvas.width;
|
||||||
|
const height = canvas.height;
|
||||||
|
|
||||||
|
// 查找起始点(第一个不透明像素)
|
||||||
|
let startX = -1;
|
||||||
|
let startY = -1;
|
||||||
|
|
||||||
|
outer: for (let y = 0; y < height; y++) {
|
||||||
|
for (let x = 0; x < width; x++) {
|
||||||
|
const index = (y * width + x) * 4;
|
||||||
|
if (data[index + 3] > 0) {
|
||||||
|
startX = x;
|
||||||
|
startY = y;
|
||||||
|
break outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startX === -1) return []; // 没有不透明像素
|
||||||
|
|
||||||
|
// Moore-Neighbor边界跟踪算法
|
||||||
|
const contour = [];
|
||||||
|
const visited = new Set();
|
||||||
|
const directions = [
|
||||||
|
[-1, 0],
|
||||||
|
[-1, -1],
|
||||||
|
[0, -1],
|
||||||
|
[1, -1],
|
||||||
|
[1, 0],
|
||||||
|
[1, 1],
|
||||||
|
[0, 1],
|
||||||
|
[-1, 1],
|
||||||
|
];
|
||||||
|
|
||||||
|
let currentX = startX;
|
||||||
|
let currentY = startY;
|
||||||
|
let backtrackDir = 4; // 起始方向:右
|
||||||
|
|
||||||
|
do {
|
||||||
|
const pointKey = `${currentX},${currentY}`;
|
||||||
|
if (!visited.has(pointKey)) {
|
||||||
|
contour.push({ x: currentX, y: currentY });
|
||||||
|
visited.add(pointKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从右方向开始顺时针查找
|
||||||
|
let found = false;
|
||||||
|
for (let i = 0; i < 8; i++) {
|
||||||
|
const dir = (backtrackDir + i) % 8;
|
||||||
|
const dx = directions[dir][0];
|
||||||
|
const dy = directions[dir][1];
|
||||||
|
const checkX = currentX + dx;
|
||||||
|
const checkY = currentY + dy;
|
||||||
|
|
||||||
|
if (
|
||||||
|
checkX >= 0 &&
|
||||||
|
checkX < width &&
|
||||||
|
checkY >= 0 &&
|
||||||
|
checkY < height
|
||||||
|
) {
|
||||||
|
const index = (checkY * width + checkX) * 4;
|
||||||
|
if (data[index + 3] > 0) {
|
||||||
|
currentX = checkX;
|
||||||
|
currentY = checkY;
|
||||||
|
backtrackDir = (dir + 5) % 8; // 下一个开始查找的方向
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) break;
|
||||||
|
} while (
|
||||||
|
!(currentX === startX && currentY === startY) &&
|
||||||
|
visited.size < width * height
|
||||||
|
);
|
||||||
|
|
||||||
|
return contour;
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import { detectDeviceType } from '../tools/index'
|
|||||||
import { CanvasEventManager } from "./events/CanvasEventManager";
|
import { CanvasEventManager } from "./events/CanvasEventManager";
|
||||||
import { OperationType } from '../tools/layerHelper'
|
import { OperationType } from '../tools/layerHelper'
|
||||||
import { createId } from '../../tools/tools'
|
import { createId } from '../../tools/tools'
|
||||||
|
import md5 from 'md5'
|
||||||
|
|
||||||
// 自定义画布转对象属性
|
// 自定义画布转对象属性
|
||||||
fabric.Object.prototype.customProperties = ["top", "left", "width", "height", "scaleX", "scaleY", "info", "thumbnail"];
|
fabric.Object.prototype.customProperties = ["top", "left", "width", "height", "scaleX", "scaleY", "info", "thumbnail"];
|
||||||
@@ -45,8 +46,10 @@ export class CanvasManager {
|
|||||||
deviceInfo: any
|
deviceInfo: any
|
||||||
canvas: any
|
canvas: any
|
||||||
currentZoom: any
|
currentZoom: any
|
||||||
|
uniqueId: string
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
this.stateManager = options.stateManager;
|
this.stateManager = options.stateManager;
|
||||||
|
this.uniqueId = md5(options.props.config.url || Date.now());
|
||||||
this.deviceInfo = detectDeviceType();
|
this.deviceInfo = detectDeviceType();
|
||||||
this.currentZoom = ref(100)
|
this.currentZoom = ref(100)
|
||||||
}
|
}
|
||||||
@@ -279,6 +282,7 @@ export class CanvasManager {
|
|||||||
console.error('JSON解析错误:', error)
|
console.error('JSON解析错误:', error)
|
||||||
}
|
}
|
||||||
if (!jsonObj) return resolve(false)
|
if (!jsonObj) return resolve(false)
|
||||||
|
if (jsonObj.uniqueId) this.uniqueId = jsonObj.uniqueId
|
||||||
this.canvas.loadFromJSON(jsonObj, () => {
|
this.canvas.loadFromJSON(jsonObj, () => {
|
||||||
if (rerecord) this.stateManager.clearState()
|
if (rerecord) this.stateManager.clearState()
|
||||||
this.resetZoom(false)
|
this.resetZoom(false)
|
||||||
@@ -293,35 +297,39 @@ export class CanvasManager {
|
|||||||
/** 导出画布为处理图片的JSON */
|
/** 导出画布为处理图片的JSON */
|
||||||
getCanvasDisUrlJSON() {
|
getCanvasDisUrlJSON() {
|
||||||
const canvas = this.canvas.toJSON()
|
const canvas = this.canvas.toJSON()
|
||||||
const images = [];
|
const images = {};
|
||||||
var i = 0;
|
const create = (url, key) => {
|
||||||
const create = (url) => {
|
const key_ = `xxxxx_${this.uniqueId}_${md5(key)}_xxxxx`;
|
||||||
const logo = `xxxxxxxx_${i++}_xxxxxxxx`;
|
images[key_] = url
|
||||||
images.push({ index: logo, url })
|
return key_
|
||||||
return logo
|
|
||||||
}
|
}
|
||||||
|
canvas.uniqueId = this.uniqueId
|
||||||
canvas.objects.forEach((object: any) => {
|
canvas.objects.forEach((object: any) => {
|
||||||
|
const id = object.info?.id
|
||||||
if (object.thumbnail) {
|
if (object.thumbnail) {
|
||||||
object.thumbnail = create(object.thumbnail)
|
object.thumbnail = create(object.thumbnail, `thumbnail_${id}`)
|
||||||
}
|
}
|
||||||
if (object.src) {
|
if (object.src) {
|
||||||
object.src = create(object.src)
|
object.src = create(object.src, `src_${id}`)
|
||||||
|
object.crossOrigin = 'anonymous'
|
||||||
}
|
}
|
||||||
if (object.fill?.source) {
|
if (object.fill?.source) {
|
||||||
object.fill.source = create(object.fill.source)
|
object.fill.source = create(object.fill.source, `fillsource_${id}`)
|
||||||
}
|
}
|
||||||
if (object.info?.fill?.source) {
|
if (object.info?.fill?.source) {
|
||||||
object.info.fill.source = create(object.info.fill.source)
|
object.info.fill.source = create(object.info.fill.source, `infofillsource_${id}`)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return { canvas: JSON.stringify(canvas), images }
|
return { canvas: JSON.stringify(canvas), images }
|
||||||
}
|
}
|
||||||
/** 处理JSON为正常画布 */
|
/** 处理JSON为正常画布 */
|
||||||
processCanvasDisUrlJSON(obj: { canvas: string, images: Object[] }) {
|
processCanvasDisUrlJSON(obj: { canvas: string, images: Object }) {
|
||||||
var json = obj.canvas;
|
var json = obj.canvas;
|
||||||
const images = obj.images || []
|
const images = obj.images || {}
|
||||||
images.forEach((v: any) => json = json.replace(new RegExp(v.index), v.url))
|
for (const key in images) {
|
||||||
return JSON.parse(json)
|
json = json.replace(new RegExp(key), images[key])
|
||||||
|
}
|
||||||
|
return json
|
||||||
}
|
}
|
||||||
dispose() {
|
dispose() {
|
||||||
this.animationManager?.dispose()
|
this.animationManager?.dispose()
|
||||||
|
|||||||
@@ -151,6 +151,37 @@ export class LayerManager {
|
|||||||
if (isActive) this.setActiveID(emptyObject.info.id, false)
|
if (isActive) this.setActiveID(emptyObject.info.id, false)
|
||||||
return emptyObject
|
return emptyObject
|
||||||
}
|
}
|
||||||
|
/** 创建组图层 */
|
||||||
|
createGroupLayer(options?: any, isRecord = true, isActive = false) {
|
||||||
|
const child = options?.child || []
|
||||||
|
delete options.child
|
||||||
|
const groupObject = new fabric.Group(child, {
|
||||||
|
// subTargetCheck: true, // 关键:检测子对象
|
||||||
|
// interactive: true, // 启用交互
|
||||||
|
// hasControls: true,
|
||||||
|
// hasBorders: true,
|
||||||
|
|
||||||
|
// // 子对象样式
|
||||||
|
// cornerColor: 'blue',
|
||||||
|
// cornerSize: 8,
|
||||||
|
// borderColor: 'green',
|
||||||
|
|
||||||
|
// // 允许子对象独立变换
|
||||||
|
// lockScalingX: false,
|
||||||
|
// lockScalingY: false,
|
||||||
|
// lockRotation: false,
|
||||||
|
info: {
|
||||||
|
id: createId("group"),
|
||||||
|
name: '组图层',
|
||||||
|
...(options?.info || {}),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// this.setLayerPosition(groupObject)
|
||||||
|
this.canvasManager.add(groupObject, isRecord)
|
||||||
|
if (isActive) this.setActiveID(groupObject.info.id, false)
|
||||||
|
return groupObject
|
||||||
|
}
|
||||||
|
|
||||||
/** 创建文本图层 */
|
/** 创建文本图层 */
|
||||||
async createTextLayer(text: string, options?: any) {
|
async createTextLayer(text: string, options?: any) {
|
||||||
const textObject = new fabric.IText(text, {
|
const textObject = new fabric.IText(text, {
|
||||||
@@ -337,7 +368,7 @@ export class LayerManager {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
resolve(img)
|
resolve(img)
|
||||||
})
|
}, { crossOrigin: 'anonymous' })
|
||||||
})
|
})
|
||||||
// console.log(mergedImage)
|
// console.log(mergedImage)
|
||||||
const index = this.canvasManager.getObjects().indexOf(targetLayer);
|
const index = this.canvasManager.getObjects().indexOf(targetLayer);
|
||||||
|
|||||||
@@ -53,7 +53,7 @@
|
|||||||
const isSubord = computed(() => nodes.value.some((v) => v.data.superiorID === props.node.id))
|
const isSubord = computed(() => nodes.value.some((v) => v.data.superiorID === props.node.id))
|
||||||
const tier = computed(() => Number(props.node?.data?.tier || 0))
|
const tier = computed(() => Number(props.node?.data?.tier || 0))
|
||||||
//只有3d模型才有三级菜单,目前三级菜单内容少直接禁用按钮
|
//只有3d模型才有三级菜单,目前三级菜单内容少直接禁用按钮
|
||||||
const isAdd3d = computed(() => (tier.value === 2 && props.node?.data?.superiorNodeType === NODE_DATATYPE.TO_3D_MODEL) || tier.value != 2)
|
const isAdd3d = computed(() => (tier.value === 2 && props.node?.data?.superiorNodeType === NODE_DATATYPE.TO_3D_MODEL) || props.node?.data?.superiorNodeType !== NODE_DATATYPE.TO_3D_MODEL)
|
||||||
const isReturned = computed(() => {
|
const isReturned = computed(() => {
|
||||||
return (
|
return (
|
||||||
props.node.data.type == NODE_DATATYPE.RESULT_IMAGE &&
|
props.node.data.type == NODE_DATATYPE.RESULT_IMAGE &&
|
||||||
@@ -79,6 +79,7 @@
|
|||||||
props.stateManager.nodeManager.createCardsSelect({
|
props.stateManager.nodeManager.createCardsSelect({
|
||||||
data: { tier: tier_, superiorID: props.node.id, originalImage }
|
data: { tier: tier_, superiorID: props.node.id, originalImage }
|
||||||
})
|
})
|
||||||
|
stateManager.setActiveNodeID('')
|
||||||
}
|
}
|
||||||
const posCenter = computed(() => {
|
const posCenter = computed(() => {
|
||||||
const arr = [NODE_DATATYPE.RESULT_IMAGE]
|
const arr = [NODE_DATATYPE.RESULT_IMAGE]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 高级工具选择 -->
|
<!-- 高级工具选择 -->
|
||||||
<div class="cards-select">
|
<div class="cards-select">
|
||||||
<div v-for="v in list" :key="v.type" @click="onClickItem(v)" v-show="v.tier === tier">
|
<div v-for="v in (node.data?.secondaryMenu?.selectList || list)" :key="v.type" @click="onClickItem(v)" v-show="v.tier === tier">
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<svg-icon :name="v.type + '-2'" size="15" size-unit="px" />
|
<svg-icon :name="v.type + '-2'" size="15" size-unit="px" />
|
||||||
</span>
|
</span>
|
||||||
@@ -28,7 +28,22 @@
|
|||||||
{
|
{
|
||||||
tier: NODE_DATATIER.SURFACE_EDIT,
|
tier: NODE_DATATIER.SURFACE_EDIT,
|
||||||
type: NODE_DATATYPE.SURFACE_EDIT,
|
type: NODE_DATATYPE.SURFACE_EDIT,
|
||||||
title: 'Surface Edit'
|
title: 'Surface Edit',
|
||||||
|
secondaryMenu: {
|
||||||
|
title: 'Surface Edit',
|
||||||
|
icon: NODE_DATATYPE.SURFACE_EDIT,
|
||||||
|
selectList: [
|
||||||
|
{
|
||||||
|
tier: NODE_DATATIER.CANVAS_MODE,
|
||||||
|
type: NODE_DATATYPE.CANVAS_MODE,
|
||||||
|
title: 'Surface Edit (Canvas)',
|
||||||
|
},{
|
||||||
|
tier: NODE_DATATIER.Fast_MODE,
|
||||||
|
type: NODE_DATATYPE.Fast_MODE,
|
||||||
|
title: 'Surface Edit',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tier: NODE_DATATIER.SCENE_COMPOSITION,
|
tier: NODE_DATATIER.SCENE_COMPOSITION,
|
||||||
@@ -55,15 +70,27 @@
|
|||||||
const id = props.node.id
|
const id = props.node.id
|
||||||
if (!id) return
|
if (!id) return
|
||||||
stateManager.deleteNode(id)
|
stateManager.deleteNode(id)
|
||||||
const superiorID = props.node.data.superiorID
|
console.log(props.node)
|
||||||
nodeManager.createCardNode({
|
if(v.secondaryMenu){
|
||||||
data: {
|
nodeManager.createCardsSelect({
|
||||||
tier: v.tier,
|
data: {
|
||||||
type: v.type,
|
tier: props.node.data?.tier,
|
||||||
superiorID,
|
superiorID: props.node.data?.superiorID,
|
||||||
originalImage: props.node.data?.originalImage,
|
originalImage: props.node.data?.originalImage,
|
||||||
}
|
secondaryMenu: v.secondaryMenu
|
||||||
})
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
const superiorID = props.node.data.superiorID
|
||||||
|
nodeManager.createCardNode({
|
||||||
|
data: {
|
||||||
|
tier: v.tier,
|
||||||
|
type: v.type,
|
||||||
|
superiorID,
|
||||||
|
originalImage: props.node.data?.originalImage,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({})
|
defineExpose({})
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 画布编辑印花 -->
|
||||||
|
<div class="fast-mode">
|
||||||
|
<p class="label">Output</p>
|
||||||
|
<div class="imgBox">
|
||||||
|
<img :src="data.url" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, inject, useAttrs } from 'vue'
|
||||||
|
import myEvent from '@/utils/myEvent'
|
||||||
|
import { getCurrentTime } from '../../../../tools/tools.ts'
|
||||||
|
import { NODE_DATATIER } from '../../../tools/index.d'
|
||||||
|
const attrs = useAttrs()
|
||||||
|
const data = reactive({
|
||||||
|
url: attrs.node?.data?.originalImage,
|
||||||
|
})
|
||||||
|
const stateManager = inject('stateManager') as any
|
||||||
|
const nodeManager = inject('nodeManager') as any
|
||||||
|
const eventManager = inject('eventManager') as any
|
||||||
|
const getApiData = ()=>{
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const opCanvas = ()=>{
|
||||||
|
const data = {
|
||||||
|
url:attrs?.node?.data?.originalImage,
|
||||||
|
canvasId: attrs?.node?.data?.canvasId || null,
|
||||||
|
sketchId: stateManager.sketchId.value,
|
||||||
|
onWorkbench:(options)=>{
|
||||||
|
let taskId = Date.now()
|
||||||
|
let workbenchData = {
|
||||||
|
createTime: getCurrentTime(),
|
||||||
|
status: 'RETURNED',
|
||||||
|
taskId: taskId + '',
|
||||||
|
...options,
|
||||||
|
}
|
||||||
|
const subordNodes = stateManager.getSubordNodes(attrs.node.id)
|
||||||
|
|
||||||
|
nodeManager.createResultNode({
|
||||||
|
data: {
|
||||||
|
superiorID: attrs.node.id,
|
||||||
|
superiorNodeType: attrs.node?.data?.type,
|
||||||
|
createIndexPosition: 0 + subordNodes.length,
|
||||||
|
tier: NODE_DATATIER.RESULT_IMAGE,
|
||||||
|
isActive: subordNodes.length == 0,
|
||||||
|
data: {
|
||||||
|
imageProcessTasks:[workbenchData],
|
||||||
|
selectTaskId:taskId + '',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
eventManager.removeEvents()
|
||||||
|
myEvent.emit('openDepthCanvas', data)
|
||||||
|
}
|
||||||
|
defineExpose({ data, getApiData, opCanvas })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.fast-mode {
|
||||||
|
margin-bottom: 40px;
|
||||||
|
> .imgBox{
|
||||||
|
width: 217px;
|
||||||
|
height: 217px;
|
||||||
|
padding: 7.5px;
|
||||||
|
> img{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -2,13 +2,13 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<svg-icon
|
<svg-icon
|
||||||
v-if="!currentComponent?.hideIcon"
|
v-if="attrs.node?.data?.secondaryMenu?.icon || !currentComponent?.hideIcon"
|
||||||
:name="currentComponent?.type"
|
:name="attrs.node?.data?.secondaryMenu?.icon || currentComponent?.type"
|
||||||
color="#fff"
|
color="#fff"
|
||||||
size="16"
|
size="16"
|
||||||
size-unit="px"
|
size-unit="px"
|
||||||
/>
|
/>
|
||||||
<span>{{ currentComponent?.title }}</span>
|
<span>{{ attrs.node?.data?.secondaryMenu?.title ||currentComponent?.title }}</span>
|
||||||
<div class="delete-icon" @click="onDeleteClick">
|
<div class="delete-icon" @click="onDeleteClick">
|
||||||
<SvgIcon name="flowDelete" size="16" size-unit="px" color="#fff" />
|
<SvgIcon name="flowDelete" size="16" size-unit="px" color="#fff" />
|
||||||
</div>
|
</div>
|
||||||
@@ -22,6 +22,12 @@
|
|||||||
<span>Generate</span>
|
<span>Generate</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="footer canvasEdit" @mousedown.stop v-if="currentComponent?.showCanvasEdit">
|
||||||
|
<button @click="currentComponent?.on()">
|
||||||
|
<svg-icon name="xingxing" size="16" size-unit="px" />
|
||||||
|
<span>Edit</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -31,6 +37,7 @@
|
|||||||
import CardsSelect from './cards-select.vue'
|
import CardsSelect from './cards-select.vue'
|
||||||
import ToRealStyle from './to-real-style.vue'
|
import ToRealStyle from './to-real-style.vue'
|
||||||
import SurfaceEdit from './surface-edit.vue'
|
import SurfaceEdit from './surface-edit.vue'
|
||||||
|
import FastMode from './fast-mode.vue'
|
||||||
import SceneComposition from './scene-composition.vue'
|
import SceneComposition from './scene-composition.vue'
|
||||||
import ColorPalette from './color-palette.vue'
|
import ColorPalette from './color-palette.vue'
|
||||||
import To3View from './to-3view.vue'
|
import To3View from './to-3view.vue'
|
||||||
@@ -41,6 +48,8 @@
|
|||||||
// import ToVideo from './to-video.vue'
|
// import ToVideo from './to-video.vue'
|
||||||
// import AddPrint from './add-print.vue'
|
// import AddPrint from './add-print.vue'
|
||||||
// import ToCAD from './to-cad.vue'
|
// import ToCAD from './to-cad.vue'
|
||||||
|
const attrs = useAttrs()
|
||||||
|
const componentRef = ref(null)
|
||||||
const components = [
|
const components = [
|
||||||
{
|
{
|
||||||
tier: NODE_DATATIER.CARDS_SELECT,
|
tier: NODE_DATATIER.CARDS_SELECT,
|
||||||
@@ -58,12 +67,23 @@
|
|||||||
api: toRealStyleApi
|
api: toRealStyleApi
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tier: NODE_DATATIER.SURFACE_EDIT,
|
tier: NODE_DATATIER.Fast_MODE,
|
||||||
type: NODE_DATATYPE.SURFACE_EDIT,
|
type: NODE_DATATYPE.Fast_MODE,
|
||||||
title: 'Surface Edit',
|
title: 'Surface Edit',
|
||||||
component: SurfaceEdit,
|
component: SurfaceEdit,
|
||||||
api: sketchAddPrintApi
|
api: sketchAddPrintApi
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
tier: NODE_DATATIER.CANVAS_MODE,
|
||||||
|
type: NODE_DATATYPE.CANVAS_MODE,
|
||||||
|
title: 'Surface Edit (Canvas)',
|
||||||
|
component: FastMode,
|
||||||
|
hideFooter: true,
|
||||||
|
showCanvasEdit: true,
|
||||||
|
on: ()=>{
|
||||||
|
componentRef.value?.opCanvas()
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
tier: NODE_DATATIER.SCENE_COMPOSITION,
|
tier: NODE_DATATIER.SCENE_COMPOSITION,
|
||||||
type: NODE_DATATYPE.SCENE_COMPOSITION,
|
type: NODE_DATATYPE.SCENE_COMPOSITION,
|
||||||
@@ -117,11 +137,9 @@
|
|||||||
default: () => ({})
|
default: () => ({})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const attrs = useAttrs()
|
|
||||||
const currentComponent = computed(() => {
|
const currentComponent = computed(() => {
|
||||||
return components.find((item) => item.type === props.type)
|
return components.find((item) => item.type === props.type)
|
||||||
})
|
})
|
||||||
const componentRef = ref(null)
|
|
||||||
|
|
||||||
const onGenerateClick = async () => {
|
const onGenerateClick = async () => {
|
||||||
const data = componentRef.value?.getApiData?.() || {}
|
const data = componentRef.value?.getApiData?.() || {}
|
||||||
@@ -140,13 +158,16 @@
|
|||||||
}) || []
|
}) || []
|
||||||
// const taskList = [{taskId:'123'}]
|
// const taskList = [{taskId:'123'}]
|
||||||
// if (!subordNode) {
|
// if (!subordNode) {
|
||||||
|
|
||||||
|
//如果是添加印花的结果就作为一级节点可以再次选择添加印花或者生成真实图
|
||||||
|
let tier = (NODE_DATATIER.Fast_MODE == currentComponent.value.tier && currentComponent.value.type == NODE_DATATYPE.Fast_MODE)?0:currentComponent.value.tier
|
||||||
taskList.forEach((item,index) => {
|
taskList.forEach((item,index) => {
|
||||||
nodeManager.createResultNode({
|
nodeManager.createResultNode({
|
||||||
data: {
|
data: {
|
||||||
superiorID: attrs.node.id,
|
superiorID: attrs.node.id,
|
||||||
superiorNodeType: attrs.node?.data?.type,
|
superiorNodeType: attrs.node?.data?.type,
|
||||||
createIndexPosition: index + subordNodes.length,
|
createIndexPosition: index + subordNodes.length,
|
||||||
tier: currentComponent.value.tier,
|
tier: tier,
|
||||||
isActive: index == 0 && subordNodes.length == 0,
|
isActive: index == 0 && subordNodes.length == 0,
|
||||||
data: {
|
data: {
|
||||||
imageProcessTasks:[item],
|
imageProcessTasks:[item],
|
||||||
@@ -251,6 +272,7 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-family: SemiBold;
|
font-family: SemiBold;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
@@ -260,6 +282,12 @@
|
|||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.canvasEdit{
|
||||||
|
> button{
|
||||||
|
margin: 0 8px;
|
||||||
|
width: 201px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<div class="result-image"
|
<div class="result-image"
|
||||||
v-for="(item, i) in data.imageProcessTasks"
|
v-for="(item, i) in data.imageProcessTasks"
|
||||||
:key="item.taskId"
|
:key="item.taskId"
|
||||||
:class="{'active': config.isActive}"
|
:class="{'active': node.id == stateManager.activeNodeID.value}"
|
||||||
@click="setSelectTaskId(item.taskId)"
|
@click="setSelectTaskId(item.taskId)"
|
||||||
>
|
>
|
||||||
<div class="header" v-if="item.status == 'RETURNED'" v-show="showHeader && config.isActive" @mousedown.stop>
|
<div class="header" v-if="item.status == 'RETURNED'" v-show="showHeader && node.id == stateManager.activeNodeID.value" @mousedown.stop>
|
||||||
<span class="icon">
|
<span class="icon">
|
||||||
<svg-icon name="chat-compose" size="20" size-unit="px" />
|
<svg-icon name="chat-compose" size="20" size-unit="px" />
|
||||||
</span>
|
</span>
|
||||||
@@ -23,7 +23,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<img
|
<img
|
||||||
v-loadimg="false"
|
|
||||||
class="image"
|
class="image"
|
||||||
v-if="item.status == 'RETURNED'"
|
v-if="item.status == 'RETURNED'"
|
||||||
:src="item?.url"
|
:src="item?.url"
|
||||||
@@ -59,11 +58,10 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import myEvent from '@/utils/myEvent'
|
import myEvent from '@/utils/myEvent'
|
||||||
import { downloadImage, base64Tofile } from '../../../tools/tools'
|
import { downloadImage } from '../../../tools/tools'
|
||||||
import { reactive, ref, onBeforeUnmount, useAttrs, inject, watch, computed, onMounted } from 'vue'
|
import { reactive, ref, onBeforeUnmount, useAttrs, inject, watch, computed, onMounted } from 'vue'
|
||||||
import HighlightAdmin from '@/components/highlightAdmin.vue'
|
import HighlightAdmin from '@/components/highlightAdmin.vue'
|
||||||
import { NODE_DATATYPE } from '../../tools/index.d'
|
import { NODE_DATATYPE } from '../../tools/index.d'
|
||||||
import { uploadImage } from '@/api/upload'
|
|
||||||
const openImagePreview = inject('openImagePreview') as (url: string) => void
|
const openImagePreview = inject('openImagePreview') as (url: string) => void
|
||||||
const openThreeModelPreview = inject('openThreeModelPreview') as (url: string) => void
|
const openThreeModelPreview = inject('openThreeModelPreview') as (url: string) => void
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -88,7 +86,8 @@
|
|||||||
'update-data'
|
'update-data'
|
||||||
])
|
])
|
||||||
// const attrs = useAttrs()
|
// const attrs = useAttrs()
|
||||||
const showHeader = ref(!!props.node?.data?.isHeader)
|
const showHeader = ref(true)
|
||||||
|
// const showHeader = ref(!!props.node?.data?.isHeader)
|
||||||
const showMenu = ref(false)
|
const showMenu = ref(false)
|
||||||
const clickTaskId = ref('')
|
const clickTaskId = ref('')
|
||||||
const generateManager = inject('generateManager') as any
|
const generateManager = inject('generateManager') as any
|
||||||
@@ -183,7 +182,7 @@
|
|||||||
])
|
])
|
||||||
const onPreview = (item: any) => {
|
const onPreview = (item: any) => {
|
||||||
if(data.superiorNodeType == NODE_DATATYPE.TO_3D_MODEL){
|
if(data.superiorNodeType == NODE_DATATYPE.TO_3D_MODEL){
|
||||||
openThreeModelPreview({url:item?.glbPath,glbInfoObj:item?.glbInfoObj})
|
openThreeModelPreview({glbPath:item?.glbPath,glbInfoObj:item?.glbInfoObj})
|
||||||
}else{
|
}else{
|
||||||
openImagePreview(item.url)
|
openImagePreview(item.url)
|
||||||
}
|
}
|
||||||
@@ -205,25 +204,19 @@
|
|||||||
eventManager.registerEvents()
|
eventManager.registerEvents()
|
||||||
}
|
}
|
||||||
const depthCanvasWorkbench = (options)=>{
|
const depthCanvasWorkbench = (options)=>{
|
||||||
console.log(options)
|
data.imageProcessTasks.forEach((item) => {
|
||||||
// 1. 提取 MIME 类型和 Base64 数据
|
if(item.taskId == options.taskId){
|
||||||
const file = base64Tofile(options.url,'image.png')
|
item.url = options.url
|
||||||
const formData = new FormData()
|
item.canvasId = options.canvasId || null
|
||||||
formData.append('file', file)
|
}
|
||||||
uploadImage(formData).then((res) => {
|
|
||||||
data.imageProcessTasks.forEach((item) => {
|
|
||||||
if(item.taskId == options.taskId){
|
|
||||||
item.url = res
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const onEdit = (item: any) => {
|
const onEdit = (item: any) => {
|
||||||
const data = {
|
const data = {
|
||||||
url:item.url,
|
url:item.url,
|
||||||
id: item.taskId,
|
canvasId: item?.canvasId || null,
|
||||||
|
sketchId: stateManager.sketchId.value,
|
||||||
onWorkbench:(options)=>{
|
onWorkbench:(options)=>{
|
||||||
let workbenchData = {
|
let workbenchData = {
|
||||||
...item,
|
...item,
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ let data = reactive({
|
|||||||
|
|
||||||
const modelRef = ref(null)
|
const modelRef = ref(null)
|
||||||
onMounted(()=>{
|
onMounted(()=>{
|
||||||
console.log(props?.currentData?.url)
|
if(props?.currentData?.glbPath)modelRef.value.open(props?.currentData?.glbPath)
|
||||||
if(props?.currentData?.url)modelRef.value.open(props?.currentData?.url)
|
|
||||||
})
|
})
|
||||||
onUnmounted(()=>{
|
onUnmounted(()=>{
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
import FullscreenDialog from '../components/fullscreen-dialog.vue'
|
import FullscreenDialog from '../components/fullscreen-dialog.vue'
|
||||||
import flowCanvas from './flow-canvas.vue'
|
import flowCanvas from './flow-canvas.vue'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { getSketchFlowCanvas, putSketchFlowCanvas } from '@/api/flow-canvas'
|
import { getSketchFlowCanvas } from '@/api/flow-canvas'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false)
|
||||||
|
|||||||
@@ -63,8 +63,7 @@ export class StateManager {
|
|||||||
this.mxHistory = ref(50)
|
this.mxHistory = ref(50)
|
||||||
this.historyList = ref([])
|
this.historyList = ref([])
|
||||||
this.historyIndex = ref(0)
|
this.historyIndex = ref(0)
|
||||||
|
this.sketchId = ref(options.sketchId)
|
||||||
this.sketchId = options.sketchId
|
|
||||||
this.saveCanvasTimeInterval = 6000
|
this.saveCanvasTimeInterval = 6000
|
||||||
this.saveCanvasTime = null
|
this.saveCanvasTime = null
|
||||||
|
|
||||||
@@ -188,12 +187,12 @@ export class StateManager {
|
|||||||
}
|
}
|
||||||
/** 画布数据存储 */
|
/** 画布数据存储 */
|
||||||
async exportFlow (time:number = 0){
|
async exportFlow (time:number = 0){
|
||||||
if(!this.sketchId)return
|
if(!this.sketchId.value)return
|
||||||
clearTimeout(this.saveCanvasTime)
|
clearTimeout(this.saveCanvasTime)
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
this.saveCanvasTime = setTimeout(()=>{
|
this.saveCanvasTime = setTimeout(()=>{
|
||||||
putSketchFlowCanvas({
|
putSketchFlowCanvas({
|
||||||
id: this.sketchId,
|
id: this.sketchId.value,
|
||||||
canvasData: JSON.stringify(this.nodes.value) }).then(() => {
|
canvasData: JSON.stringify(this.nodes.value) }).then(() => {
|
||||||
resolve(true)
|
resolve(true)
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ export const NODE_DATATYPE = {
|
|||||||
CARDS_SELECT: 'cards-select',
|
CARDS_SELECT: 'cards-select',
|
||||||
TO_REAL_STYLE: 'to-real-style',
|
TO_REAL_STYLE: 'to-real-style',
|
||||||
SURFACE_EDIT: 'surface-edit',
|
SURFACE_EDIT: 'surface-edit',
|
||||||
|
CANVAS_MODE: 'canvas-mode',
|
||||||
|
Fast_MODE: 'fast-mode',
|
||||||
SCENE_COMPOSITION: 'scene-composition',
|
SCENE_COMPOSITION: 'scene-composition',
|
||||||
COLOR_PALETTE: 'color-palette',
|
COLOR_PALETTE: 'color-palette',
|
||||||
TO_3D_MODEL: 'to-3d-model',
|
TO_3D_MODEL: 'to-3d-model',
|
||||||
@@ -38,6 +40,8 @@ export const NODE_DATATIER = {
|
|||||||
CARDS_SELECT: 0,
|
CARDS_SELECT: 0,
|
||||||
TO_REAL_STYLE: 1,
|
TO_REAL_STYLE: 1,
|
||||||
SURFACE_EDIT: 1,
|
SURFACE_EDIT: 1,
|
||||||
|
CANVAS_MODE: 1,
|
||||||
|
Fast_MODE: 1,
|
||||||
SCENE_COMPOSITION: 2,
|
SCENE_COMPOSITION: 2,
|
||||||
COLOR_PALETTE: 2,
|
COLOR_PALETTE: 2,
|
||||||
TO_3D_MODEL: 2,
|
TO_3D_MODEL: 2,
|
||||||
|
|||||||
@@ -77,4 +77,16 @@ export const base64Tofile = (base64: string,name: string) => {
|
|||||||
// 4. 创建 File 对象(可选)
|
// 4. 创建 File 对象(可选)
|
||||||
const file = new File([blob], name, { type: mime })
|
const file = new File([blob], name, { type: mime })
|
||||||
return file
|
return file
|
||||||
|
}
|
||||||
|
//获取当前时间2026-03-20 11:38:29
|
||||||
|
export const getCurrentTime = () => {
|
||||||
|
const now = new Date()
|
||||||
|
const currentTime =
|
||||||
|
now.getFullYear() + '-' +
|
||||||
|
String(now.getMonth() + 1).padStart(2, '0') + '-' +
|
||||||
|
String(now.getDate()).padStart(2, '0') + ' ' +
|
||||||
|
String(now.getHours()).padStart(2, '0') + ':' +
|
||||||
|
String(now.getMinutes()).padStart(2, '0') + ':' +
|
||||||
|
String(now.getSeconds()).padStart(2, '0')
|
||||||
|
return currentTime
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
import { computed, onMounted } from 'vue'
|
import { computed, onMounted } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const url = ''
|
const url = 'https://www.minio-api.aida.com.hk/fida-test/furniture/sketches/1a48ed3a-1faa-4fcd-bf07-765dba1702c5.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=admin%2F20260320%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260320T020948Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=7dc192bac887bce7b02c99d7037c08d9d684310f00add9b0e63b74b36ee63d37'
|
||||||
const openCanvas = () => {
|
const openCanvas = () => {
|
||||||
myEvent.emit('openFlowCanvas', { url })
|
myEvent.emit('openFlowCanvas', { url })
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user