feat(cmdb-ui):citype show attr && service tree search (#479)

This commit is contained in:
dagongren 2024-04-17 17:59:21 +08:00 committed by GitHub
parent 11dc7a6013
commit 0966d104a7
40 changed files with 710 additions and 559 deletions

View File

@ -54,6 +54,24 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe914;</span>
<div class="name">veops-show</div>
<div class="code-name">&amp;#xe914;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe913;</span>
<div class="name">itsm-duration</div>
<div class="code-name">&amp;#xe913;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe912;</span>
<div class="name">itsm-workload (1)</div>
<div class="code-name">&amp;#xe912;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe910;</span>
<div class="name">VPC</div>
@ -4788,9 +4806,9 @@
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1711963254221') format('woff2'),
url('iconfont.woff?t=1711963254221') format('woff'),
url('iconfont.ttf?t=1711963254221') format('truetype');
src: url('iconfont.woff2?t=1713335725699') format('woff2'),
url('iconfont.woff?t=1713335725699') format('woff'),
url('iconfont.ttf?t=1713335725699') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@ -4816,6 +4834,33 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont veops-show"></span>
<div class="name">
veops-show
</div>
<div class="code-name">.veops-show
</div>
</li>
<li class="dib">
<span class="icon iconfont itsm-duration"></span>
<div class="name">
itsm-duration
</div>
<div class="code-name">.itsm-duration
</div>
</li>
<li class="dib">
<span class="icon iconfont a-itsm-workload1"></span>
<div class="name">
itsm-workload (1)
</div>
<div class="code-name">.a-itsm-workload1
</div>
</li>
<li class="dib">
<span class="icon iconfont caise-VPC"></span>
<div class="name">
@ -11917,6 +11962,30 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#veops-show"></use>
</svg>
<div class="name">veops-show</div>
<div class="code-name">#veops-show</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#itsm-duration"></use>
</svg>
<div class="name">itsm-duration</div>
<div class="code-name">#itsm-duration</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#a-itsm-workload1"></use>
</svg>
<div class="name">itsm-workload (1)</div>
<div class="code-name">#a-itsm-workload1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-VPC"></use>

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 3857903 */
src: url('iconfont.woff2?t=1711963254221') format('woff2'),
url('iconfont.woff?t=1711963254221') format('woff'),
url('iconfont.ttf?t=1711963254221') format('truetype');
src: url('iconfont.woff2?t=1713335725699') format('woff2'),
url('iconfont.woff?t=1713335725699') format('woff'),
url('iconfont.ttf?t=1713335725699') format('truetype');
}
.iconfont {
@ -13,6 +13,18 @@
-moz-osx-font-smoothing: grayscale;
}
.veops-show:before {
content: "\e914";
}
.itsm-duration:before {
content: "\e913";
}
.a-itsm-workload1:before {
content: "\e912";
}
.caise-VPC:before {
content: "\e910";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,27 @@
"css_prefix_text": "",
"description": "",
"glyphs": [
{
"icon_id": "39948814",
"name": "veops-show",
"font_class": "veops-show",
"unicode": "e914",
"unicode_decimal": 59668
},
{
"icon_id": "39926816",
"name": "itsm-duration",
"font_class": "itsm-duration",
"unicode": "e913",
"unicode_decimal": 59667
},
{
"icon_id": "39926833",
"name": "itsm-workload (1)",
"font_class": "a-itsm-workload1",
"unicode": "e912",
"unicode_decimal": 59666
},
{
"icon_id": "39782649",
"name": "VPC",

Binary file not shown.

View File

@ -1,14 +0,0 @@
<svg width="1em" height="1em" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 0H2.5V1.25H1.25V2.5H0V1C0 0.447715 0.447715 0 1 0ZM0 7.5V9C0 9.55229 0.447715 10 1 10H2.5V8.75H1.25V7.5H0ZM8.75 7.5V8.75H7.5V10H9C9.55229 10 10 9.55228 10 9V7.5H8.75ZM10 2.5V1C10 0.447715 9.55228 0 9 0H7.5V1.25H8.75V2.5H10Z" fill="url(#paint0_linear_124_16807)"/>
<rect x="2.5" y="3.125" width="5" height="3.75" fill="url(#paint1_linear_124_16807)"/>
<defs>
<linearGradient id="paint0_linear_124_16807" x1="5" y1="0" x2="5" y2="10" gradientUnits="userSpaceOnUse">
<stop stop-color="#4F84FF"/>
<stop offset="1" stop-color="#85CBFF"/>
</linearGradient>
<linearGradient id="paint1_linear_124_16807" x1="5" y1="3.125" x2="5" y2="6.875" gradientUnits="userSpaceOnUse">
<stop stop-color="#4F84FF"/>
<stop offset="1" stop-color="#85CBFF"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 916 B

View File

@ -1,14 +0,0 @@
<svg width="1em" height="1em" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2.5" y="2.5" width="5" height="5" rx="0.5" fill="url(#paint0_linear_124_16808)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M1 0C0.447715 0 0 0.447715 0 1V9C0 9.55229 0.447715 10 1 10H9C9.55229 10 10 9.55228 10 9V1C10 0.447715 9.55228 0 9 0H1ZM8.75 1.25H1.25V8.75H8.75V1.25Z" fill="url(#paint1_linear_124_16808)"/>
<defs>
<linearGradient id="paint0_linear_124_16808" x1="5" y1="2.5" x2="5" y2="7.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#5187FF"/>
<stop offset="1" stop-color="#84C9FF"/>
</linearGradient>
<linearGradient id="paint1_linear_124_16808" x1="5" y1="0" x2="5" y2="10" gradientUnits="userSpaceOnUse">
<stop stop-color="#5187FF"/>
<stop offset="1" stop-color="#84C9FF"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 840 B

View File

@ -1,9 +0,0 @@
<svg width="1em" height="1em" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.56845 8.8409C3.06335 8.78963 1.86719 8.05799 2.06279 6.48243C2.1538 5.75105 2.64549 5.3214 3.34457 5.16041C3.67173 5.08909 4.00806 5.06954 4.34128 5.10247C4.40203 5.10811 4.44843 5.11401 4.47689 5.11837L4.51586 5.12631C4.64379 5.15574 4.77263 5.18104 4.90218 5.20219C5.26786 5.2651 5.63914 5.28941 6.0099 5.27474C6.8046 5.23219 7.21015 4.97429 7.23092 4.41672C7.25424 3.79429 6.76332 3.29619 5.86659 2.91832C5.52815 2.77793 5.17843 2.66645 4.82117 2.58506C4.70325 2.55755 4.58482 2.53328 4.46587 2.51226C4.30323 2.94847 3.9867 3.31016 3.57591 3.5292C3.16512 3.74824 2.68841 3.80952 2.23557 3.70149C1.90324 3.61651 1.60053 3.44214 1.36029 3.1973C1.12004 2.95245 0.951447 2.64649 0.872793 2.3126C0.794138 1.97872 0.808429 1.62967 0.914116 1.30333C1.0198 0.976995 1.21285 0.685836 1.4723 0.461451C1.73176 0.237065 2.04771 0.0880244 2.38588 0.0305017C2.72404 -0.0270211 3.07151 0.00917138 3.39056 0.135152C3.70961 0.261132 3.98807 0.472088 4.19571 0.745127C4.40335 1.01817 4.53225 1.34286 4.56841 1.68397C4.6812 1.70269 4.83374 1.73217 5.01524 1.77421C5.42003 1.86601 5.81625 1.99216 6.1996 2.15131C7.38191 2.64966 8.1156 3.39463 8.07638 4.4462C8.03639 5.53187 7.23425 6.04253 6.0563 6.10533C5.62418 6.12373 5.19132 6.09614 4.76503 6.02304C4.61925 5.99997 4.47398 5.9716 4.32923 5.93793C4.30731 5.93532 4.28534 5.9331 4.26335 5.93127C4.02033 5.90687 3.77501 5.92018 3.53606 5.97075C3.15153 6.05893 2.94311 6.24146 2.90056 6.58267C2.78725 7.49504 3.47915 7.94443 5.42694 8.00416C5.44492 7.65558 5.5586 7.3187 5.75548 7.03049C5.95237 6.74229 6.22485 6.51389 6.54303 6.37039C6.8612 6.22689 7.21277 6.17383 7.55912 6.21703C7.90548 6.26023 8.23323 6.39802 8.50641 6.61528C8.77959 6.83254 8.98763 7.12086 9.10769 7.4486C9.22775 7.77634 9.25519 8.13082 9.187 8.47314C9.11881 8.81545 8.95763 9.13235 8.72114 9.38907C8.48465 9.64578 8.18201 9.83237 7.84643 9.92836C7.39921 10.0556 6.92094 10.0153 6.50129 9.81515C6.08164 9.61495 5.74941 9.26855 5.56691 8.8409H5.56845Z" fill="url(#paint0_linear_124_16804)"/>
<defs>
<linearGradient id="paint0_linear_124_16804" x1="5.02318" y1="0.00390625" x2="5.02318" y2="10.0013" gradientUnits="userSpaceOnUse">
<stop stop-color="#497DFF"/>
<stop offset="1" stop-color="#8CD5FF"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -1,9 +0,0 @@
<svg width="1em" height="1em" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.01211 4.50621L2.7769 5.74077C2.712 5.80565 2.66051 5.88268 2.62538 5.96747C2.59025 6.05225 2.57217 6.14313 2.57217 6.2349C2.57217 6.32668 2.59025 6.41755 2.62538 6.50234C2.66051 6.58712 2.712 6.66416 2.7769 6.72904L3.27085 7.223C3.33573 7.28791 3.41276 7.3394 3.49754 7.37453C3.58232 7.40966 3.67319 7.42774 3.76496 7.42774C3.85674 7.42774 3.94761 7.40966 4.03239 7.37453C4.11717 7.3394 4.1942 7.28791 4.25908 7.223L5.49394 5.98775C5.6237 6.1175 5.72663 6.27155 5.79686 6.44109C5.86708 6.61063 5.90323 6.79234 5.90323 6.97585C5.90323 7.15935 5.86708 7.34106 5.79686 7.5106C5.72663 7.68014 5.6237 7.83419 5.49394 7.96394L3.76479 9.69316C3.56827 9.88963 3.30176 10 3.02387 10C2.74599 10 2.47948 9.88963 2.28296 9.69316L0.306832 7.71696C0.110368 7.52043 0 7.25391 0 6.97602C0 6.69813 0.110368 6.43161 0.306832 6.23508L2.03599 4.50586C2.16574 4.3761 2.31978 4.27317 2.48931 4.20294C2.65884 4.13271 2.84055 4.09657 3.02405 4.09657C3.20755 4.09657 3.38925 4.13271 3.55879 4.20294C3.72832 4.27317 3.88236 4.3761 4.01211 4.50586V4.50621ZM5.98789 5.49414L7.2231 4.25923C7.288 4.19435 7.33949 4.11732 7.37462 4.03253C7.40975 3.94775 7.42783 3.85687 7.42783 3.7651C7.42783 3.67332 7.40975 3.58245 7.37462 3.49766C7.33949 3.41288 7.288 3.33584 7.2231 3.27096L6.72915 2.777C6.66428 2.71209 6.58724 2.6606 6.50246 2.62547C6.41768 2.59034 6.32681 2.57226 6.23504 2.57226C6.14326 2.57226 6.05239 2.59034 5.96761 2.62547C5.88283 2.6606 5.8058 2.71209 5.74092 2.777L4.50606 4.01225C4.3763 3.8825 4.27337 3.72845 4.20314 3.55891C4.13292 3.38937 4.09677 3.20766 4.09677 3.02415C4.09677 2.84065 4.13292 2.65894 4.20314 2.4894C4.27337 2.31986 4.3763 2.16581 4.50606 2.03606L6.23521 0.306843C6.43173 0.110371 6.69824 0 6.97613 0C7.25401 0 7.52052 0.110371 7.71704 0.306843L9.69317 2.28304C9.88963 2.47957 10 2.74609 10 3.02398C10 3.30187 9.88963 3.56839 9.69317 3.76492L7.96401 5.49414C7.83426 5.6239 7.68022 5.72683 7.51069 5.79706C7.34116 5.86729 7.15945 5.90343 6.97595 5.90343C6.79245 5.90343 6.61075 5.86729 6.44121 5.79706C6.27168 5.72683 6.11764 5.6239 5.98789 5.49414ZM3.51817 5.9881L5.98789 3.51829C6.05339 3.45274 6.14225 3.4159 6.23491 3.41586C6.32758 3.41583 6.41646 3.45261 6.48201 3.51812C6.54755 3.58362 6.5844 3.67248 6.58443 3.76515C6.58446 3.85782 6.54768 3.9467 6.48218 4.01225L4.01211 6.48206C3.94661 6.54761 3.85775 6.58445 3.76509 6.58449C3.67242 6.58452 3.58354 6.54774 3.51799 6.48223C3.45245 6.41673 3.4156 6.32787 3.41557 6.2352C3.41554 6.14253 3.45232 6.05365 3.51782 5.9881H3.51817Z" fill="url(#paint0_linear_124_16775)"/>
<defs>
<linearGradient id="paint0_linear_124_16775" x1="5" y1="0" x2="5" y2="10" gradientUnits="userSpaceOnUse">
<stop stop-color="#5A85FF"/>
<stop offset="1" stop-color="#8DD8FF"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -1,9 +0,0 @@
<svg width="1em" height="1em" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.31822 4.16667H2.54549V2.5C2.54549 1.11458 3.63981 0 5.00003 0C6.36026 0 7.45458 1.11458 7.45458 2.5V4.16667H8.68185C8.90685 4.16667 9.09094 4.35417 9.09094 4.58333V9.58333C9.09094 9.8125 8.90685 10 8.68185 10H1.31822C1.09322 10 0.909124 9.8125 0.909124 9.58333V4.58333C0.909124 4.35417 1.09322 4.16667 1.31822 4.16667ZM5.00003 7.91667C5.45003 7.91667 5.81822 7.54167 5.81822 7.08333C5.81822 6.625 5.45003 6.25 5.00003 6.25C4.55003 6.25 4.18185 6.625 4.18185 7.08333C4.18185 7.54167 4.55003 7.91667 5.00003 7.91667ZM3.36367 4.16667H6.6364V2.5C6.6364 1.58333 5.90003 0.833333 5.00003 0.833333C4.10003 0.833333 3.36367 1.58333 3.36367 2.5V4.16667Z" fill="url(#paint0_linear_124_16805)"/>
<defs>
<linearGradient id="paint0_linear_124_16805" x1="5.00003" y1="0" x2="5.00003" y2="10" gradientUnits="userSpaceOnUse">
<stop stop-color="#4D82FF"/>
<stop offset="1" stop-color="#88CFFF"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1022 B

View File

@ -1,9 +0,0 @@
<svg width="1em" height="1em" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.91242 9.46382C3.91242 9.57428 3.82288 9.66382 3.71242 9.66382H2.35075C2.2403 9.66382 2.15075 9.57428 2.15075 9.46382V3.55962C2.15075 3.44916 2.06121 3.35962 1.95075 3.35962H0.539905C0.354312 3.35962 0.268806 3.12879 0.40961 3.00788L3.58212 0.283626C3.71182 0.172253 3.91242 0.264405 3.91242 0.43536V9.46382ZM6.08758 0.567715C6.08758 0.457258 6.17712 0.367716 6.28758 0.367716H7.64925C7.7597 0.367716 7.84925 0.457259 7.84925 0.567716V6.4411C7.84925 6.55156 7.93879 6.6411 8.04925 6.6411H9.46001C9.64561 6.6411 9.73111 6.87195 9.59029 6.99285L6.41786 9.71645C6.28816 9.8278 6.08758 9.73565 6.08758 9.5647V0.567715Z" fill="url(#paint0_linear_124_16806)"/>
<defs>
<linearGradient id="paint0_linear_124_16806" x1="5" y1="0" x2="5" y2="10" gradientUnits="userSpaceOnUse">
<stop stop-color="#5A85FF"/>
<stop offset="1" stop-color="#8DD8FF"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 979 B

View File

@ -1,9 +0,0 @@
<svg width="1em" height="1em" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.51961 6.8937V10H4.48V6.8937H1.76732C1.65823 6.8937 1.56223 6.85372 1.48369 6.77237C1.40522 6.69504 1.3621 6.5915 1.36369 6.48421C1.36369 5.95891 1.52769 5.48566 1.85895 5.06411C2.18986 4.64428 2.56258 4.43334 2.97893 4.43334V1.64277C2.75966 1.64277 2.57167 1.56142 2.41022 1.39873C2.25355 1.24349 2.16738 1.0362 2.17022 0.821384C2.17022 0.598718 2.25022 0.407762 2.41022 0.244037C2.56912 0.0827244 2.7593 0 2.97893 0H7.01959C7.23885 0 7.42685 0.0813456 7.5883 0.244037C7.74721 0.406728 7.82866 0.598718 7.82866 0.821384C7.82866 1.04405 7.74866 1.23501 7.58867 1.39873C7.4283 1.5628 7.23885 1.64277 7.01959 1.64277V4.43196C7.43594 4.43196 7.81012 4.64291 8.13956 5.06273C8.46631 5.47151 8.64098 5.97137 8.63628 6.48421C8.63628 6.59486 8.59701 6.6924 8.51665 6.77237C8.43665 6.85234 8.34211 6.8937 8.23302 6.8937H5.51998H5.51961Z" fill="url(#paint0_linear_124_16803)"/>
<defs>
<linearGradient id="paint0_linear_124_16803" x1="5.00001" y1="0" x2="5.00001" y2="10" gradientUnits="userSpaceOnUse">
<stop stop-color="#5A85FF"/>
<stop offset="1" stop-color="#8DD8FF"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -4,34 +4,22 @@
@click="jumpTo"
v-if="showTitle && !collapsed"
style="width: 100%; height: 100%; cursor: pointer"
:src="file_name ? `/api/common-setting/v1/file/${file_name}` : require('@/assets/logo_VECMDB.png')"
:src="require('@/assets/logo_VECMDB.png')"
/>
<img
@click="jumpTo"
v-else
style="width: 32px; height: 32px; margin-left: 24px; cursor: pointer"
:src="small_file_name ? `/api/common-setting/v1/file/${small_file_name}` : require('@/assets/logo.png')"
:src="require('@/assets/logo.png')"
/>
<!-- <logo-svg/> -->
<!-- <img v-if="showTitle" style="width:92px;height: 32px" src="@/assets/OneOps.png" /> -->
<!-- <h1 v-if="showTitle">{{ title }}</h1> -->
</div>
</template>
<script>
// import LogoSvg from '@/assets/logo.svg?inline'
import { mapState } from 'vuex'
export default {
name: 'Logo',
components: {
// LogoSvg,
},
computed: {
...mapState({
file_name: (state) => state.logo.file_name,
small_file_name: (state) => state.logo.small_file_name,
}),
},
components: {},
computed: {},
props: {
title: {
type: String,

View File

@ -9,25 +9,11 @@
import gridSvg from '@/assets/icons/grid.svg?inline'
import top_agent from '@/assets/icons/top_agent.svg?inline'
import top_acl from '@/assets/icons/top_acl.svg?inline'
import ops_default_show from '@/assets/icons/ops-default_show.svg?inline'
import ops_is_choice from '@/assets/icons/ops-is_choice.svg?inline'
import ops_is_index from '@/assets/icons/ops-is_index.svg?inline'
import ops_is_link from '@/assets/icons/ops-is_link.svg?inline'
import ops_is_password from '@/assets/icons/ops-is_password.svg?inline'
import ops_is_sortable from '@/assets/icons/ops-is_sortable.svg?inline'
import ops_is_unique from '@/assets/icons/ops-is_unique.svg?inline'
import ops_move_icon from '@/assets/icons/ops-move-icon.svg?inline'
export {
gridSvg,
top_agent,
top_acl,
ops_default_show,
ops_is_choice,
ops_is_index,
ops_is_link,
ops_is_password,
ops_is_sortable,
ops_is_unique,
ops_move_icon
}

View File

@ -0,0 +1,14 @@
import './highlight.less'
const highlight = (el, binding) => {
if (binding.value.value) {
let testValue = `${binding.value.value}`
if (['(', ')', '$'].includes(testValue)) {
testValue = `\\${testValue}`
}
const regex = new RegExp(`(${testValue})`, 'gi')
el.innerHTML = el.innerText.replace(regex, `<span class='${binding.value.class ?? 'ops-text-highlight'}'>$1</span>`)
}
}
export default highlight

View File

@ -0,0 +1,5 @@
@import '~@/style/static.less';
.ops-text-highlight {
background-color: @primary-color_3;
}

View File

@ -0,0 +1,12 @@
import hightlight from './highlight'
const install = function (Vue) {
Vue.directive('hightlight', hightlight)
}
if (window.Vue) {
window.hightlight = hightlight
Vue.use(install); // eslint-disable-line
}
hightlight.install = install
export default hightlight

View File

@ -0,0 +1,13 @@
import waves from './waves'
const install = function (Vue) {
Vue.directive('waves', waves)
}
if (window.Vue) {
window.waves = waves
Vue.use(install); // eslint-disable-line
}
waves.install = install
export default waves

View File

@ -0,0 +1,26 @@
.waves-ripple {
position: absolute;
border-radius: 100%;
background-color: rgba(0, 0, 0, 0.15);
background-clip: padding-box;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-transform: scale(0);
-ms-transform: scale(0);
transform: scale(0);
opacity: 1;
}
.waves-ripple.z-active {
opacity: 0;
-webkit-transform: scale(2);
-ms-transform: scale(2);
transform: scale(2);
-webkit-transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, -webkit-transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out;
transition: opacity 1.2s ease-out, transform 0.6s ease-out, -webkit-transform 0.6s ease-out;
}

View File

@ -0,0 +1,72 @@
import './waves.css'
const context = '@@wavesContext'
function handleClick(el, binding) {
function handle(e) {
const customOpts = Object.assign({}, binding.value)
const opts = Object.assign({
ele: el, // 波纹作用元素
type: 'hit', // hit 点击位置扩散 center中心点扩展
color: 'rgba(0, 0, 0, 0.15)' // 波纹颜色
},
customOpts
)
const target = opts.ele
if (target) {
target.style.position = 'relative'
target.style.overflow = 'hidden'
const rect = target.getBoundingClientRect()
let ripple = target.querySelector('.waves-ripple')
if (!ripple) {
ripple = document.createElement('span')
ripple.className = 'waves-ripple'
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
target.appendChild(ripple)
} else {
ripple.className = 'waves-ripple'
}
switch (opts.type) {
case 'center':
ripple.style.top = rect.height / 2 - ripple.offsetHeight / 2 + 'px'
ripple.style.left = rect.width / 2 - ripple.offsetWidth / 2 + 'px'
break
default:
ripple.style.top =
(e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop ||
document.body.scrollTop) + 'px'
ripple.style.left =
(e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft ||
document.body.scrollLeft) + 'px'
}
ripple.style.backgroundColor = opts.color
ripple.className = 'waves-ripple z-active'
return false
}
}
if (!el[context]) {
el[context] = {
removeHandle: handle
}
} else {
el[context].removeHandle = handle
}
return handle
}
export default {
bind(el, binding) {
el.addEventListener('click', handleClick(el, binding), false)
},
update(el, binding) {
el.removeEventListener('click', el[context].removeHandle, false)
el.addEventListener('click', handleClick(el, binding), false)
},
unbind(el) {
el.removeEventListener('click', el[context].removeHandle, false)
el[context] = null
delete el[context]
}
}

View File

@ -31,7 +31,6 @@ router.beforeEach(async (to, from, next) => {
store.dispatch("loadAllUsers")
store.dispatch("loadAllEmployees")
store.dispatch("loadAllDepartments")
store.dispatch("getCompanyInfo")
store.dispatch('GenerateRoutes', { roles }).then(() => {
router.addRoutes(store.getters.appRoutes)
const redirect = decodeURIComponent(from.query.redirect || to.path)

View File

@ -73,3 +73,11 @@ export function deleteCIRelationView(firstCiId, secondCiId, data) {
data
})
}
export function searchCIRelationFull(params) {
return axios({
url: `/v0.1/ci_relations/search/full`,
method: 'GET',
params,
})
}

View File

@ -95,12 +95,12 @@
isFocusExpression = false
}
"
class="ci-searchform-expression"
:class="{ 'ci-searchform-expression': true, 'ci-searchform-expression-has-value': expression }"
:style="{ width }"
:placeholder="placeholder"
@keyup.enter="emitRefresh"
>
<ops-icon slot="suffix" type="veops-copy" @click="handleCopyExpression" />
<a-icon slot="suffix" type="check-circle" @click="handleCopyExpression" />
</a-input>
<slot></slot>
</a-space>
@ -284,6 +284,9 @@ export default {
cursor: pointer;
}
}
.ci-searchform-expression-has-value .ant-input-suffix {
color: @func-color_3;
}
.cmdb-search-form {
.ant-form-item-label {
overflow: hidden;
@ -294,7 +297,6 @@ export default {
</style>
<style lang="less" scoped>
.search-form-bar {
margin-bottom: 20px;
display: flex;

View File

@ -194,7 +194,10 @@ const cmdb_en = {
attributeAssociationTip3: 'Two Attributes must be selected',
attributeAssociationTip4: 'Please select a attribute from Source CIType',
attributeAssociationTip5: 'Please select a attribute from Target CIType',
show: 'show attribute',
setAsShow: 'Set as show attribute',
cancelSetAsShow: 'Cancel show attribute',
showTips: 'The names of nodes in the service tree and topology view'
},
components: {
unselectAttributes: 'Unselected',
@ -530,7 +533,8 @@ if __name__ == "__main__":
peopleHasRead: 'Personnel authorized to read:',
authorizationPolicy: 'CI Authorization Policy:',
idAuthorizationPolicy: 'Authorized by node:',
view: 'View permissions'
view: 'View permissions',
searchTips: 'Search in service tree'
},
tree: {
tips1: 'Please go to Preference page first to complete your subscription!',

View File

@ -194,6 +194,10 @@ const cmdb_zh = {
attributeAssociationTip3: '属性关联必须选择两个属性',
attributeAssociationTip4: '请选择原模型属性',
attributeAssociationTip5: '请选择目标模型属性',
show: '展示属性',
setAsShow: '设置为展示属性',
cancelSetAsShow: '取消设置为展示属性',
showTips: '服务树和拓扑视图里节点的名称'
},
components: {
unselectAttributes: '未选属性',
@ -529,7 +533,8 @@ if __name__ == "__main__":
peopleHasRead: '当前有查看权限的人员:',
authorizationPolicy: '实例授权策略:',
idAuthorizationPolicy: '按节点授权的:',
view: '查看权限'
view: '查看权限',
searchTips: '在服务树中筛选'
},
tree: {
tips1: '请先到 我的订阅 页面完成订阅!',

View File

@ -150,11 +150,11 @@ export default {
computed: {
topoData() {
const ci_types_list = this.ci_types()
const unique_id = this.attributes().unique_id
const unique_name = this.attributes().unique
const _findCiType = ci_types_list.find((item) => item.id === this.typeId)
const unique_id = _findCiType.show_id || this.attributes().unique_id
const unique_name = _findCiType.show_name || this.attributes().unique
const _findUnique = this.attrList().find((attr) => attr.id === unique_id)
const unique_alias = _findUnique?.alias || _findUnique?.name || ''
const _findCiType = ci_types_list.find((item) => item.id === this.typeId)
const nodes = {
isRoot: true,
id: `Root_${this.typeId}`,
@ -183,6 +183,10 @@ export default {
this.parentCITypes.forEach((parent) => {
const _findCiType = ci_types_list.find((item) => item.id === parent.id)
if (this.firstCIs[parent.name]) {
const unique_id = _findCiType.show_id || _findCiType.unique_id
const _findUnique = parent.attributes.find((attr) => attr.id === unique_id)
const unique_name = _findUnique?.name
const unique_alias = _findUnique?.alias || _findUnique?.name || ''
this.firstCIs[parent.name].forEach((parentCi) => {
nodes.children.push({
id: `${parentCi._id}`,
@ -190,9 +194,9 @@ export default {
title: parent.alias || parent.name,
name: parent.name,
side: 'left',
unique_alias: parentCi.unique_alias,
unique_name: parentCi.unique,
unique_value: parentCi[parentCi.unique],
unique_alias,
unique_name,
unique_value: parentCi[unique_name],
children: [],
icon: _findCiType?.icon || '',
endpoints: [
@ -222,6 +226,10 @@ export default {
this.childCITypes.forEach((child) => {
const _findCiType = ci_types_list.find((item) => item.id === child.id)
if (this.secondCIs[child.name]) {
const unique_id = _findCiType.show_id || _findCiType.unique_id
const _findUnique = child.attributes.find((attr) => attr.id === unique_id)
const unique_name = _findUnique?.name
const unique_alias = _findUnique?.alias || _findUnique?.name || ''
this.secondCIs[child.name].forEach((childCi) => {
nodes.children.push({
id: `${childCi._id}`,
@ -229,9 +237,9 @@ export default {
title: child.alias || child.name,
name: child.name,
side: 'right',
unique_alias: childCi.unique_alias,
unique_name: childCi.unique,
unique_value: childCi[childCi.unique],
unique_alias,
unique_name,
unique_value: childCi[unique_name],
children: [],
icon: _findCiType?.icon || '',
endpoints: [
@ -333,7 +341,6 @@ export default {
secondCIs[item.ci_type] = [item]
}
})
console.log(_.cloneDeep(secondCIs))
this.secondCIs = secondCIs
})
.catch((e) => {})

View File

@ -15,7 +15,7 @@
position: absolute;
background: #fff;
border: 1px solid #d9d9d9;
border-radius: 10px;
border-radius: 2px;
padding: 4px 8px;
width: 100px;
text-align: center;
@ -74,13 +74,11 @@
}
.root {
width: 100px;
background: #2f54eb;
border: none;
border-radius: 5px;
font-weight: 500;
border-color: @primary-color;
font-weight: 700;
padding: 4px 8px;
.title {
color: #fff;
color: @primary-color;
}
}
}

View File

@ -10,6 +10,7 @@
import _ from 'lodash'
import { TreeCanvas } from 'butterfly-dag'
import { searchCIRelation } from '@/modules/cmdb/api/CIRelation'
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
import Node from './node.js'
import 'butterfly-dag/dist/index.css'
@ -87,7 +88,7 @@ export default {
this.canvas.focusCenterWithAnimate()
})
},
redrawData(res, sourceNode, side) {
async redrawData(res, sourceNode, side) {
const newNodes = []
const newEdges = []
if (!res.result.length) {
@ -95,18 +96,24 @@ export default {
return
}
const ci_types_list = this.ci_types()
res.result.forEach((r) => {
for (let i = 0; i < res.result.length; i++) {
const r = res.result[i]
if (!this.exsited_ci.includes(r._id)) {
const _findCiType = ci_types_list.find((item) => item.id === r._type)
const { attributes } = await getCITypeAttributesById(_findCiType.id)
const unique_id = _findCiType.show_id || _findCiType.unique_id
const _findUnique = attributes.find((attr) => attr.id === unique_id)
const unique_name = _findUnique?.name
const unique_alias = _findUnique?.alias || _findUnique?.name || ''
newNodes.push({
id: `${r._id}`,
Class: Node,
title: r.ci_type_alias || r.ci_type,
name: r.ci_type,
side: side,
unique_alias: r.unique_alias,
unique_name: r.unique,
unique_value: r[r.unique],
unique_alias,
unique_name,
unique_value: r[unique_name],
children: [],
icon: _findCiType?.icon || '',
endpoints: [
@ -131,7 +138,8 @@ export default {
targetNode: side === 'right' ? `${r._id}` : sourceNode,
type: 'endpoint',
})
})
}
const { nodes, edges } = this.canvas.getDataMap()
// 删除原节点和边
this.canvas.removeNodes(nodes.map((node) => node.id))

View File

@ -10,6 +10,7 @@
:class="{ 'attribute-card': true, 'attribute-card-add': isAdd, 'attribute-card-inherited': inherited }"
>
<div class="attribute-card-uniqueKey" v-if="isUnique">{{ $t('cmdb.ciType.uniqueKey') }}</div>
<div class="attribute-card-uniqueKey" v-if="isShowId">{{ $t('cmdb.ciType.show') }}</div>
<template v-if="!isAdd">
<a-tooltip :title="inherited ? $t('cmdb.ciType.inheritFrom', { name: property.inherited_from }) : ''">
<div class="attribute-card-content">
@ -27,6 +28,7 @@
<div
class="attribute-card-trigger"
v-if="(property.value_type === '3' || property.value_type === '4') && !isStore"
:style="{ top: isShowId ? '18px' : '' }"
>
<a @click="openTrigger"><ops-icon type="ops-trigger"/></a>
</div>
@ -64,12 +66,24 @@
</a-space>
</a-popover>
<a-space class="attribute-card-operation" v-if="!inherited">
<a v-if="!isStore"><a-icon type="edit" @click="handleEdit"/></a>
<a-tooltip :title="$t('cmdb.ciType.computeForAllCITips')">
<a v-if="!isStore && property.is_computed"><a-icon type="redo" @click="handleCalcComputed"/></a>
<a-space class="attribute-card-operation">
<a v-if="!isStore && !inherited"><a-icon type="edit" @click="handleEdit"/></a>
<a-tooltip
v-if="
!isStore &&
!isUnique &&
!['6'].includes(property.value_type) &&
!property.is_password &&
!property.is_list
"
:title="$t(isShowId ? 'cmdb.ciType.cancelSetAsShow' : 'cmdb.ciType.setAsShow')"
>
<a><ops-icon type="veops-show" @click="setAsShow"/></a>
</a-tooltip>
<a v-if="!isUnique" style="color:red;"><a-icon type="delete" @click="handleDelete"/></a>
<a-tooltip v-if="!isStore && property.is_computed" :title="$t('cmdb.ciType.computeForAllCITips')">
<a><a-icon type="redo" @click="handleCalcComputed"/></a>
</a-tooltip>
<a v-if="!isUnique && !inherited" style="color:red;"><a-icon type="delete" @click="handleDelete"/></a>
</a-space>
</div>
<TriggerForm ref="triggerForm" :CITypeId="CITypeId" />
@ -84,17 +98,9 @@
<script>
import { deleteCITypeAttributesById, deleteAttributesById, calcComputedAttribute } from '@/modules/cmdb/api/CITypeAttr'
import ValueTypeIcon from '@/components/CMDBValueTypeMapIcon'
import {
ops_default_show,
ops_is_choice,
ops_is_index,
ops_is_link,
ops_is_password,
ops_is_sortable,
ops_is_unique,
} from '@/core/icons'
import { valueTypeMap } from '../../utils/const'
import TriggerForm from './triggerForm.vue'
import { updateCIType } from '@/modules/cmdb/api/CIType'
export default {
name: 'AttributeCard',
inject: {
@ -102,17 +108,14 @@ export default {
from: 'unique',
default: () => undefined,
},
show_id: {
from: 'show_id',
default: () => undefined,
},
},
components: {
ValueTypeIcon,
TriggerForm,
ops_default_show,
ops_is_choice,
ops_is_index,
ops_is_link,
ops_is_password,
ops_is_sortable,
ops_is_unique,
},
props: {
property: {
@ -146,6 +149,12 @@ export default {
}
return false
},
isShowId() {
if (this.show_id) {
return this.property?.id === this.show_id()
}
return false
},
valueTypeMap() {
return valueTypeMap()
},
@ -217,6 +226,11 @@ export default {
},
})
},
setAsShow() {
updateCIType(this.CITypeId, { show_id: this.isShowId ? null : this.property?.id }).then((res) => {
this.$emit('ok')
})
},
},
}
</script>

View File

@ -186,6 +186,7 @@ import {
createCITypeGroupById,
updateCITypeGroupById,
getTriggerList,
getCIType,
} from '@/modules/cmdb/api/CIType'
import {
getCITypeAttributesById,
@ -231,6 +232,7 @@ export default {
newGroupName: '',
attrTypeFilter: [],
unique: '',
show_id: null,
}
},
computed: {
@ -250,20 +252,31 @@ export default {
unique: () => {
return this.unique
},
show_id: () => {
return this.show_id
},
}
},
beforeCreate() {},
created() {},
mounted() {
this.getCITypeGroupData()
this.init()
},
methods: {
getPropertyIcon,
init() {
getCIType(this.CITypeId).then((res) => {
if (res?.ci_types && res.ci_types.length) {
this.show_id = res.ci_types[0]?.show_id ?? null
}
})
this.getCITypeGroupData()
},
handleEditProperty(property) {
this.$refs.attributeEditForm.handleEdit(property, this.attributes)
},
handleOk() {
this.getCITypeGroupData()
this.init()
},
setOtherGroupAttributes() {
const orderMap = this.attributes.reduce(function(map, obj) {
@ -591,7 +604,6 @@ export default {
</script>
<style lang="less" scoped>
.fold {
width: calc(100% - 216px);
display: inline-block;

View File

@ -53,11 +53,10 @@
</a-menu-item>
<a-menu-item key="1">
<a-space>
<a
href="/api/v0.1/ci_types/template/export/file"
><a-icon type="download" /> {{ $t('download') }}</a
<a href="/api/v0.1/ci_types/template/export/file">
<a-icon type="download" /> {{ $t('download') }}
</a></a-space
>
</a-space>
</a-menu-item>
</a-menu>
</a-dropdown>
@ -262,6 +261,7 @@
'default_order_attr',
{ rules: [{ required: false, message: $t('cmdb.ciType.selectDefaultOrderAttr') }] },
]"
:placeholder="$t('placeholder2')"
>
<el-option
:key="item.name"
@ -299,6 +299,7 @@
filterInput = ''
}
"
@change="handleChangeUnique"
>
<el-option
:key="item.id"
@ -313,6 +314,40 @@
<a-divider type="vertical" />
<a @click="handleCreatNewAttr">{{ $t('cmdb.ciType.notfound') }}</a>
</a-form-item>
<a-form-item
:help="$t('cmdb.ciType.showTips')"
:label="$t('cmdb.ciType.show')"
v-if="drawerTitle === $t('cmdb.ciType.editCIType')"
>
<el-select
size="small"
filterable
clearable
name="show_id"
:filter-method="
(input) => {
showIdFilterInput = input
}
"
v-decorator="['show_id', { rules: [{ required: false }] }]"
:placeholder="$t('placeholder2')"
@visible-change="
() => {
showIdFilterInput = ''
}
"
>
<el-option
:key="item.id"
:value="item.id"
v-for="item in showIdSelectOptions"
:label="item.alias || item.name"
>
<span> {{ item.alias || item.name }}</span>
<span :title="item.name" style="font-size: 10px; color: #afafaf"> {{ item.name }}</span>
</el-option>
</el-select>
</a-form-item>
<div v-if="newAttrAreaVisible" :style="{ padding: '15px 8px 0 8px', backgroundColor: '#fafafa' }">
<create-new-attribute
ref="createNewAttribute"
@ -418,14 +453,17 @@ export default {
addId: null,
filterInput: '',
showIdFilterInput: '',
orderSelectionOptions: [],
currentTypeAttrs: [],
default_order_asc: '1',
allTreeDepAndEmp: [],
editCiType: null,
isInherit: false,
unique_id: null,
}
},
computed: {
@ -482,6 +520,22 @@ export default {
}
return _attributes
},
orderSelectionOptions() {
return this.currentTypeAttrs.filter((item) => item.is_required)
},
showIdSelectOptions() {
const _showIdSelectOptions = this.currentTypeAttrs.filter(
(item) => item.id !== this.unique_id && !['6'].includes(item.value_type) && !item.is_password && !item.is_list
)
if (this.showIdFilterInput) {
return _showIdSelectOptions.filter(
(item) =>
item.name.toLowerCase().includes(this.showIdFilterInput.toLowerCase()) ||
item.alias.toLowerCase().includes(this.showIdFilterInput.toLowerCase())
)
}
return _showIdSelectOptions
},
},
provide() {
return {
@ -659,6 +713,7 @@ export default {
delete values.parent_ids
await this.updateCIType(values.id, {
...values,
show_id: values.show_id || null,
icon,
})
} else {
@ -864,7 +919,8 @@ export default {
this.drawerTitle = this.$t('cmdb.ciType.editCIType')
this.drawerVisible = true
await getCITypeAttributesById(record.id).then((res) => {
this.orderSelectionOptions = res.attributes.filter((item) => item.is_required)
this.currentTypeAttrs = res.attributes
this.unique_id = res.unique_id
})
await getCIType(record.id).then((res) => {
const ci_type = res.ci_types[0]
@ -877,6 +933,9 @@ export default {
})
})
}
this.form.setFieldsValue({
show_id: ci_type.show_id ?? null,
})
})
this.$nextTick(() => {
this.default_order_asc = record.default_order_attr && record.default_order_attr.startsWith('-') ? '2' : '1'
@ -941,12 +1000,18 @@ export default {
this.$message.error({ content: this.$t('cmdb.ciType.uploadFailed'), key, duration: 2 })
}
},
handleChangeUnique(value) {
this.unique_id = value
const show_id = this.form.getFieldValue('show_id')
if (show_id === value) {
this.form.setFieldsValue({ show_id: '' })
}
},
},
}
</script>
<style lang="less" scoped>
.ci-types-wrap {
margin: 0 0 -24px 0;
.ci-types-empty {

View File

@ -11,6 +11,14 @@
<template #one>
<div class="relation-views-left" :style="{ height: `${windowHeight - 115}px` }">
<div class="relation-views-left-header" :title="$route.meta.name">{{ $route.meta.name }}</div>
<a-input
:placeholder="$t('cmdb.serviceTree.searchTips')"
class="relation-views-left-input"
@pressEnter="handleSearchFull"
v-model="fullSearchValue"
>
<a-icon slot="prefix" type="search" />
</a-input>
<div
class="ops-list-batch-action"
:style="{ marginBottom: '10px' }"
@ -47,6 +55,7 @@
<span>{{ $t('selectRows', { rows: batchTreeKey.length }) }}</span>
</div>
<a-tree
v-if="!isFullSearch"
:selectedKeys="selectedKeys"
:loadData="onLoadData"
:treeData="treeData"
@ -55,13 +64,10 @@
@drop="onDrop"
:expandedKeys="expandedKeys"
>
<template #title="{ key: treeKey, title,number, isLeaf }">
<template #title="treeNodeData">
<ContextMenu
:title="title"
:number="number"
:treeKey="treeKey"
:treeNodeData="treeNodeData"
:levels="levels"
:isLeaf="isLeaf"
:currentViews="relationViews.views[viewName]"
:id2type="relationViews.id2type"
@onContextMenuClick="onContextMenuClick"
@ -74,6 +80,30 @@
/>
</template>
</a-tree>
<a-tree
v-else
:treeData="filterFullTreeData"
defaultExpandAll
:selectedKeys="selectedKeys"
:expandedKeys="expandedKeys"
>
<template #title="treeNodeData">
<ContextMenu
:treeNodeData="treeNodeData"
:levels="levels"
:currentViews="relationViews.views[viewName]"
:id2type="relationViews.id2type"
@onContextMenuClick="onContextMenuClick"
@onNodeClick="onNodeClick"
:ciTypeIcons="ciTypeIcons"
:showBatchLevel="showBatchLevel"
:batchTreeKey="batchTreeKey"
@clickCheckbox="clickCheckbox"
@updateTreeData="updateTreeData"
:fullSearchValue="fullSearchValue"
/>
</template>
</a-tree>
</div>
</template>
<template #two>
@ -342,7 +372,6 @@
total,
})
"
:style="{ alignSelf: 'flex-end', marginRight: '12px' }"
>
<template slot="buildOptionText" slot-scope="props">
<span v-if="props.value !== '100000'">{{ props.value }}{{ $t('cmdb.history.itemsPerPage') }}</span>
@ -392,6 +421,7 @@ import {
batchDeleteCIRelation,
batchUpdateCIRelationChildren,
addCIRelationView,
searchCIRelationFull,
} from '@/modules/cmdb/api/CIRelation'
import { getCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr'
@ -489,9 +519,13 @@ export default {
statisticsObj: {},
viewOption: {},
loadRootStatisticsParams: {},
fullSearchValue: '',
isFullSearch: false,
fullTreeData: [],
filterFullTreeData: [],
}
},
computed: {
windowHeight() {
return this.$store.state.windowHeight
@ -500,9 +534,6 @@ export default {
return this.windowHeight - 244
},
selectedKeys() {
if (this.treeKeys.length <= 1) {
return this.treeKeys.map((item) => `@^@${item}`)
}
return [this.treeKeys.join('@^@')]
},
isLeaf() {
@ -576,7 +607,7 @@ export default {
this.reload()
},
pageNo: function(newPage, oldPage) {
this.loadData({ pageNo: newPage }, undefined, this.sortByTable)
this.loadData({ params: { pageNo: newPage }, refreshType: undefined, sortByTable: this.sortByTable })
},
},
@ -604,7 +635,7 @@ export default {
this.loadData()
},
async loadData(parameter, refreshType = undefined, sortByTable = undefined) {
async loadData({ parameter, refreshType = undefined, sortByTable = undefined } = {}) {
// refreshType='refreshNumber' 树图只更新number
const params = Object.assign(parameter || {}, (this.$refs.search || {}).queryParam)
let q = ''
@ -624,8 +655,6 @@ export default {
const exp = expression.match(regQ) ? expression.match(regQ)[0] : null
if (exp) {
// exp = exp.replace(/(\:)/g, '$1*')
// exp = exp.replace(/(\,)/g, '*$1')
q = `${q},${exp}`
}
@ -656,38 +685,9 @@ export default {
}
if (this.treeKeys.length === 0) {
// await this.judgeCITypes(q)
if (!refreshType) {
if (!refreshType && !this.isFullSearch) {
await this.loadRoot()
}
// const fuzzySearch = (this.$refs['search'] || {}).fuzzySearch || ''
// if (fuzzySearch) {
// q = `q=_type:${this.currentTypeId[0]},*${fuzzySearch}*,` + q
// } else {
// q = `q=_type:${this.currentTypeId[0]},` + q
// }
// if (this.currentTypeId[0] && this.treeData && this.treeData.length) {
// // default select first node
// this.onNodeClick(this.treeData[0].key)
// const res = await searchCI2(q)
// const root_id = this.treeData.map((item) => item.id).join(',')
// q += `&root_id=${root_id}`
// this.pageNo = res.page
// this.numfound = res.numfound
// res.result.forEach((item, index) => (item.key = item._id))
// const jsonAttrList = this.preferenceAttrList.filter((attr) => attr.value_type === '6')
// console.log(jsonAttrList)
// this.instanceList = res['result'].map((item) => {
// jsonAttrList.forEach(
// (jsonAttr) => (item[jsonAttr.name] = item[jsonAttr.name] ? JSON.stringify(item[jsonAttr.name]) : '')
// )
// return { ..._.cloneDeep(item) }
// })
// this.initialInstanceList = _.cloneDeep(this.instanceList)
// this.calcColumns()
// }
} else {
q += `&root_id=${this.treeKeys[this.treeKeys.length - 1].split('%')[0]}`
@ -726,7 +726,7 @@ export default {
}
q += `&level=${this.topo_flatten.includes(this.currentTypeId[0]) ? 1 : level.join(',')}`
if (!refreshType) {
if (!refreshType && !this.isFullSearch) {
this.loadNoRoot(this.treeKeys[this.treeKeys.length - 1], level)
}
const fuzzySearch = (this.$refs['search'] || {}).fuzzySearch || ''
@ -812,9 +812,6 @@ export default {
this.selectedRowKeys = []
this.currentTypeId = [typeId]
this.loadColumns()
// this.$nextTick(() => {
// this.refreshTable()
// })
},
async judgeCITypes() {
@ -854,64 +851,6 @@ export default {
this.currentTypeId = [this.showTypeIds[0]]
await this.loadColumns()
}
// const showTypeIds = []
// let _showTypes = []
// let _showTypeIds = []
// if (this.treeKeys.length) {
// const typeId = parseInt(this.treeKeys[this.treeKeys.length - 1].split('%')[1])
// _showTypes = this.node2ShowTypes[typeId + '']
// _showTypes.forEach((item) => {
// _showTypeIds.push(item.id)
// })
// } else {
// _showTypeIds = JSON.parse(JSON.stringify(this.origShowTypeIds))
// _showTypes = JSON.parse(JSON.stringify(this.origShowTypes))
// }
// const promises = _showTypeIds.map((typeId) => {
// let _q = (`q=_type:${typeId},` + q).replace(/count=\d*/, 'count=1')
// if (Object.values(this.level2constraint).includes('2')) {
// _q = _q + `&has_m2m=1`
// }
// if (this.root_parent_path) {
// _q = _q + `&root_parent_path=${this.root_parent_path}`
// }
// // if (this.treeKeys.length === 0) {
// // return searchCI2(_q).then((res) => {
// // if (res.numfound !== 0) {
// // showTypeIds.push(typeId)
// // }
// // })
// // } else {
// _q = _q + `&descendant_ids=${this.descendant_ids}`
// return searchCIRelation(_q).then((res) => {
// if (res.numfound !== 0) {
// showTypeIds.push(typeId)
// }
// })
// // }
// })
// await Promise.all(promises).then(async () => {
// if (showTypeIds.length && showTypeIds.sort().join(',') !== this.showTypeIds.sort().join(',')) {
// const showTypes = []
// _showTypes.forEach((item) => {
// if (showTypeIds.includes(item.id)) {
// showTypes.push(item)
// }
// })
// console.log(showTypes)
// this.showTypes = showTypes
// this.showTypeIds = showTypeIds
// if (
// !this.currentTypeId.length ||
// (this.currentTypeId.length && !this.showTypeIds.includes(this.currentTypeId[0]))
// ) {
// this.currentTypeId = [this.showTypeIds[0]]
// await this.loadColumns()
// }
// }
// })
},
async loadRoot() {
@ -919,29 +858,41 @@ export default {
const facet = []
const ciIds = []
res.result.forEach((item) => {
facet.push([item[item.unique], 0, item._id, item._type, item.unique])
const showName = this.relationViews.id2type[item._type]?.show_name ?? null
facet.push({
showName,
showNameValue: item[showName] ?? null,
uniqueValue: item[item.unique],
number: 0,
ciId: item._id,
typeId: item._type,
unique: item.unique,
})
ciIds.push(item._id)
})
const promises = this.leaf.map((leafId) => {
const leafId = this.leaf[0]
let level = 0
this.levels.forEach((item, idx) => {
if (item.includes(leafId)) {
level = idx + 1
}
})
return statisticsCIRelation({
const params = {
level,
root_ids: ciIds.join(','),
level: level,
type_ids: this.leaf2showTypes[this.leaf[0]].join(','),
has_m2m: Number(Object.values(this.level2constraint).includes('2')),
}
this.loadRootStatisticsParams = params
await statisticsCIRelation({
...params,
type_ids: this.leaf2showTypes[this.leaf[0]].join(','),
descendant_ids: this.descendant_ids_for_statistics,
}).then((num) => {
facet.forEach((item, idx) => {
item[1] += num[ciIds[idx] + '']
item.number += num[ciIds[idx] + '']
})
})
})
await Promise.all(promises)
this.wrapTreeData(facet)
// default select first node
this.onNodeClick(this.treeData[0].key)
@ -976,7 +927,16 @@ export default {
const facet = []
const ciIds = []
res.result.forEach((item) => {
facet.push([item[item.unique], 0, item._id, item._type, item.unique])
const showName = this.relationViews.id2type[item._type]?.show_name ?? null
facet.push({
showName,
showNameValue: item[showName] ?? null,
uniqueValue: item[item.unique],
number: 0,
ciId: item._id,
typeId: item._type,
unique: item.unique,
})
ciIds.push(item._id)
})
let ancestor_ids
@ -998,7 +958,7 @@ export default {
descendant_ids: this.descendant_ids_for_statistics,
}).then((num) => {
facet.forEach((item, idx) => {
item[1] += num[ciIds[idx] + '']
item.number += num[ciIds[idx] + '']
})
})
}
@ -1009,7 +969,7 @@ export default {
}
},
onNodeClick(keys) {
onNodeClick(keys, callback = undefined) {
this.triggerSelect = true
if (keys) {
const _tempKeys = keys.split('@^@').filter((item) => item !== '')
@ -1028,19 +988,25 @@ export default {
}
this.refreshTable()
if (callback && typeof callback === 'function') {
callback()
}
},
wrapTreeData(facet) {
if (this.triggerSelect) {
return
}
const treeData = []
const _treeKeys = _.cloneDeep(this.treeKeys)
facet.forEach((item) => {
_treeKeys.push(item.ciId + '%' + item.typeId + '%' + `{"${item.unique}":"${item.uniqueValue}"}`)
treeData.push({
title: item[0],
number: item[1],
key: this.treeKeys.join('@^@') + '@^@' + item[2] + '%' + item[3] + '%' + `{"${item[4]}":"${item[0]}"}`,
isLeaf: this.leaf.includes(item[3]),
id: item[2],
title: item.showName ? item.showNameValue : item.uniqueValue,
number: item.number,
key: _treeKeys.join('@^@'),
isLeaf: this.leaf.includes(item.typeId),
id: item.ciId,
showName: item.showName,
})
})
if (this.treeNode === null) {
@ -1060,7 +1026,6 @@ export default {
}
this.treeKeys = treeNode.eventKey.split('@^@').filter((item) => item !== '')
this.treeNode = treeNode
// this.refreshTable()
resolve()
})
},
@ -1228,7 +1193,7 @@ export default {
that.$refs.xTable.clearCheckboxRow()
that.$refs.xTable.clearCheckboxReserve()
that.selectedRowKeys = []
that.loadData({}, 'refreshNumber')
that.loadData({ params: {}, refreshType: 'refreshNumber' })
})
},
})
@ -1241,9 +1206,7 @@ export default {
const _splitTargetKey = targetKey.split('@^@').filter((item) => item !== '')
if (_splitDragKey.length - 1 === _splitTargetKey.length) {
const dragId = _splitDragKey[_splitDragKey.length - 1].split('%')[0]
// const targetObj = JSON.parse(_splitTargetKey[_splitTargetKey.length - 1].split('%')[2])
const targetId = _splitTargetKey[_splitTargetKey.length - 1].split('%')[0]
// TODO 拖拽这里不造咋弄 等等再说吧
batchUpdateCIRelationChildren([dragId], [targetId]).then((res) => {
this.reload()
})
@ -1278,7 +1241,7 @@ export default {
this.sortByTable = sortByTable
this.$nextTick(() => {
if (this.pageNo === 1) {
this.loadData({}, undefined, sortByTable)
this.loadData({ params: {}, refreshType: undefined, sortByTable })
} else {
this.pageNo = 1
}
@ -1437,7 +1400,7 @@ export default {
onOk() {
deleteCI(record.ci_id || record._id).then((res) => {
that.$message.success(that.$t('deleteSuccess'))
that.loadData({}, 'refreshNumber')
that.loadData({ params: {}, refreshType: 'refreshNumber' })
})
},
})
@ -1457,7 +1420,7 @@ export default {
}
addCIRelationView(first_ci_id, ci_id, { ancestor_ids }).then((res) => {
setTimeout(() => {
this.loadData({}, 'refreshNumber')
this.loadData({ params: {}, refreshType: 'refreshNumber' })
}, 500)
})
},
@ -1495,7 +1458,7 @@ export default {
.finally(() => {
that.loading = false
setTimeout(() => {
that.loadData({})
that.loadData({ params: {} })
}, 800)
})
},
@ -1558,7 +1521,7 @@ export default {
that.selectedRowKeys = []
that.$refs.xTable.clearCheckboxRow()
that.$refs.xTable.clearCheckboxReserve()
that.loadData({}, 'refreshNumber')
that.loadData({ params: {}, refreshType: 'refreshNumber' })
})
},
})
@ -1568,7 +1531,6 @@ export default {
},
jsonEditorOk(row, column, jsonData) {
// 后端写数据有快慢不拉接口直接修改table的数据
// this.reloadData()
this.instanceList.forEach((item) => {
if (item._id === row._id) {
item[column.property] = JSON.stringify(jsonData)
@ -1577,7 +1539,7 @@ export default {
this.$refs.xTable.refreshColumn()
},
relationViewRefreshNumber() {
this.loadData({}, 'refreshNumber')
this.loadData({ params: {}, refreshType: 'refreshNumber' })
},
onShowSizeChange(current, pageSize) {
this.pageSize = pageSize
@ -1754,14 +1716,12 @@ export default {
return node[i]
}
if (node[i].children && node[i].children.length) {
for (let i = 0; i < node[i].children.length; i++) {
const found = this.findNode(node[i].children, target)
if (found) {
return found
}
}
}
}
return null
},
updateTreeData(ciId, value) {
@ -1771,6 +1731,79 @@ export default {
}
this.refreshTable()
},
handleSearchFull(e) {
const value = e.target.value
this.treeKeys = []
this.expandedKeys = []
if (!value) {
this.reload()
return
}
if (this.isFullSearch) {
this.calcFilterFullTreeData()
return
}
searchCIRelationFull({
...this.loadRootStatisticsParams,
type_ids: this.topo_flatten.join(','),
}).then((res) => {
this.isFullSearch = true
this.fullTreeData = this.formatTreeData(res)
this.calcFilterFullTreeData()
})
},
calcFilterFullTreeData() {
const _expandedKeys = []
const predicateCiIds = []
const filterTree = (node, predicate) => {
if (predicate(node)) {
predicateCiIds.push(node.id)
return true
}
if (node.children) {
node.children = node.children.filter((child) => {
if (predicateCiIds.some((id) => child.key.includes(String(id)))) {
return true
}
return filterTree(child, predicate)
})
if (node.children.length && !predicateCiIds.some((id) => node.key.includes(String(id)))) {
_expandedKeys.push(node.key)
}
return node.children.length > 0
}
return false
}
const predicate = (node) =>
String(node.title)
.toLowerCase()
.includes(this.fullSearchValue.toLowerCase())
const _fullTreeData = _.cloneDeep(this.fullTreeData)
this.filterFullTreeData = _fullTreeData.filter((item) => filterTree(item, predicate))
if (this.filterFullTreeData && this.filterFullTreeData.length) {
this.onNodeClick(this.filterFullTreeData[0].key, () => {
this.expandedKeys = _expandedKeys
})
} else {
this.treeKeys = []
this.instanceList = []
}
},
formatTreeData(array, parentKey = '') {
array.forEach((item) => {
const showName = this.relationViews.id2type[item.type_id]?.show_name ?? null
const uniqueName = this.relationViews.id2type[item.type_id]?.unique_name ?? null
const keyList = parentKey.split('@^@').filter((item) => !!item)
keyList.push(item.id + '%' + item.type_id + '%' + `{"${uniqueName}":"${item.uniqueValue}"}`)
const key = keyList.join('@^@')
item.key = key
item.showName = showName
if (!item.isLeaf && item.children && item.children.length) {
item.children = this.formatTreeData(item.children, key)
}
})
return array
},
},
}
</script>
@ -1819,6 +1852,18 @@ export default {
padding: 0 6px;
}
}
.relation-views-left-input {
margin-bottom: 12px;
input {
background-color: transparent;
border-top: none;
border-right: none;
border-left: none;
}
.ant-input:focus {
box-shadow: none;
}
}
}
.relation-views-right {
width: 100%;

View File

@ -27,7 +27,13 @@
/>
<span class="relation-views-node-icon" v-else>{{ icon ? icon[0].toUpperCase() : 'i' }}</span>
</template>
<span class="relation-views-node-title" v-if="!isEditNodeName" :title="title">{{ title }}</span>
<span
class="relation-views-node-title"
v-if="!isEditNodeName"
:title="title"
v-highlight="{ value: fullSearchValue, class: 'relation-views-node-title-highlight' }"
>{{ title }}
</span>
<a-input
ref="input"
@blur="changeNodeName"
@ -67,10 +73,7 @@
key="editNodeName"
><ops-icon type="icon-xianxing-edit" />{{ $t('cmdb.serviceTree.editNodeName') }}</a-menu-item
>
<a-menu-item
key="batch"
><ops-icon type="veops-copy" />{{ $t('cmdb.serviceTree.batch') }}</a-menu-item
>
<a-menu-item key="batch"><ops-icon type="veops-copy" />{{ $t('cmdb.serviceTree.batch') }}</a-menu-item>
</template>
<template v-else>
<a-menu-item
@ -103,20 +106,17 @@
<script>
import { updateCI } from '../../../api/ci.js'
import highlight from '@/directive/highlight'
export default {
name: 'ContextMenu',
directives: {
highlight,
},
props: {
title: {
type: String,
default: '',
},
number: {
type: Number,
default: 0,
},
treeKey: {
type: String,
default: '',
treeNodeData: {
type: Object,
default: () => {},
},
levels: {
type: Array,
@ -130,10 +130,6 @@ export default {
type: Object,
default: () => {},
},
isLeaf: {
type: Boolean,
default: () => false,
},
ciTypeIcons: {
type: Object,
default: () => {},
@ -146,6 +142,10 @@ export default {
type: Array,
default: () => [],
},
fullSearchValue: {
type: String,
default: '',
},
},
data() {
return {
@ -201,6 +201,21 @@ export default {
showCheckbox() {
return this.showBatchLevel === this.treeKey.split('@^@').filter((item) => !!item).length - 1
},
title() {
return this.treeNodeData.title
},
number() {
return this.treeNodeData.number
},
treeKey() {
return this.treeNodeData.key
},
isLeaf() {
return this.treeNodeData.isLeaf
},
showName() {
return this.treeNodeData.showName
},
},
methods: {
onContextMenuClick(treeKey, menuKey) {
@ -230,8 +245,11 @@ export default {
.split('%')
const unique = Object.keys(JSON.parse(ci[2]))[0]
const ciId = Number(ci[0])
updateCI(ciId, { [unique]: value }).then((res) => {
let editAttrName = unique
if (this.showName) {
editAttrName = this.showName
}
updateCI(ciId, { [editAttrName]: value }).then((res) => {
this.$message.success(this.$t('updateSuccess'))
this.$emit('updateTreeData', ciId, value)
})
@ -244,7 +262,6 @@ export default {
</script>
<style lang="less" scoped>
.relation-views-node {
width: 100%;
display: inline-flex;
@ -313,6 +330,9 @@ export default {
</style>
<style lang="less">
.relation-views-node-title-highlight {
color: @func-color_1;
}
.relation-views-left {
ul:has(.relation-views-node-checkbox) > li > ul {
margin-left: 26px;

View File

@ -1,33 +0,0 @@
import { getCompanyInfo } from '@/api/company'
const logo = {
state: {
file_name: '',
small_file_name: ''
},
mutations: {
SET_FILENAME: (state, name) => {
state.file_name = name
},
SET_SMALL_FILENAME: (state, name) => {
state.small_file_name = name
}
},
actions: {
getCompanyInfo({ commit }) {
return new Promise((resolve, reject) => {
getCompanyInfo().then(res => {
if (res.info) {
commit('SET_FILENAME', res.info.logoName)
commit('SET_SMALL_FILENAME', res.info.smallLogoName)
resolve(res.info)
}
}).catch(err => {
console.log('获取失败', err)
reject(err)
})
})
}
}
}
export default logo

View File

@ -5,7 +5,6 @@ import Vuex from 'vuex'
import app from './global/app'
import user from './global/user'
import routes from './global/routes'
import logo from './global/logo'
import notice from './global/notice'
import getters from './global/getters'
import appConfig from '@/config/app'
@ -17,7 +16,6 @@ const store = new Vuex.Store({
app,
user,
routes,
logo,
notice
},
state: {

View File

@ -1352,3 +1352,11 @@ body {
.ant-tree li .ant-tree-node-content-wrapper:hover {
background-color: @primary-color_3;
}
.ant-pagination-options-size-changer.ant-select {
margin-right: 0;
}
.ant-form-explain{
font-size: 12px;
}

View File

@ -130,22 +130,30 @@ export const isEmptySubDepartments = (item) => {
// format部门员工树
export const formatOption = (data, idType = 1, isDisabledAllCompany, departmentKey = 'department_id', employeeKey = 'employee_id') => {
// idType 1 表示 员工id为`${department_id}-${employee_id}`
// 2 表示 department-${department_id} employee-${employee_id}
// idType 1 表示 员工id为`${departmentKey}-${employeeKey}`
// 2 表示 department-${departmentKey} employee-${employeeKey}
// 3 表示 departmentKey employeeKey
let _data = _.cloneDeep(data)
_data = _data.filter((item) => {
return item.employees.length || (item.sub_departments.length && !isEmptySubDepartments(item))
})
const switchEmployeeIdType = (item, employee) => {
switch (idType) {
case 1: return `${item[departmentKey]}-${employee[employeeKey]}`
case 2: return `employee-${employee[employeeKey]}`
case 3: return `${employee[employeeKey]}`
}
}
_data.forEach((item) => {
if (isDisabledAllCompany) {
item.isDisabled = !item.department_id
}
item.id = idType === 1 ? item[departmentKey] : `department-${item[departmentKey]}`
item.id = [1, 3].includes(idType) ? item[departmentKey] : `department-${item[departmentKey]}`
item.label = item.department_name
item.children = [
...formatOption(
item.sub_departments.map((dep) => {
return { ...dep, id: idType === 1 ? dep[departmentKey] : `department-${dep[departmentKey]}`, label: dep.department_name }
return { ...dep, id: [1, 3].includes(idType) ? dep[departmentKey] : `department-${dep[departmentKey]}`, label: dep.department_name }
}),
idType,
isDisabledAllCompany,
@ -153,7 +161,7 @@ export const formatOption = (data, idType = 1, isDisabledAllCompany, departmentK
employeeKey
),
...item.employees.map((employee) => {
return { ...employee, id: idType === 1 ? `${item[departmentKey]}-${employee[employeeKey]}` : `employee-${employee[employeeKey]}`, label: employee.nickname }
return { ...employee, id: switchEmployeeIdType(item, employee), label: employee.nickname }
}),
]
})

View File

@ -3,140 +3,62 @@
<a-form-model ref="infoData" :model="infoData" :label-col="labelCol" :wrapper-col="wrapperCol" :rules="rule">
<SpanTitle>{{ $t('cs.companyInfo.spanCompany') }}</SpanTitle>
<a-form-model-item :label="$t('cs.companyInfo.name')" prop="name">
<a-input v-model="infoData.name" :disabled="!isEditable"/>
<a-input v-model="infoData.name" :disabled="!isEditable" />
</a-form-model-item>
<a-form-model-item :label="$t('cs.companyInfo.description')">
<a-input v-model="infoData.description" type="textarea" :disabled="!isEditable"/>
<a-input v-model="infoData.description" type="textarea" :disabled="!isEditable" />
</a-form-model-item>
<SpanTitle>{{ $t('cs.companyInfo.spanAddress') }}</SpanTitle>
<a-form-model-item :label="$t('cs.companyInfo.country')">
<a-input v-model="infoData.country" :disabled="!isEditable"/>
<a-input v-model="infoData.country" :disabled="!isEditable" />
</a-form-model-item>
<a-form-model-item :label="$t('cs.companyInfo.city')">
<a-input v-model="infoData.city" :disabled="!isEditable"/>
<a-input v-model="infoData.city" :disabled="!isEditable" />
</a-form-model-item>
<a-form-model-item :label="$t('cs.companyInfo.address')">
<a-input v-model="infoData.address" :disabled="!isEditable"/>
<a-input v-model="infoData.address" :disabled="!isEditable" />
</a-form-model-item>
<a-form-model-item :label="$t('cs.companyInfo.postcode')">
<a-input v-model="infoData.postCode" :disabled="!isEditable"/>
<a-input v-model="infoData.postCode" :disabled="!isEditable" />
</a-form-model-item>
<SpanTitle>{{ $t('cs.companyInfo.spanContract') }}</SpanTitle>
<a-form-model-item :label="$t('cs.companyInfo.website')">
<a-input v-model="infoData.website" :disabled="!isEditable"/>
<a-input v-model="infoData.website" :disabled="!isEditable" />
</a-form-model-item>
<a-form-model-item :label="$t('cs.companyInfo.phone')" prop="phone">
<a-input v-model="infoData.phone" :disabled="!isEditable"/>
<a-input v-model="infoData.phone" :disabled="!isEditable" />
</a-form-model-item>
<a-form-model-item :label="$t('cs.companyInfo.faxCode')" prop="faxCode">
<a-input v-model="infoData.faxCode" :disabled="!isEditable"/>
<a-input v-model="infoData.faxCode" :disabled="!isEditable" />
</a-form-model-item>
<a-form-model-item :label="$t('cs.companyInfo.email')" prop="email">
<a-input v-model="infoData.email" :disabled="!isEditable"/>
<a-input v-model="infoData.email" :disabled="!isEditable" />
</a-form-model-item>
<SpanTitle>{{ $t('cs.companyInfo.spanLogo') }}</SpanTitle>
<a-form-model-item :label="$t('cs.companyInfo.messenger')" prop="messenger">
<a-input v-model="infoData.messenger" :disabled="!isEditable"/>
<a-input v-model="infoData.messenger" :disabled="!isEditable" />
</a-form-model-item>
<a-form-model-item :label="$t('cs.companyInfo.domainName')" prop="domainName">
<a-input v-model="infoData.domainName" :disabled="!isEditable"/>
</a-form-model-item>
<a-form-model-item :label="$t('cs.companyInfo.logo')">
<a-space>
<a-upload
:disabled="!isEditable"
name="avatar"
list-type="picture-card"
class="avatar-uploader"
:show-upload-list="false"
:customRequest="customRequest"
:before-upload="beforeUpload"
:style="{ width: '400px', height: '80px' }"
accept=".png,.jpg,.jpeg"
>
<div
class="ops-setting-companyinfo-upload-show"
v-if="infoData.logoName"
:style="{ width: '400px', height: '80px' }"
@click="eidtImageOption.type = 'Logo'"
>
<img :src="`/api/common-setting/v1/file/${infoData.logoName}`" alt="avatar"/>
<a-icon
v-if="isEditable"
type="minus-circle"
theme="filled"
class="delete-icon"
@click.stop="deleteLogo"
/>
</div>
<div v-else @click="eidtImageOption.type = 'Logo'">
<a-icon type="plus"/>
<div class="ant-upload-text">{{ $t('cs.companyInfo.upload') }}</div>
</div>
</a-upload>
<a-upload
:disabled="!isEditable"
name="avatar"
list-type="picture-card"
class="avatar-uploader"
:show-upload-list="false"
:customRequest="customRequest"
:before-upload="beforeUpload"
:style="{ width: '82px', height: '82px' }"
accept=".png,.jpg,.jpeg"
>
<div
class="ops-setting-companyinfo-upload-show"
v-if="infoData.smallLogoName"
:style="{ width: '82px', height: '82px' }"
@click="eidtImageOption.type = 'SmallLogo'"
>
<img :src="`/api/common-setting/v1/file/${infoData.smallLogoName}`" alt="avatar"/>
<a-icon
v-if="isEditable"
type="minus-circle"
theme="filled"
class="delete-icon"
@click.stop="deleteSmallLogo"
/>
</div>
<div v-else @click="eidtImageOption.type = 'SmallLogo'">
<a-icon type="plus"/>
<div class="ant-upload-text">{{ $t('cs.companyInfo.upload') }}</div>
</div>
</a-upload>
</a-space>
<a-input v-model="infoData.domainName" :disabled="!isEditable" />
</a-form-model-item>
<a-form-model-item :wrapper-col="{ span: 14, offset: 3 }" v-if="isEditable">
<a-button type="primary" @click="onSubmit"> {{ $t('save') }}</a-button>
<a-button ghost type="primary" style="margin-left: 28px" @click="resetForm"> {{ $t('reset') }}</a-button>
</a-form-model-item>
</a-form-model>
<edit-image
v-if="showEditImage"
:show="showEditImage"
:image="editImage"
:title="eidtImageOption.title"
:eidtImageOption="eidtImageOption"
@save="submitImage"
@close="showEditImage = false"
/>
</div>
</template>
<script>
import { getCompanyInfo, postCompanyInfo, putCompanyInfo } from '@/api/company'
import { postImageFile } from '@/api/file'
import { mapMutations, mapState } from 'vuex'
import { mapState } from 'vuex'
import SpanTitle from '../components/spanTitle.vue'
import EditImage from '../components/EditImage.vue'
import { mixinPermissions } from '@/utils/mixin'
export default {
name: 'CompanyInfo',
mixins: [mixinPermissions],
components: { SpanTitle, EditImage },
components: { SpanTitle },
data() {
return {
labelCol: { span: 3 },
@ -152,14 +74,10 @@ export default {
phone: '',
faxCode: '',
email: '',
logoName: '',
smallLogoName: '',
messenger: '',
domainName: '',
},
getId: -1,
showEditImage: false,
editImage: null
}
},
async mounted() {
@ -210,26 +128,8 @@ export default {
],
}
},
eidtImageOption () {
return {
type: 'Logo',
fixedNumber: [15, 4],
title: this.$t('cs.companyInfo.editCompanyLogo'),
previewWidth: '200px',
previewHeight: '40px',
autoCropWidth: 200,
autoCropHeight: 40,
}
}
},
methods: {
...mapMutations(['SET_FILENAME', 'SET_SMALL_FILENAME']),
deleteLogo() {
this.infoData.logoName = ''
},
deleteSmallLogo() {
this.infoData.smallLogoName = ''
},
async onSubmit() {
this.$refs.infoData.validate(async (valid) => {
if (valid) {
@ -238,8 +138,6 @@ export default {
} else {
await putCompanyInfo(this.getId, this.infoData)
}
this.SET_FILENAME(this.infoData.logoName)
this.SET_SMALL_FILENAME(this.infoData.smallFileName)
this.$message.success(this.$t('saveSuccess'))
} else {
this.$message.warning(this.$t('cs.companyInfo.checkInputCorrect'))
@ -259,70 +157,10 @@ export default {
phone: '',
faxCode: '',
email: '',
logoName: '',
smallLogoName: '',
messenger: '',
domainName: '',
}
},
customRequest(file) {
const reader = new FileReader()
var self = this
if (this.eidtImageOption.type === 'Logo') {
this.eidtImageOption = {
type: 'Logo',
fixedNumber: [20, 4],
title: this.$t('cs.companyInfo.editCompanyLogo'),
previewWidth: '200px',
previewHeight: '40px',
autoCropWidth: 200,
autoCropHeight: 40,
}
} else if (this.eidtImageOption.type === 'SmallLogo') {
this.eidtImageOption = {
type: 'SmallLogo',
fixedNumber: [4, 4],
title: this.$t('cs.companyInfo.editCompanyLogoSmall'),
previewWidth: '80px',
previewHeight: '80px',
autoCropWidth: 250,
autoCropHeight: 250,
}
}
reader.onload = function (e) {
let result
if (typeof e.target.result === 'object') {
// 把Array Buffer转化为blob 如果是base64不需要
result = window.URL.createObjectURL(new Blob([e.target.result]))
} else {
result = e.target.result
}
self.editImage = result
self.showEditImage = true
}
reader.readAsDataURL(file.file)
},
submitImage(file) {
postImageFile(file).then((res) => {
if (res.file_name) {
if (this.eidtImageOption.type === 'Logo') {
this.infoData.logoName = res.file_name
} else if (this.eidtImageOption.type === 'SmallLogo') {
this.infoData.smallLogoName = res.file_name
}
} else {
}
})
},
beforeUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 2
if (!isLt2M) {
this.$message.error(this.$t('cs.companyInfo.imageSizeLimit2MB'))
}
return isLt2M
},
},
}
</script>