Merge pull request #10860 from dataease/pr@dev-v2_copilot_index

Pr@dev v2 copilot index
This commit is contained in:
dataeaseShu 2024-07-09 16:43:04 +08:00 committed by GitHub
commit 4d3958c3af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 1171 additions and 1 deletions

View File

@ -202,6 +202,10 @@ export const listFieldsWithPermissions = (datasetId: number) => {
return request.get({ url: '/datasetField/listWithPermissions/' + datasetId })
}
export const copilotFields = (datasetId: number) => {
return request.post({ url: '/datasetField/copilotFields/' + datasetId })
}
export const saveRowPermission = (data = {}) => {
return request.post({ url: '/dataset/rowPermissions/save', data })
}
@ -299,3 +303,21 @@ export const getFieldTree = async (data): Promise<IResponse> => {
return res?.data
})
}
export const copilotChat = async (data): Promise<IResponse> => {
return request.post({ url: '/copilot/chat', data }).then(res => {
return res?.data
})
}
export const getListCopilot = async (): Promise<IResponse> => {
return request.post({ url: '/copilot/getList' }).then(res => {
return res?.data
})
}
export const clearAllCopilot = async (): Promise<IResponse> => {
return request.post({ url: '/copilot/clearAll' }).then(res => {
return res?.data
})
}

View File

@ -0,0 +1,14 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.1716 1.68834C20.6753 1.53273 21.0458 2.16193 20.6652 2.52691L12.2658 10.5836C11.0058 11.7921 9.32754 12.4668 7.5817 12.4668C5.68044 12.4668 3.8669 11.667 2.58487 10.263L1.45879 9.02985C1.33225 8.90313 1.24137 8.74527 1.19534 8.5722C1.14931 8.39913 1.14974 8.21698 1.19661 8.04413C1.24347 7.87129 1.3351 7.71386 1.46225 7.58775C1.5894 7.46164 1.74757 7.3713 1.92079 7.32585L20.1716 1.68834Z" fill="url(#paint0_linear_15885_149847)"/>
<path d="M12 16.1851C12 14.2766 12.7377 12.4419 14.0588 11.0646L21.4664 3.34177C21.8268 2.96601 22.4499 3.32266 22.3084 3.82374L17.143 22.1182C17.0971 22.291 17.0064 22.4487 16.8801 22.5754C16.7538 22.7021 16.5964 22.7932 16.4237 22.8397C16.251 22.8862 16.0691 22.8864 15.8964 22.8402C15.7236 22.794 15.566 22.7031 15.4395 22.5767L14.4439 21.6791C12.8881 20.2764 12 18.2799 12 16.1851Z" fill="url(#paint1_linear_15885_149847)"/>
<defs>
<linearGradient id="paint0_linear_15885_149847" x1="22.3289" y1="13.1532" x2="1.16113" y2="13.1532" gradientUnits="userSpaceOnUse">
<stop stop-color="#9258F7"/>
<stop offset="1" stop-color="#3370FF"/>
</linearGradient>
<linearGradient id="paint1_linear_15885_149847" x1="22.3289" y1="13.1532" x2="1.16113" y2="13.1532" gradientUnits="userSpaceOnUse">
<stop stop-color="#9258F7"/>
<stop offset="1" stop-color="#3370FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20.1716 1.68834C20.6753 1.53273 21.0458 2.16193 20.6652 2.52691L12.2658 10.5836C11.0058 11.7921 9.32754 12.4668 7.5817 12.4668C5.68044 12.4668 3.8669 11.667 2.58487 10.263L1.45879 9.02985C1.33225 8.90313 1.24137 8.74527 1.19534 8.5722C1.14931 8.39913 1.14974 8.21698 1.19661 8.04413C1.24347 7.87129 1.3351 7.71386 1.46225 7.58775C1.5894 7.46164 1.74757 7.3713 1.92079 7.32585L20.1716 1.68834Z" fill="#BBBFC4"/>
<path d="M12 16.1851C12 14.2766 12.7377 12.4419 14.0588 11.0646L21.4664 3.34177C21.8268 2.96601 22.4499 3.32266 22.3084 3.82374L17.143 22.1182C17.0971 22.291 17.0064 22.4487 16.8801 22.5754C16.7538 22.7021 16.5964 22.7932 16.4237 22.8397C16.251 22.8862 16.0691 22.8864 15.8964 22.8402C15.7236 22.794 15.566 22.7031 15.4395 22.5767L14.4439 21.6791C12.8881 20.2764 12 18.2799 12 16.1851Z" fill="#BBBFC4"/>
</svg>

After

Width:  |  Height:  |  Size: 928 B

View 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="M5.66668 17.3333V11.697C5.66668 11.312 5.98648 11 6.38097 11H9.33335V6.03508C9.33335 5.64751 9.67446 5.33333 10.0953 5.33333H13.9048C14.3256 5.33333 14.6667 5.64751 14.6667 6.03508V9.33333H17.6191C18.0136 9.33333 18.3333 9.63181 18.3333 10V17.3333H18.9999C19.184 17.3333 19.3332 17.4826 19.3332 17.6667V18.3333C19.3332 18.5174 19.184 18.6667 18.9999 18.6667H4.9999C4.8158 18.6667 4.66656 18.5174 4.66656 18.3333V17.6667C4.66656 17.4826 4.8158 17.3333 4.9999 17.3333H5.66668ZM17 17.3333V10.6667H14.6667V17.3333H17ZM13.3333 17.3333V6.66666H10.6667V17.3333H13.3333ZM9.33335 17.3333V12.3333H7.00001V17.3333H9.33335Z" fill="#646A73"/>
</svg>

After

Width:  |  Height:  |  Size: 742 B

View 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="M18 16.3333V18C18 18.3682 17.7015 18.6667 17.3333 18.6667H6.66667C6.29848 18.6667 6 18.3682 6 18V16.3333C6 16.1492 6.14924 16 6.33333 16H7C7.18409 16 7.33333 16.1492 7.33333 16.3333V17.3333H16.6667V16.3333C16.6667 16.1492 16.8159 16 17 16H17.6667C17.8508 16 18 16.1492 18 16.3333ZM12.6667 13.3571L14.6736 11.3502C14.8038 11.22 15.0149 11.22 15.1451 11.3502L15.6165 11.8216C15.7466 11.9517 15.7466 12.1628 15.6165 12.293L12.3166 15.5928C12.2515 15.6579 12.1662 15.6904 12.0809 15.6904C11.9956 15.6904 11.9103 15.6579 11.8452 15.5928L8.54539 12.293C8.41521 12.1628 8.41521 11.9517 8.54539 11.8216L9.01679 11.3502C9.14697 11.22 9.35802 11.22 9.4882 11.3502L11.3333 13.1953V5.99999C11.3333 5.81589 11.4826 5.66666 11.6667 5.66666H12.3333C12.5174 5.66666 12.6667 5.81589 12.6667 5.99999V13.3571Z" fill="#646A73"/>
</svg>

After

Width:  |  Height:  |  Size: 921 B

View 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 fill-rule="evenodd" clip-rule="evenodd" d="M5.68833 5.68831C5.91562 5.46102 6.2239 5.33333 6.54534 5.33333H17.4547C17.7761 5.33333 18.0844 5.46102 18.3117 5.68831C18.539 5.91561 18.6667 6.22389 18.6667 6.54533V17.4547C18.6667 17.7761 18.539 18.0844 18.3117 18.3117C18.0844 18.539 17.7761 18.6667 17.4547 18.6667H6.54534C5.87601 18.6667 5.33334 18.124 5.33334 17.4547V6.54533C5.33334 6.22389 5.46104 5.91561 5.68833 5.68831ZM6.66668 10.6667V13.3333H9.33334V10.6667H6.66668ZM6.66668 14.6667V17.3333H9.33334V14.6667H6.66668ZM10.6667 17.3333H13.3333V14.6667H10.6667V17.3333ZM14.6667 17.3333H17.3333V14.6667H14.6667V17.3333ZM17.3333 13.3333V10.6667H14.6667V13.3333H17.3333ZM13.3333 10.6667H10.6667V13.3333H13.3333V10.6667ZM17.3333 6.66666H6.66668V9.33333H17.3333V6.66666Z" fill="#646A73"/>
</svg>

After

Width:  |  Height:  |  Size: 894 B

View File

@ -0,0 +1,92 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_15894_331428)">
<g filter="url(#filter0_i_15894_331428)">
<path d="M19.9675 18.3601C20.7649 17.0162 21.2214 15.455 21.2214 13.7897C21.2214 12.2793 20.8459 10.8547 20.1812 9.6001L20.6152 9.6001C21.9543 9.6001 23.0399 10.6611 23.0399 11.97V15.9902C23.0399 17.2991 21.9543 18.3601 20.6152 18.3601H19.9675Z" fill="url(#paint0_linear_15894_331428)"/>
<path d="M19.6859 18.3601C20.5068 17.0247 20.9789 15.461 20.9789 13.7897C20.9789 12.2747 20.5911 10.8483 19.9071 9.6001L19.6799 9.6001V18.3601H19.6859Z" fill="url(#paint1_linear_15894_331428)"/>
</g>
<g filter="url(#filter1_i_15894_331428)">
<path d="M3.81869 9.6001H2.89975C1.82844 9.6001 0.959961 10.4489 0.959961 11.496V16.4642C0.959961 17.5113 1.82844 18.3601 2.89975 18.3601H4.03243C3.23503 17.0162 2.77852 15.455 2.77852 13.7897C2.77852 12.2793 3.15399 10.8547 3.81869 9.6001Z" fill="url(#paint2_linear_15894_331428)"/>
<path d="M4.09279 9.6001C3.40884 10.8483 3.02099 12.2747 3.02099 13.7897C3.02099 15.461 3.49308 17.0247 4.31403 18.3601H4.31996V9.6001L4.09279 9.6001Z" fill="url(#paint3_linear_15894_331428)"/>
</g>
<g filter="url(#filter2_i_15894_331428)">
<path d="M21 13.783C21 18.7535 16.9706 22.783 12 22.783C7.02944 22.783 3 18.7535 3 13.783C3 8.8124 7.02944 4.78296 12 4.78296C16.9706 4.78296 21 8.8124 21 13.783Z" fill="url(#paint4_radial_15894_331428)"/>
</g>
<rect x="4" y="8.78296" width="16" height="10" rx="5" fill="#1E1A3F"/>
<path d="M4.80005 13.8001C4.80005 11.4805 6.68045 9.6001 9.00005 9.6001H15C17.3196 9.6001 19.2 11.4805 19.2 13.8001C19.2 16.1197 17.3196 18.0001 15 18.0001H9.00005C6.68045 18.0001 4.80005 16.1197 4.80005 13.8001Z" fill="url(#paint5_linear_15894_331428)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.00005 9.58301C6.68045 9.58301 4.80005 11.4634 4.80005 13.783C4.80005 13.8231 4.80061 13.8631 4.80173 13.903C4.86525 11.6389 6.72059 9.82301 9.00005 9.82301H15C17.2795 9.82301 19.1348 11.6389 19.1984 13.903C19.1995 13.8631 19.2 13.8231 19.2 13.783C19.2 11.4634 17.3196 9.58301 15 9.58301H9.00005Z" fill="#0540E5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.00005 18.0001C6.68045 18.0001 4.80005 16.1197 4.80005 13.8001C4.80005 13.76 4.80061 13.72 4.80173 13.6801C4.86525 15.9442 6.72059 17.7601 9.00005 17.7601H15C17.2795 17.7601 19.1348 15.9442 19.1984 13.6801C19.1995 13.72 19.2 13.76 19.2 13.8001C19.2 16.1197 17.3196 18.0001 15 18.0001H9.00005Z" fill="#A30494"/>
<path d="M16.8651 13.448C17.0896 14.5431 16.6905 15.5543 15.6962 15.7657C14.7019 15.977 13.939 15.2128 13.7145 14.1177C13.4901 13.0226 13.8891 12.0113 14.8834 11.8C15.8778 11.5886 16.6407 12.3529 16.8651 13.448Z" fill="white"/>
<path d="M7.12208 13.5587C6.97458 14.6668 7.4432 15.6477 8.44983 15.7892C9.45646 15.9307 10.1642 15.1151 10.3117 14.007C10.4592 12.8989 9.99061 11.9179 8.98398 11.7765C7.97736 11.635 7.26958 12.4506 7.12208 13.5587Z" fill="white"/>
<ellipse cx="12" cy="5.23305" rx="1.02857" ry="0.321429" fill="#1E1A3F"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.6162 5.27319L11.7322 3.76598C11.8191 3.75836 11.9087 3.75439 12 3.75439C12.0914 3.75439 12.181 3.75837 12.268 3.76599L12.3839 5.27318C12.262 5.2888 12.1341 5.29715 12.0025 5.29725H11.9976C11.8659 5.29715 11.7382 5.2888 11.6162 5.27319Z" fill="url(#paint6_linear_15894_331428)"/>
<rect x="10.2" y="1.08008" width="3.6" height="3.6" rx="1.8" fill="url(#paint7_radial_15894_331428)"/>
</g>
<defs>
<filter id="filter0_i_15894_331428" x="19.6799" y="9.6001" width="3.36011" height="8.76001" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="0.5"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_15894_331428"/>
</filter>
<filter id="filter1_i_15894_331428" x="0.959961" y="9.6001" width="3.36011" height="8.76001" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="0.5"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_15894_331428"/>
</filter>
<filter id="filter2_i_15894_331428" x="3" y="4.78296" width="18" height="18" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="0.5"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_15894_331428"/>
</filter>
<linearGradient id="paint0_linear_15894_331428" x1="23.0399" y1="13.9251" x2="21.5373" y2="13.9251" gradientUnits="userSpaceOnUse">
<stop stop-color="#FEFDFF"/>
<stop offset="1" stop-color="#BDBECB"/>
</linearGradient>
<linearGradient id="paint1_linear_15894_331428" x1="23.0399" y1="13.9251" x2="21.5373" y2="13.9251" gradientUnits="userSpaceOnUse">
<stop stop-color="#FEFDFF"/>
<stop offset="1" stop-color="#BDBECB"/>
</linearGradient>
<linearGradient id="paint2_linear_15894_331428" x1="0.959961" y1="13.9251" x2="2.65863" y2="13.9251" gradientUnits="userSpaceOnUse">
<stop stop-color="#FEFDFF"/>
<stop offset="1" stop-color="#BDBECB"/>
</linearGradient>
<linearGradient id="paint3_linear_15894_331428" x1="0.959961" y1="13.9251" x2="2.65863" y2="13.9251" gradientUnits="userSpaceOnUse">
<stop stop-color="#FEFDFF"/>
<stop offset="1" stop-color="#BDBECB"/>
</linearGradient>
<radialGradient id="paint4_radial_15894_331428" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(12 6.3001) rotate(89.3217) scale(16.2911)">
<stop stop-color="#FEFDFF"/>
<stop offset="0.802974" stop-color="#BDBECB"/>
</radialGradient>
<linearGradient id="paint5_linear_15894_331428" x1="12" y1="9.55724" x2="11.4774" y2="17.6234" gradientUnits="userSpaceOnUse">
<stop stop-color="#16C1FB"/>
<stop offset="0.262595" stop-color="#1355F3"/>
<stop offset="1" stop-color="#E500CF"/>
</linearGradient>
<linearGradient id="paint6_linear_15894_331428" x1="12" y1="4.14011" x2="12.0001" y2="5.29725" gradientUnits="userSpaceOnUse">
<stop stop-color="#FEFDFF"/>
<stop offset="0.668336" stop-color="#C6C3CB"/>
</linearGradient>
<radialGradient id="paint7_radial_15894_331428" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(12.0385 1.41951) rotate(90) scale(3.222)">
<stop stop-color="#FEFDFF"/>
<stop offset="0.802974" stop-color="#BDBECB"/>
</radialGradient>
<clipPath id="clip0_15894_331428">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.713135 21.4739V1.80273C0.713135 1.52659 0.936992 1.30273 1.21313 1.30273H2.26008C2.53623 1.30273 2.76008 1.52659 2.76008 1.80273V20.5523H22.5686C22.8447 20.5523 23.0686 20.7761 23.0686 21.0523V22.0992C23.0686 22.3754 22.8447 22.5992 22.5686 22.5992H1.83907C1.54045 22.5992 1.25407 22.4806 1.04291 22.2694C0.83176 22.0583 0.713135 21.7725 0.713135 21.4739Z" fill="#646A73"/>
<path d="M4.19544 18.3911C3.96872 18.2313 3.91539 17.9175 4.07659 17.6918L8.90155 10.9358C8.97757 10.8235 9.07516 10.7274 9.18865 10.6531C9.30213 10.5788 9.42925 10.5278 9.56262 10.5031C9.69599 10.4784 9.83293 10.4804 9.96551 10.5091C10.0981 10.5377 10.2236 10.5925 10.3349 10.6701L15.7191 14.2624L20.9481 8.16625C21.1291 7.95528 21.4474 7.93239 21.6567 8.11531L22.4497 8.80844C22.6562 8.98892 22.6788 9.30208 22.5003 9.51031L16.6806 16.2998C16.5179 16.4883 16.2919 16.611 16.0452 16.6449C15.7984 16.6788 15.5478 16.6215 15.3402 16.4839L10.0275 12.9315L5.77196 18.8941C5.61221 19.118 5.30171 19.1708 5.07694 19.0124L4.19544 18.3911Z" fill="#646A73"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View 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="M5.29008 5.22068L5.29008 5.22068C3.5148 6.99712 2.49805 9.40416 2.49805 11.97C2.49805 17.2342 6.75182 21.5024 12.0004 21.5024C17.249 21.5024 21.5027 17.2342 21.5027 11.97C21.5027 11.6777 21.3866 11.3973 21.1799 11.1906C20.9731 10.9838 20.6928 10.8677 20.4004 10.8677C20.108 10.8677 19.8276 10.9838 19.6209 11.1906C19.4142 11.3973 19.298 11.6777 19.298 11.97C19.298 16.0178 16.0303 19.2977 12.0004 19.2977C7.97048 19.2977 4.70273 16.0178 4.70273 11.97M5.29008 5.22068L4.80039 11.97M5.29008 5.22068C5.39243 5.11826 5.51394 5.037 5.64769 4.98154C5.78145 4.92608 5.92481 4.89751 6.0696 4.89746C6.2144 4.89741 6.35778 4.92588 6.49157 4.98124C6.62536 5.0366 6.74694 5.11777 6.84936 5.22012C6.95178 5.32247 7.03304 5.44398 7.0885 5.57774C7.14396 5.71149 7.17253 5.85485 7.17258 5.99965C7.17263 6.14444 7.14417 6.28782 7.0888 6.42161C7.03344 6.55541 6.95227 6.67698 6.84992 6.7794M5.29008 5.22068L6.919 6.84843M4.70273 11.97H4.80039M4.70273 11.97C4.70273 11.9701 4.70273 11.9702 4.70273 11.9702L4.80039 11.97M4.70273 11.97C4.701 11.0061 4.88979 10.0512 5.25827 9.16045C5.62676 8.26965 6.16768 7.46047 6.84992 6.7794M4.80039 11.97C4.79865 11.0189 4.98493 10.0767 5.34851 9.19778C5.7121 8.31884 6.24582 7.52042 6.919 6.84843M6.84992 6.7794L6.919 6.84843M6.84992 6.7794C6.84995 6.77937 6.84998 6.77935 6.85001 6.77932L6.919 6.84843" fill="#3370FF" stroke="#3370FF" stroke-width="0.195312"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,89 @@
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
const visible = ref(true)
const emits = defineEmits(['confirm'])
const confirm = () => {
emits('confirm')
}
onMounted(() => {
// do
})
</script>
<template>
<el-popover
:visible="visible"
placement="bottom"
popper-class="copilot-popper-tips"
:width="288"
show-arrow
>
<div class="copilot-popper-tips-content">
<p class="title">Copilot 对话分析</p>
<p class="constant">
你好我是 Copilot 对话分析
<br />点击一下开启可视化图表解答模式<br />&nbsp;
</p>
<div class="bottom">
<el-button size="middle" @click="confirm"> 我知道了 </el-button>
</div>
</div>
<template #reference>
<div class="copilot-popper-tips-icon">
<el-icon style="margin: 2px" class="ai-icon">
<Icon name="copilot" />
</el-icon>
</div>
</template>
</el-popover>
</template>
<style lang="less">
.copilot-popper-tips {
z-index: 10001 !important;
padding: 24px !important;
box-shadow: none !important;
border: 0px !important;
background: var(--ed-color-primary) !important;
.ed-popper__arrow::before {
border: 1px solid var(--ed-color-primary) !important;
background: var(--ed-color-primary) !important;
}
}
.copilot-popper-tips-content {
color: rgba(255, 255, 255, 1);
.title {
font-family: PingFang SC;
font-size: 20px;
font-weight: 500;
line-height: 28px;
}
.content {
font-family: PingFang SC;
font-size: 14px;
font-weight: 500;
line-height: 22px;
text-align: left;
}
.bottom {
line-height: 22px;
text-align: right;
button {
border: 0px !important;
border-color: #ffffff !important;
font-weight: 500;
color: rgba(51, 112, 255, 1) !important;
}
}
}
.copilot-popper-tips-icon {
margin: 0 8px;
z-index: 10003;
border-radius: 50%;
background: #ffffff;
width: 28px;
height: 28px;
}
</style>

View File

@ -19,6 +19,7 @@ import AiComponent from '@/layout/components/AiComponent.vue'
import { findBaseParams } from '@/api/aiComponent'
import ExportExcel from '@/views/visualized/data/dataset/ExportExcel.vue'
import AiTips from '@/layout/components/AiTips.vue'
import Copilot from '@/layout/components/Copilot.vue'
const appearanceStore = useAppearanceStoreWithOut()
const { push } = useRouter()
@ -35,6 +36,10 @@ const handleAiClick = () => {
useEmitt().emitter.emit('aiComponentChange')
}
const handleCopilotClick = () => {
push('/copilot/index')
}
const desktop = isDesktop()
const activeIndex = computed(() => {
if (route.path.includes('system')) {
@ -52,6 +57,7 @@ const routers: any[] = formatRoute(permissionStore.getRoutersNotHidden as AppCus
const showSystem = ref(false)
const showToolbox = ref(false)
const showOverlay = ref(true)
const showOverlayCopilot = ref(true)
const handleSelect = (index: string) => {
//
if (isExternal(index)) {
@ -84,14 +90,30 @@ const initAiBase = async () => {
})
}
const initCopilotBase = async () => {
const aiCopilotCheck = wsCache.get('DE-COPILOT-TIPS-CHECK')
if (aiCopilotCheck === 'CHECKED') {
showOverlayCopilot.value = false
} else {
showOverlayCopilot.value = true
}
}
const aiTipsConfirm = () => {
wsCache.set('DE-AI-TIPS-CHECK', 'CHECKED')
showOverlay.value = false
}
const copilotConfirm = () => {
wsCache.set('DE-COPILOT-TIPS-CHECK', 'CHECKED')
showOverlayCopilot.value = false
}
onMounted(() => {
initShowSystem()
initShowToolbox()
initAiBase()
initCopilotBase()
useEmitt({
name: 'data-export-center',
callback: function (params) {
@ -122,6 +144,11 @@ onMounted(() => {
</el-menu>
<div class="operate-setting" v-if="!desktop">
<XpackComponent jsname="c3dpdGNoZXI=" />
<el-icon style="margin: 0 10px" class="ai-icon copilot-icon" v-if="!showOverlayCopilot">
<Icon name="copilot" @click="handleCopilotClick" />
</el-icon>
<Copilot @confirm="copilotConfirm" v-if="showOverlayCopilot" class="copilot-icon-tips" />
<el-icon
style="margin: 0 10px"
class="ai-icon"
@ -152,6 +179,7 @@ onMounted(() => {
:base-url="aiBaseUrl"
></ai-component>
<div v-if="showOverlay && appearanceStore.getShowAi" class="overlay"></div>
<div v-if="showOverlayCopilot" class="overlay"></div>
</div>
</el-header>
<ExportExcel ref="ExportExcelRef"></ExportExcel>
@ -284,7 +312,8 @@ onMounted(() => {
font-size: 24px !important;
}
.ai-icon-tips {
.ai-icon-tips,
.copilot-icon-tips {
font-size: 24px !important;
z-index: 10001;
}

View File

@ -20,6 +20,22 @@ export const routes: AppRouteRecordRaw[] = [
}
]
},
{
path: '/copilot',
name: 'copilot',
component: () => import('@/layout/index.vue'),
hidden: true,
meta: {},
children: [
{
path: 'index',
name: 'cpt',
hidden: true,
component: () => import('@/views/copilot/index.vue'),
meta: { hidden: true }
}
]
},
{
path: '/notSupport',
name: 'notSupport',

View File

@ -0,0 +1,367 @@
<script lang="ts" setup>
import { PropType, computed, onMounted, shallowRef, ref, nextTick } from 'vue'
import { Column, Line } from '@antv/g2plot'
import { downloadCanvas } from '@/utils/imgUtils'
import ExcelJS from 'exceljs'
interface Copilot {
msgType: string
question: string
chart: object
chartData: object
msgStatus: number
id: string
}
const props = defineProps({
copilotInfo: {
type: Object as PropType<Copilot>,
default: () => ({
msgType: 'api',
chart: {},
id: '',
question: '',
chartData: {
data: {},
title: ''
},
msgStatus: 0
})
},
isWelcome: {
type: Boolean
},
isAnswer: {
type: Boolean
}
})
const content = ref()
const chartTypeList = ref()
let columnPlot = null
onMounted(() => {
const { chart, msgType, msgStatus, chartData, id } = props.copilotInfo
if (msgStatus === 1 && msgType === 'api' && chartData) {
if (['bar', 'line'].includes(chart.type)) {
isLine.value = chart.type === 'line'
const chartType = chart.type === 'bar' ? Column : Line
columnPlot = new chartType(`de-${id}-ed`, {
data: chartData.data.data,
xField: chart.axis.x,
yField: chart.axis.y,
legend: {
layout: 'horizontal',
position: 'left'
}
})
columnPlot.render()
} else {
columns.value = chartData.data.fields.map(_ => ({
key: `${_.originName}`,
dataKey: `${_.originName}`,
title: `${_.originName}`,
width: 150
}))
data.value = chartData.data.data.map((ele, index) => {
return {
...ele,
id: index + 'row'
}
})
renderTableLocal.value = true
}
}
nextTick(() => {
;(chartTypeList.value || content.value).scrollIntoView({
block: 'end',
inline: 'nearest',
behavior: 'smooth'
})
})
})
const exportExcel = () => {
const { chartData, chart } = props.copilotInfo
const workbook = new ExcelJS.Workbook()
const worksheet = workbook.addWorksheet('Sheet1')
//
worksheet.columns = chartData.data.fields.map(ele => {
return { header: ele.originName, key: ele.originName }
})
const arr = chartData.data.fields.map(ele => ele.originName)
chartData.data.data.forEach(item => {
worksheet.addRow(arr.map(ele => item[ele]))
})
// excel
workbook.xlsx.writeBuffer().then(buffer => {
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a')
link.href = url
link.download = chart.title + '.xlsx'
link.click()
window.URL.revokeObjectURL(url)
})
}
const renderTableLocal = ref(false)
const switchChartType = type => {
columnPlot?.destroy()
isLine.value = type === 'line'
const { chart, msgType, msgStatus, chartData, id } = props.copilotInfo
renderTableLocal.value = false
if (msgStatus === 1 && msgType === 'api' && chartData) {
if (['bar', 'line'].includes(type)) {
const chartType = type === 'bar' ? Column : Line
const columnPlot = new chartType(`de-${id}-ed`, {
data: chartData.data.data,
xField: chart.axis.x,
yField: chart.axis.y,
legend: {
layout: 'horizontal',
position: 'left'
}
})
columnPlot.render()
return
}
columns.value = chartData.data.fields.map(_ => ({
key: `${_.originName}`,
dataKey: `${_.originName}`,
title: `${_.originName}`,
width: 150
}))
data.value = chartData.data.data.map((ele, index) => {
return {
...ele,
id: index + 'row'
}
})
renderTableLocal.value = true
}
}
const chartTypeRef = ref()
const downloadChart = () => {
if (renderTableLocal.value) {
exportExcel()
return
}
downloadCanvas('img', chartTypeRef.value, '图表')
}
const renderTable = computed(() => {
const { chart, msgType, msgStatus, chartData } = props.copilotInfo
return (
msgType === 'api' && msgStatus === 1 && !['bar', 'line'].includes(chart?.type) && chartData.data
)
})
const isLine = ref(false)
const columns = shallowRef([])
const data = shallowRef([])
const tips = computed(() => {
const { chart, msgType, question, msgStatus } = props.copilotInfo
if (msgType === 'api' && msgStatus === 1) {
return chart.title
}
if (msgStatus === 0) {
return '抱歉,根据已知信息无法回答这个问题,请重新描述你的问题或提供更多信息~'
} else if (msgType === 'user') {
return question
}
return ''
})
</script>
<template>
<div
class="dialogue-chart"
:class="[
copilotInfo.msgType === 'user' ? 'user-dialogue' : 'api-dialogue',
copilotInfo.msgType === 'api' && copilotInfo.msgStatus === 1 && 'chart-dialogue'
]"
>
<el-icon style="font-size: 32px" class="dialogue-chart_icon">
<Icon :name="copilotInfo.msgType === 'api' ? 'copilot' : 'default_avatar'" />
</el-icon>
<div ref="content" class="content">
<div v-if="isWelcome" class="question-or-title" style="font-size: 16px; font-weight: 500">
您好我是 Copilot很高兴为你服务
</div>
<div v-else-if="isAnswer" class="question-or-title" style="font-size: 16px; font-weight: 500">
回答中<span class="dot">...</span>
</div>
<div v-else class="question-or-title">
{{ tips }}
</div>
<div v-if="isWelcome" class="is-welcome">这是一句 Copilot 的功能描述</div>
<div
v-else-if="copilotInfo.msgType === 'api' && copilotInfo.msgStatus === 1"
class="chart-type"
ref="chartTypeRef"
>
<div class="column-plot_de" :id="`de-${copilotInfo.id}-ed`">
<el-table-v2
v-if="renderTable || renderTableLocal"
:columns="columns"
:data="data"
:width="718"
:height="335"
fixed
/>
</div>
</div>
</div>
<div
ref="chartTypeList"
class="chart-type_list"
v-if="copilotInfo.msgType === 'api' && copilotInfo.msgStatus === 1"
>
<el-tooltip effect="dark" content="切换至柱状图" placement="top">
<el-icon v-show="isLine" @click="switchChartType('bar')">
<Icon name="chart-bar" />
</el-icon>
</el-tooltip>
<el-tooltip effect="dark" content="切换至折线图" placement="top">
<el-icon style="font-size: 16px" v-show="!isLine" @click="switchChartType('line')">
<Icon name="icon_chart-line" />
</el-icon>
</el-tooltip>
<el-divider direction="vertical" />
<el-tooltip effect="dark" content="切换至明细表" placement="top">
<el-icon @click="switchChartType('table')">
<Icon name="chart-table" />
</el-icon>
</el-tooltip>
<el-divider direction="vertical" />
<el-tooltip effect="dark" content="下载" placement="top">
<el-icon @click="downloadChart">
<Icon name="chart-download" />
</el-icon>
</el-tooltip>
</div>
</div>
</template>
<style lang="less" scoped>
.dialogue-chart {
display: flex;
margin-top: 24px;
position: relative;
.chart-type_list {
position: absolute;
bottom: -36px;
right: 0;
display: flex;
align-items: center;
font-size: 24px;
.ed-icon {
position: relative;
cursor: pointer;
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 24px;
height: 24px;
background: #1f23291a;
transform: translate(-50%, -50%);
display: none;
border-radius: 4px;
}
&:hover {
&::after {
display: block;
}
}
}
.ed-divider--vertical {
border-color: #1f232926;
height: 14px;
margin: 0 6px;
}
}
&.chart-dialogue {
margin-bottom: 52px;
}
&.user-dialogue {
.content {
background: #d6e2ff;
}
}
&.api-dialogue {
.content {
background: #fff;
box-shadow: 0px 4px 8px 0px #1f23291a;
}
}
.column-plot_de {
width: 718px;
height: 335px;
}
.content {
flex: 1;
margin-left: 8px;
border-radius: 8px;
.question-or-title {
font-family: PingFang SC;
font-size: 14px;
font-weight: 400;
line-height: 22px;
padding: 12px 16px;
@keyframes identifier {
0% {
width: 0px;
}
33% {
width: 10px;
}
100% {
width: 22px;
}
}
.dot {
overflow: hidden;
display: inline-block;
animation: identifier 1s infinite;
}
}
.chart-type {
height: 360px;
border-top: 1px solid #1f232926;
padding: 12px 16px;
}
.is-welcome {
font-family: PingFang SC;
font-size: 14px;
font-weight: 400;
line-height: 22px;
text-align: left;
color: #646a73;
margin: -8px 16px 12px 16px;
}
}
}
</style>

View File

@ -0,0 +1,521 @@
<script lang="ts" setup>
import { ref, shallowRef, computed, watch } from 'vue'
import { ElMessageBox } from 'element-plus-secondary'
import {
getDatasetTree,
clearAllCopilot,
copilotFields,
getListCopilot,
copilotChat
} from '@/api/dataset'
import { useElementSize } from '@vueuse/core'
import { fieldType } from '@/utils/attr'
import DialogueChart from '@/views/copilot/DialogueChart.vue'
import { type Tree } from '@/views/visualized/data/dataset/form/CreatDsGroup.vue'
import { cloneDeep } from 'lodash-es'
const quota = shallowRef([])
const dimensions = shallowRef([])
const datasetTree = shallowRef([])
const historyArr = ref([])
const datasetId = ref('')
const questionInput = ref('')
const showLeft = ref(false)
const defaultProps = {
children: 'children',
label: 'name'
}
const dsSelectProps = {
label: 'name',
children: 'children',
value: 'id',
isLeaf: node => !node.children?.length
}
const expandedD = ref(true)
const expandedQ = ref(true)
const dfs = arr => {
return arr.filter(ele => {
if (!!ele.children?.length && !ele.leaf) {
ele.children = dfs(ele.children)
return !!ele.children?.length
}
return ele.leaf
})
}
const computedTree = computed(() => {
if (datasetTree.value[0]?.id === '0') {
return dfs(datasetTree.value[0].children)
}
return dfs(datasetTree.value)
})
const isActive = computed(() => {
return questionInput.value.trim().length && !!datasetId.value
})
const initDataset = () => {
getDatasetTree({}).then(res => {
datasetTree.value = (res as unknown as Tree[]) || []
})
}
const treeSelectRef = ref()
let oldId = ''
let currentId = ''
let oldName = ''
const handleDatasetChange = () => {
if (!!oldId) {
currentId = datasetId.value
datasetId.value = oldId
const msg = `当前数据集为【${oldName}】,切换数据集将清空当前会话。`
ElMessageBox.confirm('确定要切换数据集吗?', {
confirmButtonType: 'primary',
type: 'warning',
tip: msg,
autofocus: false,
showClose: false
}).then(() => {
datasetId.value = currentId
oldId = datasetId.value
oldName = treeSelectRef.value.getCurrentNode().name
getOptions(datasetId.value)
clearAllCopilot()
})
} else {
oldId = datasetId.value
oldName = treeSelectRef.value.getCurrentNode().name
getOptions(datasetId.value)
}
}
const getOptions = id => {
copilotFields(id).then(res => {
dimensions.value = res.data?.dimensionList || []
quota.value = res.data?.quotaList || []
})
}
initDataset()
let historyBack = []
getListCopilot().then(res => {
historyBack = (res as unknown as string[]) || []
historyArr.value = cloneDeep(historyBack)
})
const questionInputRef = ref()
const overHeight = ref(false)
const { height } = useElementSize(questionInputRef)
watch(
() => height.value,
val => {
overHeight.value = val > 48
}
)
const copilotChatLoading = ref(false)
const queryAnswer = () => {
if (!isActive.value || copilotChatLoading.value) return
historyArr.value.push({
msgType: 'user',
chart: {},
id: `${+new Date()}`,
question: questionInput.value,
chartData: {
data: {},
title: ''
},
msgStatus: 1
})
copilotChatLoading.value = true
copilotChat({
datasetGroupId: datasetId.value,
question: questionInput.value,
history: historyBack
})
.then(res => {
historyArr.value.push(res)
historyBack = res.history || []
})
.finally(() => {
copilotChatLoading.value = false
})
}
</script>
<template>
<div class="copilot">
<div class="copilot-analysis">
<el-icon style="margin-right: 8px; font-size: 24px">
<Icon name="copilot" />
</el-icon>
Copilot 对话分析
</div>
<div class="copilot-service">
<div class="dialogue">
<div class="copilot-dialogue" :style="{ height: `calc(100vh - ${height + 152}px)` }">
<DialogueChart key="isWelcome" isWelcome></DialogueChart>
<DialogueChart :copilotInfo="ele" v-for="ele in historyArr" :key="ele.id"></DialogueChart>
<DialogueChart v-if="copilotChatLoading" key="isAnswer" isAnswer></DialogueChart>
</div>
<div class="question-input" :class="overHeight && 'over-height'" ref="questionInputRef">
<el-input
v-model="questionInput"
:autosize="{ minRows: 1, maxRows: 8 }"
type="textarea"
:placeholder="$t('common.inputText')"
>
</el-input>
<el-icon v-if="copilotChatLoading" class="copilot-icon circular-input_icon">
<Icon name="icon_loading_outlined"></Icon>
</el-icon>
<el-icon v-else class="copilot-icon" @click="queryAnswer" :class="isActive && 'active'">
<Icon :name="isActive ? 'active-btn_copilot' : 'btn_copilot'"></Icon>
</el-icon>
</div>
</div>
<div class="dataset-select" :style="{ width: showLeft ? 0 : '280px' }">
<el-tooltip effect="dark" content="收起" placement="left">
<p v-show="!showLeft" class="arrow-right" @click="showLeft = true">
<el-icon>
<Icon name="icon_right_outlined"></Icon>
</el-icon>
</p>
</el-tooltip>
<el-tooltip effect="dark" content="展开" placement="left">
<p v-show="showLeft" class="left-outlined" @click="showLeft = false">
<el-icon>
<Icon name="icon_left_outlined"></Icon>
</el-icon>
</p>
</el-tooltip>
<div class="title-dataset_select">选择数据集</div>
<div style="margin: 0 16px" class="tree-select">
<el-tree-select
v-model="datasetId"
:data="computedTree"
placeholder="请选择数据集"
@change="handleDatasetChange"
:props="dsSelectProps"
style="width: 100%"
ref="treeSelectRef"
placement="bottom"
:render-after-expand="false"
filterable
popper-class="dataset-tree"
>
<template #default="{ node, data }">
<div class="content">
<el-icon size="18px" v-if="!data.leaf">
<Icon name="dv-folder"></Icon>
</el-icon>
<el-icon size="18px" v-if="data.leaf">
<Icon name="icon_dataset"></Icon>
</el-icon>
<span class="label ellipsis" style="margin-left: 8px" :title="node.label">{{
node.label
}}</span>
</div>
</template>
</el-tree-select>
</div>
<div class="preview-field">
<div :class="['field-d', { open: expandedD }]">
<div :class="['title', { expanded: expandedD }]" @click="expandedD = !expandedD">
<ElIcon class="expand">
<Icon name="icon_expand-right_filled"></Icon>
</ElIcon>
&nbsp;{{ $t('chart.dimension') }}
</div>
<el-tree v-if="expandedD" :data="dimensions" :props="defaultProps">
<template #default="{ data }">
<span class="custom-tree-node father">
<el-icon>
<Icon
:name="`field_${fieldType[data.deExtractType]}`"
:className="`field-icon-${
fieldType[[2, 3].includes(data.deExtractType) ? 2 : 0]
}`"
></Icon>
</el-icon>
<span :title="data.name" class="label-tooltip">{{ data.name }}</span>
</span>
</template>
</el-tree>
</div>
<div :class="['field-q', { open: expandedQ }]">
<div :class="['title', { expanded: expandedQ }]" @click="expandedQ = !expandedQ">
<ElIcon class="expand">
<Icon name="icon_expand-right_filled"></Icon>
</ElIcon>
&nbsp;{{ $t('chart.quota') }}
</div>
<el-tree v-if="expandedQ" :data="quota" :props="defaultProps">
<template #default="{ data }">
<span class="custom-tree-node father">
<el-icon>
<Icon
:name="`field_${fieldType[data.deExtractType]}`"
:className="`field-icon-${
fieldType[[2, 3].includes(data.deExtractType) ? 2 : 0]
}`"
></Icon>
</el-icon>
<span :title="data.name" class="label-tooltip">{{ data.name }}</span>
</span>
</template>
</el-tree>
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.copilot {
width: 100%;
height: 100%;
.copilot-analysis {
background-color: #fff;
padding: 16px 24px;
display: flex;
align-items: center;
border-bottom: 1px solid #1f232926;
}
.copilot-service {
width: 100%;
height: calc(100% - 58px);
display: flex;
overflow-y: auto;
.dialogue {
flex: 1;
padding: 0 160px;
position: relative;
.copilot-dialogue {
padding-top: 24px;
position: relative;
overflow-y: auto;
padding-bottom: 25px;
}
.question-input {
min-height: 47px;
width: calc(100% - 400px);
margin-left: 20px;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
border: 1px solid #fff;
bottom: 25px;
border-radius: 8px;
left: 180px;
box-sizing: border-box;
background: #fff;
box-shadow: 0px 6px 24px 0px #1f232914;
&:hover {
border: 1px solid var(--ed-color-primary);
}
&:has(.ed-textarea__inner:focus) {
border: 1px solid var(--ed-color-primary);
}
:deep(.ed-textarea__inner) {
border-radius: 8px !important;
box-shadow: none;
resize: none;
padding: 12px 16px;
max-height: 200px;
}
&.over-height :deep(.ed-textarea__inner) {
padding-bottom: 40px;
}
.copilot-icon {
position: absolute !important;
bottom: 12px;
right: 16px;
font-size: 24px;
cursor: not-allowed;
position: relative;
&.active {
cursor: pointer;
&::after {
content: '';
position: absolute;
height: 32px;
width: 32px;
border-radius: 8px;
display: none;
background: #3370ff1a;
}
&:hover {
&::after {
display: block;
}
}
}
}
@keyframes circular {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
.circular-input_icon {
animation: circular 1s infinite;
}
}
}
.dataset-select {
width: 280px;
height: calc(100vh - 115px);
background: #fff;
border-left: 1px solid #1f232926;
position: relative;
.left-outlined {
position: absolute;
font-size: 12px;
cursor: pointer;
left: -20px;
top: 16px;
width: 20px;
height: 24px;
border-top-left-radius: 50%;
border-bottom-left-radius: 50%;
box-shadow: 0px 4px 8px 0px #0000001a;
border: 1px solid #dee0e3;
background: #fff;
display: flex;
align-items: center;
& > .ed-icon {
margin-left: 6px;
}
&:hover {
width: 24px;
left: -24px;
color: var(--ed-color-primary, #3370ff);
& > .ed-icon {
margin-left: 8px;
}
}
}
.arrow-right {
position: absolute;
top: 16px;
z-index: 2;
cursor: pointer;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
left: -12px;
height: 24px;
width: 24px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
border: 1px solid #dee0e3;
background: #fff;
font-size: 12px;
border-radius: 50%;
&:hover {
color: var(--ed-color-primary, #3370ff);
}
}
.title-dataset_select {
width: 100%;
margin: 16px 16px 12px 16px;
font-family: PingFang SC;
font-size: 14px;
font-weight: 500;
line-height: 22px;
}
.preview-field {
padding: 0 8px;
width: 100%;
height: calc(100% - 340px);
position: relative;
overflow-y: auto;
:deep(.ed-tree-node__content) {
border-radius: 4px;
&:hover {
background: #1f23291a;
}
}
:deep(.ed-tree-node.is-current > .ed-tree-node__content:not(.is-menu):after) {
display: none;
}
.custom-tree-node {
width: calc(100% - 32px);
display: flex;
align-items: center;
padding-right: 8px;
box-sizing: content-box;
.label-tooltip {
margin-left: 5.33px;
width: 70%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.field-d,
.field-q {
position: relative;
height: 49px;
&.open {
max-height: 50%;
height: 50%;
}
.title {
cursor: pointer;
position: sticky;
top: 0px;
height: 49px;
font-family: '阿里巴巴普惠体 3.0 55 Regular L3';
font-style: normal;
font-weight: 500;
font-size: 14px;
line-height: 22px;
color: #1f2329;
display: flex;
align-items: center;
z-index: 10;
background-color: #fff;
.expand {
font-size: 10px;
}
&.expanded {
.expand {
transform: rotate(90deg);
}
}
}
overflow-y: auto;
}
.field-d {
max-height: calc(100% - 50px);
border-bottom: 1px solid rgba(31, 35, 41, 0.15);
}
}
}
}
}
</style>