feat: terminal日志相关
This commit is contained in:
Binary file not shown.
@@ -20,6 +20,39 @@ Created by iconfont
|
||||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="fast-forward" unicode="" d="M170.08082177-39.14113205000001C136.50949938-39.14113205000001 120.80526686-1.62024150000002 120.80526686 31.38685650000002V736.66674459C120.80526686 772.68303734 137.92005867 807.19473315 170.08082177 807.19473315c12.50696323-0.94037342 24.54373978-4.9839776 34.88784483-11.9427397l557.35918571-352.63994361a70.33991404 70.33991404 0 0 0 35.5461069-61.03021926 70.33991404 70.33991404 0 0 0-35.5461069-61.03022008L202.1475472-32.088333120000016a64.13345084 64.13345084 0 0 0-32.06672543-6.95876128zM621.45994971-39.14113205000001c-33.5713224 0-49.2755549 37.42685289-49.27555491 70.52798856V736.66674459c0 36.01629275 17.11479181 70.52798856 49.27555491 70.52798856 12.50696323-0.94037342 24.54373978-4.9839776 34.88784483-11.9427397l557.35918572-352.63994361a70.33991404 70.33991404 0 0 0 35.54610688-61.03021926 70.33991404 70.33991404 0 0 0-35.54610688-61.03022008l-560.18030513-352.63994362a64.13345084 64.13345084 0 0 0-32.06672542-6.95876128z" horiz-adv-x="1365" />
|
||||
|
||||
|
||||
<glyph glyph-name="replay" unicode="" d="M230.26081622 205.72049206999998l125.72164273 182.98336441a15.88397269 15.88397269 0 0 1-13.18369679 24.69957716h-78.14914534A333.56342394 333.56342394 0 0 0 549.29040543 713.37225613a335.54892053 335.54892053 0 0 0 360.32791752-204.90324669A330.62488941 330.62488941 0 0 0 792.15634589 113.59345166000003a337.53441712 337.53441712 0 0 0-380.18288338-4.84461214 46.85771893 46.85771893 0 0 1-62.90053127-10.0863226 46.06352064 46.06352064 0 0 1 11.03936054-66.71268479 431.88521445 431.88521445 0 0 1 491.92663102 9.37154413 423.06960999 423.06960999 0 0 1 142.63807405 508.28712268C917.63972912 731.32114523 724.80830247 836.71130312 528.7206611 804.30799911c-196.00822152-32.48272385-343.96742585-194.18156461-357.38938298-390.90456547H91.03779655a15.88397269 15.88397269 0 0 1-13.18369765-24.62015734L203.97284163 205.72049206999998a15.96339252 15.96339252 0 0 1 26.28797459 0z" horiz-adv-x="1117" />
|
||||
|
||||
|
||||
<glyph glyph-name="play" unicode="" d="M213.36854709-52.78764302000002C178.68528487-52.78764302000002 162.52305909-14.085664749999978 162.52305909 20.160781179999958V748.07247933C162.52305909 785.20191632 180.17046204 820.84617615 213.36854709 820.84617615c12.92978081-0.87363348 25.33538117-5.24180258 36.081077-12.40560038L824.73749408 444.4847267c22.71447903-13.10450733 36.69262068-37.04207374 36.69261983-62.90163448 0-26.03428812-13.9781408-50.0592178-36.69261983-63.07636187L246.39190562-45.44911870999999a66.22144358 66.22144358 0 0 0-33.19808506-7.25116021z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="suspend" unicode="" d="M207.96632006 820.84617615m87.36923523 0l0 0q87.36923523 0 87.36923523-87.36923524l0-698.95388182q0-87.36923523-87.36923523-87.36923524l0 0q-87.36923523 0-87.36923523 87.36923524l0 698.95388182q0 87.36923523 87.36923523 87.36923524ZM644.81249621 820.84617615m87.36923523 0l0 0q87.36923523 0 87.36923522-87.36923524l0-698.95388182q0-87.36923523-87.36923522-87.36923524l0 0q-87.36923523 0-87.36923523 87.36923524l0 698.95388182q0 87.36923523 87.36923523 87.36923524Z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="drop-down" unicode="" d="M86.7501044 722.52498402l433.03370011-418.33978344a40.11042154 40.11042154 0 0 1 59.01394754 0L1011.75202551 722.52498402a37.17163787 37.17163787 0 0 1 0.23827997 53.93064588 40.42812817 40.42812817 0 0 1-55.8368839 0.23827997l-0.23827996-0.23827997L549.33049118 383.53235134 142.74584159 776.53505655A40.42812817 40.42812817 0 0 1 86.90895771 776.77333652a37.17163787 37.17163787 0 0 1-0.23827997-54.01007254l0.07942666-0.23827996zM1014.37310257 481.30646813a40.50755481 40.50755481 0 0 1-55.83688389 0L551.55443582 88.22433625999997 144.89035872 481.30646813a40.42812817 40.42812817 0 0 1-55.91631054 0.15885331 37.33049118 37.33049118 0 0 1-0.15885331-53.93064588l0.15885331-0.15885331L522.32545492 8.877185510000004l1.50910473-1.66795805a39.71328913 39.71328913 0 0 1 55.83688475 0l1.50910474 1.58853139 433.03370012 418.49863674a37.17163787 37.17163787 0 0 1 0.15885331 53.93064588z" horiz-adv-x="1117" />
|
||||
|
||||
|
||||
<glyph glyph-name="replay2" unicode="" d="M511.99927221-52.84617615000002A437.42771482 437.42771482 0 0 0 75.15382385 383.99927220999996v33.98980732a26.78425915 26.78425915 0 0 0 26.78425915 26.78425915h2.18349968a32.38857496 32.38857496 0 0 0 31.00569147-33.69867408v-26.78425917a377.67261424 377.67261424 0 0 1 377.67261424-377.67261422A377.89096395 377.89096395 0 1 1 253.25459267 658.5379307000001l-26.78426-26.78425915 89.23234236-24.67354301a20.88881098 20.88881098 0 0 0 14.41109633-25.11024328 19.57871101 19.57871101 0 0 0-18.99644454-14.77501308h-5.09483201L146.62703814 611.9566099900001a16.88572837 16.88572837 0 0 0-11.71811371 21.39829476l11.49976315 42.86937135L178.50612931 799.1552934a16.88572837 16.88572837 0 0 0 17.1768616 12.59151257h4.51256555a18.19582835 18.19582835 0 0 0 12.59151339-21.98056039L183.09147837 678.91725874l50.94831921 42.28710574a436.84544836 436.84544836 0 1 0 277.95947463-774.05054063zM436.74132589 231.59101312999996c-12.5915134 0-18.48696159 14.19274576-18.4869616 26.78426v267.84259415c0 13.68326281 6.40493198 26.78425915 18.4869616 26.78425915a26.78425915 26.78425915 0 0 0 13.10099635-4.51256554l209.17924381-133.92129664a26.78425915 26.78425915 0 0 0 0-46.36297101l-210.27099323-133.9212975a23.87292683 23.87292683 0 0 0-12.00924694-2.69298261z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="JC" unicode="" d="M510.45038204 506.72575677a123.79044134 123.79044134 0 0 1 0-247.58088267 123.79044134 123.79044134 0 0 1 0 247.58088267z m0-191.33885552a67.54841419 67.54841419 0 0 0 0 135.02435114 67.54841419 67.54841419 0 0 0 0-135.02435114z m406.52259184 95.66942775h-30.07788906a377.02451795 377.02451795 0 0 1-109.51250376 239.31852342A376.15479561 376.15479561 0 0 1 538.35396481 760.1772633200001V790.25515153a28.12101357 28.12101357 0 1 1-56.09707356 0v-30.07788821A376.15479561 376.15479561 0 0 1 243.44570666 650.44732878 377.02451795 377.02451795 0 0 1 133.93320206 411.056329H103.34797589a28.12101357 28.12101357 0 0 1 0-56.24202715H134.00567927A377.02451795 377.02451795 0 0 1 243.44570666 115.49577843999998a376.15479561 376.15479561 0 0 1 238.88366181-109.80241177v-28.91825869a28.12101357 28.12101357 0 1 1 56.16955078 0v28.91825869a376.15479561 376.15479561 0 0 1 238.88366181 109.80241177 377.02451795 377.02451795 0 0 1 109.51250376 239.31852341h30.07788906a28.12101357 28.12101357 0 0 1 0 56.24202715zM538.42644204 62.152824630000055V127.67188696000005a28.12101357 28.12101357 0 1 1-56.16955079 0v-65.5915387a322.23202747 322.23202747 0 0 0-292.08166204 292.66147638h68.49061373a28.12101357 28.12101357 0 0 1 0 56.24202715h-68.41813653a322.23202747 322.23202747 0 0 0 291.93670848 292.589v-63.41723412a28.12101357 28.12101357 0 1 1 56.09707357 0v63.48971134a322.23202747 322.23202747 0 0 0 292.22661563-292.66147722h-68.99795086a28.12101357 28.12101357 0 0 1 0-56.24202715h68.99795086a322.23202747 322.23202747 0 0 0-292.08166205-292.66147638z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="A-" unicode="" d="M417.66990745 820.84617615h144.76410199l321.18275026-833.83853948H746.98471736L668.75564795 201.93595533999996H310.20574812l-78.22906941-214.92831867H96.48715719L417.66990745 820.84617615zM348.71541853 307.04786608999996H630.11156287L492.33699969 684.28134071h-4.63729025L348.84983319 307.04786608999996h-0.13441466z m599.08412519 377.56951001H1171.8008213V595.03030696h-358.41548516V684.6173761h134.41420758z" horiz-adv-x="1260" />
|
||||
|
||||
|
||||
<glyph glyph-name="A" unicode="" d="M421.28438951 785.86139981h140.2402238l311.14578932-807.78108513H740.30811161L664.52370062 186.29212340000004H317.17848516l-75.78441099-208.21180872H110.13860019L421.28438951 785.86139981zM354.48472837 288.11928693000004H627.0872432L493.61813512 653.56421547h-4.49237493L354.61494257 288.11928693000004h-0.1302142z m580.36274628 365.77046283v130.21376442H1021.6349487v-130.21376442h130.21376359V567.1022765299999h-130.21376359v-130.21376443h-86.78747405v130.21376443h-130.2137636V653.88974976h130.2137636z" horiz-adv-x="1260" />
|
||||
|
||||
|
||||
<glyph glyph-name="terminal-log" unicode="" d="M593.90865802 33.759595880000006H129.75959587c-32.76346322 0-54.60577202 21.8423088-54.60577202 54.60577202v655.26926422C75.15382385 776.39809534 96.99613266 798.24040414 129.75959587 798.24040414H730.42308807c32.76346322 0 54.60577202-21.8423088 54.60577203-54.60577202v-294.87116889H730.42308807V743.63463212H129.75959587v-655.26926422h409.54329014l54.60577202-54.60577202zM703.12020206 416.00000001c103.75096683 0 191.12020206-87.36923523 191.12020207-191.12020206s-87.36923523-191.12020206-191.12020207-191.12020207S512 121.12883111999997 512 224.87979795 599.36923523 416.00000001 703.12020206 416.00000001z m0 54.60577202A244.70666606 244.70666606 0 0 1 457.39422798 224.87979795C457.39422798 88.36536790000002 566.60577202-20.84617614000001 703.12020206-20.84617614000001S948.84617615 88.36536790000002 948.84617615 224.87979795 839.63463211 470.60577203 703.12020206 470.60577203z m-491.45194816 109.21154403h436.84617615c16.38173161 0 27.30288601-10.9211544 27.30288601-27.302886s-10.9211544-27.30288601-27.30288601-27.30288601h-436.84617615c-16.38173161 0-27.30288601 10.9211544-27.30288601 27.30288601s10.9211544 27.30288601 27.30288601 27.302886z m0-163.81731605h218.42308807c16.38173161 0 27.30288601-10.9211544 27.30288602-27.30288601s-10.9211544-27.30288601-27.30288602-27.30288601h-218.42308807c-16.38173161 0-27.30288601 10.9211544-27.30288601 27.30288601S195.28652229 416.00000001 211.6682539 416.00000001z m0-163.81731606h163.81731605c16.38173161 0 27.30288601-10.9211544 27.30288601-27.302886S391.86730157 197.57691193999995 375.48556995 197.57691193999995h-163.81731605C195.28652229 197.57691193999995 184.36536789 208.49806633000003 184.36536789 224.87979795s10.9211544 27.30288601 27.30288601 27.302886z m611.5846466-87.36923522h-87.36923522c-32.76346322 0-54.60577202 21.8423088-54.60577202 54.60577201V334.09134199000005c0 16.38173161 10.9211544 27.30288601 27.30288601 27.302886s27.30288601-10.9211544 27.30288601-27.302886v-120.13269845h87.36923522c10.9211544 0 21.8423088-10.9211544 21.84230882-21.84230881s-10.9211544-27.30288601-21.84230882-27.302886z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="ZD" unicode="" d="M619.53696675 554.58775367c0 16.3089242-10.9211544 27.15727033-27.23007776 27.15727032H265.69156407c-16.3089242 0-27.2300786-10.9211544-27.23007776-27.15727032 0-16.38173161 10.9211544-27.2300786 27.23007776-27.23007859h326.61532492c16.3089242 0 27.2300786 10.9211544 27.23007776 27.23007859z m-353.84540268-136.15039214c-16.3089242 0-27.2300786-10.9211544-27.23007776-27.15727033 0-16.38173161 10.9211544-27.2300786 27.23007776-27.2300786H428.99922654c16.3089242 0 27.2300786 10.9211544 27.23007859 27.2300786s-10.9211544 27.15727033-27.23007859 27.15727033H265.69156407z m435.4628302 54.46015719A243.90578197 243.90578197 0 0 1 456.22930512 227.97242873000005a243.90578197 243.90578197 0 0 1 244.92508916-244.99789655 243.90578197 243.90578197 0 0 1 244.9978974 244.99789655 243.90578197 243.90578197 0 0 1-244.9978974 244.92508999z m1e-8-435.46283021c-103.38692806 0-190.53774021 87.07800474-190.53774022 190.53774022 0 103.38692806 87.15081214 190.4649328 190.53774021 190.4649328s190.53774021-87.07800474 190.53774021-190.4649328c0-103.45973634-87.07800474-190.53774021-190.53774021-190.53774022zM810.00189955 255.12969991h-217.69501056c-16.3089242 0-27.2300786-10.9211544-27.23007859-27.15727118 0-16.38173161 10.9211544-27.2300786 27.23007859-27.23007774h217.69501056c16.38173161 0 27.2300786 10.9211544 27.2300786 27.23007774s-10.9211544 27.15727033-27.2300786 27.15727118zM428.99922654 37.43468851H184.00132913c-32.61784753 0-54.38734893 21.76950139-54.38734894 54.38734894V690.66533753c0 32.61784753 21.76950139 54.38734893 54.38734894 54.38734894h489.99579481c32.61784753 0 54.38734893-21.76950139 54.38734893-54.38734894v-136.15039213c0-16.3089242 10.9211544-27.15727033 27.23007775-27.15727032s27.2300786 10.9211544 27.23007859 27.23007859V690.66533753A109.21154404 109.21154404 0 0 1 673.92431567 799.5128428099999H184.00132913A109.21154404 109.21154404 0 0 1 75.15382385 690.66533753V91.82203745000004a109.21154404 109.21154404 0 0 1 108.84750528-108.84750527H428.99922654c16.3089242 0 27.2300786 10.9211544 27.23007859 27.23007774s-10.9211544 27.2300786-27.23007859 27.23007859z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="revoke1" unicode="" d="M444.51696428 665.85277317h437.50983336L796.94424055 752.48106438a40.05466394 40.05466394 0 0 0 0 56.45288137 38.44172462 38.44172462 0 0 0 55.51200003 0l152.01954619-154.57336599a40.05466394 40.05466394 0 0 0 0-56.52008827L852.38903539 443.13271339a39.1809878 39.1809878 0 0 0-55.51200089 0 40.05466394 40.05466394 0 0 0 0 56.45288222l85.2169692 86.22505574H444.51696428c-160.48747825 0-290.79954668-125.47325044-290.79954667-279.57617577 0-154.23733744 130.37927447-279.64338183 290.79954667-279.64338269h401.75634153c21.64027172 0 39.1137826-17.74233424 39.11378259-39.78584057a39.3153999 39.3153999 0 0 0-39.11378259-39.71863452H444.51696428C240.74894344-52.84617615000002 75.15382385 108.44777135000004 75.15382385 306.70491625c0 197.78670337 165.59511959 359.14785692 369.36314043 359.14785692z" horiz-adv-x="1102" />
|
||||
|
||||
|
||||
@@ -38,7 +71,7 @@ Created by iconfont
|
||||
<glyph glyph-name="batch-edit" unicode="" d="M744.7552 374.88127999999995l-58.71616-58.7264-174.92992-174.91968c-0.34816-0.28672-0.7424-0.4352-1.08544-0.73728-1.42848-1.28-3.01568-2.37056-4.736-3.20512-0.5888-0.25088-1.18784-0.64512-1.87904-0.8448-2.22208-0.83456-4.63872-1.3824-7.15264-1.3824H437.59104a21.06368 21.06368 0 0 0-21.07392 21.0688v58.72128c0.0512 2.46272 0.50176 4.87936 1.3824 7.15264 0.25088 0.58368 0.59392 1.22368 0.93696 1.8688 0.8448 1.72544 1.87392 3.30752 3.15904 4.736l-0.05632-0.0512c0.30208 0.35328 0.39936 0.78848 0.74752 1.13664l174.96576 174.9248 58.71616 58.72128a21.04832 21.04832 0 0 0 29.75744 0.0512l58.6752-58.7264a21.00224 21.00224 0 0 0-0.04608-29.78816z m-132.29056-14.90944l-145.17248-145.16224 28.96384-28.91776 145.27488 145.17248-28.96384 28.96384-0.1024-0.05632z m29.8496 29.80352l28.96384-28.90752 28.91776 28.90752-28.91776 28.91264-28.96384-28.91264zM862.44352 659.54304H304.91648c-41.18528 0-75.05408-33.86368-75.05408-75.04896v-557.65504c0-41.1904 33.86368-75.05408 75.05408-75.05408h557.65504c41.1904 0 75.05408 33.86368 75.05408 75.05408V584.4940799999999c-0.13312 41.3184-33.86368 75.04896-75.18208 75.04896z m-4.18304-584.84736c0-24.05888-19.74272-43.80672-43.80672-43.80672H352.768c-24.05888 0-43.8016 19.74272-43.8016 43.80672V536.50944c0 24.05888 19.74272 43.8016 43.8016 43.8016h461.81376c24.05888 0 43.8016-19.74272 43.8016-43.8016v-461.81376h-0.12288zM263.33696 156.93312000000003h-20.00384c-24.05888 0-43.8016 19.74272-43.8016 43.8016V662.42048c0 24.05888 19.7376 43.8016 43.8016 43.8016h461.81376c24.05888 0 43.8016-19.74272 43.8016-43.8016v-38.57408h79.24224V710.4102399999999c0 41.18528-33.86368 75.04896-75.05408 75.04896H195.34336c-41.18528 0-75.04896-33.86368-75.04896-75.04896v-557.66016c0-41.18528 33.86368-75.04896 75.04896-75.04896h67.9936v79.232z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="sanjiaoxing" unicode="" d="M959.51284282 384L85.82049052 820.84617615v-873.6923523z" horiz-adv-x="1024" />
|
||||
<glyph glyph-name="triangle" unicode="" d="M959.51284282 384L85.82049052 820.84617615v-873.6923523z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="push-pin-line" unicode="" d="M768 810.66666668v-85.333333h-42.666667v-256l85.333334-128v-85.333334h-256v-298.666666h-85.333334v298.666666H213.333333v85.333334l85.333334 128V725.33333368H256V810.66666668h512zM384 725.33333368v-281.856L315.904 341.33333368h392.192L640 443.47733368V725.33333368H384z" horiz-adv-x="1024" />
|
||||
|
||||
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 143 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -31,8 +31,8 @@
|
||||
@changeTab="changeTab" :targetTab.sync="targetTab" :detail="detail"></panel-tab>
|
||||
|
||||
<!--terminal-log的记录和回放-->
|
||||
<terminal-log-cmd-tab :from="from" :obj="obj" @changeTab="changeTab" ref="reminalLogCMDTab" v-if="from == $CONSTANTS.fromRoute.terminalLog && targetTab == 'cmd'"></terminal-log-cmd-tab>
|
||||
<terminal-log-record-tab :from="from" :obj="obj" @changeTab="changeTab" ref="reminalLogRecordTab" v-if="from == $CONSTANTS.fromRoute.terminalLog && targetTab == 'record'"></terminal-log-record-tab>
|
||||
<terminal-log-replay-tab :from="from" :obj="obj" @changeTab="changeTab" ref="reminalLogReplayTab" v-if="from == $CONSTANTS.fromRoute.terminalLog && targetTab == 'replay'"></terminal-log-replay-tab>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -45,7 +45,7 @@
|
||||
import endpointTab from "./tabs/endpointTab";
|
||||
import panelTab from "./tabs/panelTab";
|
||||
import terminalLogRecordTab from "./tabs/terminalLogRecordTab";
|
||||
import terminalLogReplayTab from "./tabs/terminalLogReplayTab";
|
||||
import terminalLogCMDTab from "./tabs/terminalLogCMDTab";
|
||||
|
||||
export default {
|
||||
name: "bottomBox",
|
||||
@@ -56,7 +56,7 @@
|
||||
'endpoint-tab': endpointTab,
|
||||
'panel-tab': panelTab,
|
||||
terminalLogRecordTab,
|
||||
terminalLogReplayTab
|
||||
'terminal-log-cmd-tab': terminalLogCMDTab
|
||||
},
|
||||
props: {
|
||||
isFullScreen: false, //是否全屏
|
||||
@@ -95,6 +95,10 @@
|
||||
afterResize() {
|
||||
if (this.from == this.$CONSTANTS.fromRoute.endpoint && this.targetTab == 'endpointQuery') {
|
||||
this.$refs.endpointQuery.tableReload();
|
||||
} else if (this.from == this.$CONSTANTS.fromRoute.terminalLog && this.targetTab == 'record') {
|
||||
setTimeout(() => {
|
||||
this.$refs.reminalLogRecordTab.consoleResize();
|
||||
}, 600);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,250 @@
|
||||
<template>
|
||||
<div style="height: 100%;">
|
||||
<div class="sub-top-tools">
|
||||
<div class="sub-list-tabs">
|
||||
<div class="sub-list-tab-title">ID:{{obj.id}}</div><div
|
||||
@click="changeTab('record')" class="sub-list-tab">{{$t("config.terminallog.record.record")}}</div><div
|
||||
class="sub-list-tab sub-list-tab-active">{{$t("config.terminallog.cmd.cmd")}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-container">
|
||||
<div class="record-container--record-tip">
|
||||
<span class="record--title">{{$t('config.terminallog.cmd.legendTip')}}:</span>
|
||||
<span class="detail--cmd"><span class="detail--cmd__red"><i class="nz-icon nz-icon-jinggao" style="color: #f35844; margin-right: 8px"></i>{{$t("config.terminallog.cmd.dangerTip")}}</span></span>
|
||||
</div>
|
||||
<div class="record-container--record">
|
||||
<div class="record--title">{{$t('config.terminallog.cmd.history')}}</div>
|
||||
<div class="record--list">
|
||||
<template v-for="(record, index) in records">
|
||||
<template v-for="item in record.list">
|
||||
<div class="detail--time"><span>{{calcTime(item.time)}}</span></div>
|
||||
<div class="detail--cmd"><span :class="matchBgColor(item.cmd)">{{item.cmd}}</span></div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
<div :style="{visibility: hasNext ? 'visible' : 'hidden'}" class="record--more">
|
||||
<span @click="loadMore" class="more-btn"><i class="nz-icon nz-icon-drop-down"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "terminalLogRecordTab",
|
||||
components: {
|
||||
},
|
||||
props: {
|
||||
obj: Object, //关联的实体对象
|
||||
},
|
||||
computed: {
|
||||
calcTime() {
|
||||
return function(time) {
|
||||
if (this.obj.startTime) {
|
||||
let startTime = new Date(this.obj.startTime).getTime();
|
||||
if (startTime) {
|
||||
let thisTime = startTime+time;
|
||||
return this.dateFormat(thisTime);
|
||||
}
|
||||
}
|
||||
return "-";
|
||||
}
|
||||
},
|
||||
matchBgColor() {
|
||||
return function(cmd) {
|
||||
let className = "";
|
||||
let dangerCmd = this.$CONSTANTS.terminalLog.dangerCmd;
|
||||
let infoCmd = this.$CONSTANTS.terminalLog.infoCmd;
|
||||
let cmdSplit = cmd.split(" ");
|
||||
if (this.intersection(infoCmd, cmdSplit).length > 0) {
|
||||
className = "detail--cmd__green";
|
||||
}
|
||||
if (this.intersection(dangerCmd, cmdSplit).length > 0) {
|
||||
className = "detail--cmd__red";
|
||||
}
|
||||
return className;
|
||||
}
|
||||
},
|
||||
hasNext() {
|
||||
if (this.records.length > 0) {
|
||||
return this.records[this.records.length-1].hasNext;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filter: {
|
||||
uuid: "",
|
||||
cmd: "",
|
||||
time: "",
|
||||
size: 200
|
||||
},
|
||||
records: [ // 加载更多时有多个record,否则只有一个
|
||||
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initData(filter) {
|
||||
this.$get("/terminal/cmd", filter).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.records.push(res.data);
|
||||
} else {
|
||||
this.$message.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
loadMore() {
|
||||
let filter = Object.assign({}, this.filter);
|
||||
filter.time = this.records[this.records.length-1].time;
|
||||
this.initData(filter);
|
||||
},
|
||||
// 切换tab
|
||||
changeTab(tab) {
|
||||
this.$emit('changeTab', tab);
|
||||
},
|
||||
intersection(a, b) {
|
||||
let s = new Set(b);
|
||||
return a.filter(x => s.has(x));
|
||||
},
|
||||
dateFormat(time) {
|
||||
if (!time) {
|
||||
return '-';
|
||||
}
|
||||
let date = new Date(time);
|
||||
let year = date.getFullYear();
|
||||
let month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
|
||||
let day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
|
||||
let hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
|
||||
let minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
|
||||
let seconds = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
|
||||
|
||||
return year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds;
|
||||
},
|
||||
formatUpdateTime(date) {
|
||||
let time=new Date(date);
|
||||
let hours=time.getHours()>9?time.getHours():'0'+time.getHours();
|
||||
let minutes=time.getMinutes()>9?time.getMinutes():'0'+time.getMinutes();
|
||||
|
||||
return hours+':'+minutes;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
obj: {
|
||||
immediate: true,
|
||||
deep: true,
|
||||
handler(n) {
|
||||
this.records = [];
|
||||
this.filter.uuid = n.uuid;
|
||||
this.initData(this.filter);
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.record-container {
|
||||
height: calc(100% - 50px);
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
}
|
||||
.record-container--record {
|
||||
background-color: white;
|
||||
width: calc(100% - 6px);
|
||||
padding: 16px 15px 6px 15px;
|
||||
border: 1px solid #d8dce1;
|
||||
box-sizing: border-box;
|
||||
min-height: 100px;
|
||||
|
||||
.record--title {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.record--list {
|
||||
display: grid;
|
||||
gap: 6px 12px;
|
||||
grid-template-columns: 150px auto;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
|
||||
.detail--time {
|
||||
line-height: 22px;
|
||||
grid-column: 1/span 1;
|
||||
display: flex;
|
||||
font-size: 12px;
|
||||
align-items: flex-start;
|
||||
|
||||
span {
|
||||
background-color: #ECECEC;
|
||||
padding: 2px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail--cmd {
|
||||
line-height: 22px;
|
||||
grid-column: 2/span 1;
|
||||
display: flex;
|
||||
|
||||
span {
|
||||
padding: 2px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail--cmd__green {
|
||||
background-color: #B4FDB1;
|
||||
}
|
||||
.detail--cmd__red {
|
||||
background-color: #FFD2C2;
|
||||
}
|
||||
}
|
||||
|
||||
.record--more {
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
|
||||
.more-btn {
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
|
||||
.nz-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.record-container--record-tip {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 17px;
|
||||
|
||||
.record--title {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.detail--cmd {
|
||||
line-height: 22px;
|
||||
font-size: 14px;
|
||||
padding-left: 20px;
|
||||
|
||||
span {
|
||||
padding: 3px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail--cmd__green {
|
||||
background-color: #A7F29E;
|
||||
}
|
||||
.detail--cmd__red {
|
||||
background-color: #FBe2DE;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,154 +1,295 @@
|
||||
<template>
|
||||
<div style="height: 100%;">
|
||||
<div class="replay-tab" ref="replayTab">
|
||||
<div class="sub-top-tools">
|
||||
<div class="sub-list-tabs">
|
||||
<div class="sub-list-tab-title">ID:{{obj.id}}</div><div
|
||||
@click="changeTab('replay')" class="sub-list-tab">{{$t("config.terminallog.replay")}}</div><div
|
||||
class="sub-list-tab sub-list-tab-active">{{$t("config.terminallog.record.record")}}</div>
|
||||
class="sub-list-tab sub-list-tab-active">{{$t("config.terminallog.record.record")}}</div><div
|
||||
@click="changeTab('cmd')" class="sub-list-tab">{{$t("config.terminallog.cmd.cmd")}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-container">
|
||||
<div class="record-container--record">
|
||||
<div class="record--title">{{$t('config.terminallog.record.history')}}</div>
|
||||
<div class="record--list">
|
||||
<template v-for="(record, index) in records">
|
||||
<template v-for="item in record.list">
|
||||
<div class="detail--time"><span>{{calcTime(item.time)}}</span></div>
|
||||
<div class="detail--cmd"><span :class="matchBgColor(item.cmd)">{{item.cmd}}</span></div>
|
||||
</template>
|
||||
</template>
|
||||
<div class="replay-container">
|
||||
<div class="replay-operate">
|
||||
<div>
|
||||
<button :title="$t('config.terminallog.record.pause')" @click="pause" class="nz-btn nz-btn-style-light nz-btn-size-large" id="terminal-replay-pause" v-show="isPlaying"><i class="nz-icon nz-icon-suspend"></i></button>
|
||||
<button :title="$t('config.terminallog.record.play')" @click="play" class="nz-btn nz-btn-style-light nz-btn-size-large" id="terminal-replay-play" v-show="isFinish || !isPlaying"><i class="nz-icon nz-icon-play"></i></button>
|
||||
<button :title="$t('config.terminallog.record.replay')" @click="restart" class="nz-btn nz-btn-style-light nz-btn-size-large" id="terminal-replay-restart"><i class="nz-icon nz-icon-replay"></i></button>
|
||||
<button @click="speedChange" class="nz-btn nz-btn-style-light nz-btn-size-large" id="terminal-replay-speed-change"><i class="nz-icon nz-icon-fast-forward"></i> {{speedTable[speedOffset].name}}</button>
|
||||
<el-checkbox class="operate-skip" id="terminal-replay-skip" v-model="needSkip">{{$t("config.terminallog.record.skipTip")}}</el-checkbox>
|
||||
<el-tag class="time-box" color="#23bf9a" effect="dark" size="medium">{{parseCurrentTime}} s</el-tag>
|
||||
</div>
|
||||
<div class="record--more" v-if="hasNext">
|
||||
<span @click="loadMore" class="nz-btn nz-btn-size-small nz-btn-style-light"><i class="nz-icon nz-icon-arrow-down"></i></span>
|
||||
<div @click="jumpProgress" class="terminal-replay-progress">
|
||||
<el-progress :percentage="progress" :show-text="false" class="terminal-replay-progress-bar" ref="terminalProgress"></el-progress>
|
||||
<div @mousedown="startDragging" class="progress-controller" id="progressController" ref="progressController"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="record-container--record record-container--record__tip">
|
||||
<div class="record--title">{{$t('config.terminallog.record.legendTip')}}</div>
|
||||
<div class="record--list">
|
||||
<div class="detail--time"><span>yyyy-MM-dd HH:mm:ss</span></div>
|
||||
<div class="detail--cmd"><span class="detail--cmd__red">{{$t("config.terminallog.record.dangerTip")}}</span></div>
|
||||
</div>
|
||||
<div class="record-console" ref="recordConsole">
|
||||
<div :id="obj.uuid" class="record-terminal"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Terminal from '../../js/Xterm';
|
||||
import bus from "../../../../libs/bus";
|
||||
|
||||
export default {
|
||||
name: "terminalLogRecordTab",
|
||||
name: "terminalLogReplayTab",
|
||||
components: {
|
||||
Terminal
|
||||
},
|
||||
props: {
|
||||
obj: Object, //关联的实体对象
|
||||
},
|
||||
computed: {
|
||||
calcTime() {
|
||||
return function(time) {
|
||||
if (this.obj.startTime) {
|
||||
let startTime = new Date(this.obj.startTime).getTime();
|
||||
if (startTime) {
|
||||
let thisTime = startTime+time;
|
||||
return this.dateFormat(thisTime);
|
||||
}
|
||||
}
|
||||
return "-";
|
||||
}
|
||||
},
|
||||
matchBgColor() {
|
||||
return function(cmd) {
|
||||
let className = "";
|
||||
let dangerCmd = this.$CONSTANTS.terminalLog.dangerCmd;
|
||||
let infoCmd = this.$CONSTANTS.terminalLog.infoCmd;
|
||||
let cmdSplit = cmd.split(" ");
|
||||
if (this.intersection(infoCmd, cmdSplit).length > 0) {
|
||||
className = "detail--cmd__green";
|
||||
}
|
||||
if (this.intersection(dangerCmd, cmdSplit).length > 0) {
|
||||
className = "detail--cmd__red";
|
||||
}
|
||||
return className;
|
||||
}
|
||||
},
|
||||
hasNext() {
|
||||
if (this.records.length > 0) {
|
||||
return this.records[this.records.length-1].hasNext;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filter: {
|
||||
uuid: this.obj.uuid,
|
||||
cmd: "",
|
||||
time: "",
|
||||
size: 200
|
||||
size: 1,
|
||||
uuid: ""
|
||||
},
|
||||
records: [ // 加载更多时有多个record,否则只有一个
|
||||
terminal: null,
|
||||
|
||||
recordData: [],
|
||||
isNeedStop: false, // 是否需要停止
|
||||
playedCount: 0, // 当前已经播放完的数量
|
||||
isPlaying: true, // 是否正在播放
|
||||
isFinish: false, //是否已结束
|
||||
isDragging: false, //是否正在拖动进度条
|
||||
draggingOriginalX: 0, //开始拖拽时鼠标的x
|
||||
draggingOriginalProgress: 0, //开始拖拽时的进度
|
||||
recordTick: 50, // 输出间隔时间ms,默认50
|
||||
playerTimer: null, // 定时器
|
||||
playerCurrentTime: 0, // 当前时间进度
|
||||
speedTable: [ // 快进倍速选项
|
||||
{speed: 1, name: '×1'},
|
||||
{speed: 2, name: '×2'},
|
||||
{speed: 4, name: '×4'},
|
||||
{speed: 8, name: '×8'},
|
||||
{speed: 16, name: '×16'}
|
||||
],
|
||||
/*record: { // cmd记录,含hasNext、time(最后一条时间)、total和list
|
||||
total: 4,
|
||||
hasNext: true,
|
||||
time: 9889,
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
uuid: 1,
|
||||
time: 1024,
|
||||
cmd: "ls -ef|grep java"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
uuid: 2,
|
||||
time: 3824,
|
||||
cmd: "su root ls -ef|grep java|afaewrafaser aolewr | awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|ls -ef|grep java|afaewrafaser aolewr | awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|ls -ef|grep java|afaewrafaser aolewr | awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|ls -ef|grep java|afaewrafaser aolewr | awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|ls -ef|grep java|afaewrafaser aolewr | awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|ls -ef|grep java|afaewrafaser aolewr | awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|ls -ef|grep java|afaewrafaser aolewr | awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|awk fajpoerja;welkrjfa;wle|"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
uuid: 3,
|
||||
time: 7740,
|
||||
cmd: "rm -rf /"
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
uuid: 4,
|
||||
time: 9889,
|
||||
cmd: "exit"
|
||||
},
|
||||
]
|
||||
}*/
|
||||
speedOffset: 0, // 快进倍数index
|
||||
progress: 0, // 进度条进度
|
||||
needSkip: true, // 是否跳过无操作时间,为true时表示需要,即不跳过无操作时间
|
||||
timeUsed: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initData(filter) {
|
||||
this.$get("/terminal/cmd", filter).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.records.push(res.data);
|
||||
} else {
|
||||
this.$message.error(res.msg);
|
||||
}
|
||||
});
|
||||
},
|
||||
loadMore() {
|
||||
let filter = Object.assign({}, this.filter);
|
||||
filter.time = this.records[this.records.length-1].time;
|
||||
this.initData(filter);
|
||||
},
|
||||
// 切换tab
|
||||
changeTab(tab) {
|
||||
this.$emit('changeTab', tab);
|
||||
},
|
||||
intersection(a, b) {
|
||||
let s = new Set(b);
|
||||
return a.filter(x => s.has(x));
|
||||
|
||||
getRecordData() {
|
||||
return new Promise(resolve => {
|
||||
this.$get("/terminal/record", this.filter).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.recordData = res.data.list;
|
||||
this.timeUsed = res.data.endTime;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
consoleResize() {
|
||||
this.terminal && this.terminal.resize(parseInt(this.$refs.recordConsole.offsetWidth/11), parseInt(this.$refs.recordConsole.offsetHeight/18));
|
||||
this.$nextTick(() => {
|
||||
this.terminal && this.terminal.fit();
|
||||
});
|
||||
},
|
||||
|
||||
initAndPlay() {
|
||||
this.$nextTick(() => {
|
||||
// terminal初始化
|
||||
if (this.terminal) {
|
||||
this.terminal.reset(parseInt(this.$refs.recordConsole.offsetWidth/11), parseInt(this.$refs.recordConsole.offsetHeight/18));
|
||||
} else {
|
||||
this.terminal = new Terminal({
|
||||
rows: parseInt(this.$refs.recordConsole.offsetHeight/18),
|
||||
cols: parseInt(this.$refs.recordConsole.offsetWidth/11)
|
||||
});
|
||||
this.terminal.open(document.getElementById(this.obj.uuid));
|
||||
}
|
||||
|
||||
if (this.recordData.length > 0) {
|
||||
this.isNeedStop = false;
|
||||
this.isPlaying = true;
|
||||
this.isFinished = false;
|
||||
this.playedCount = 0;
|
||||
this.doPlay();
|
||||
} else {
|
||||
let req = this.getRecordData();
|
||||
req.then(() => {
|
||||
if (this.recordData.length > 0) {
|
||||
// 请求得到数据后,开始播放
|
||||
this.isNeedStop = false;
|
||||
this.isPlaying = true;
|
||||
this.isFinished = false;
|
||||
this.playedCount = 0;
|
||||
this.doPlay();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/*原理:利用setTimeout和数据的时间偏移量来模拟实现视频播放效果*/
|
||||
doPlay() {
|
||||
if (this.isNeedStop) {
|
||||
this.isPlaying = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.recordData.length <= this.playedCount) {
|
||||
this.playerTimer = setTimeout(this.doPlay, this.recordTick);
|
||||
return;
|
||||
}
|
||||
|
||||
this.playerCurrentTime += this.recordTick * this.speedTable[this.speedOffset].speed;
|
||||
|
||||
let recordTick = this.recordTick;
|
||||
|
||||
let playData;
|
||||
for (let i = this.playedCount; i < this.recordData.length; i++) {
|
||||
if (this.isNeedStop) {
|
||||
break;
|
||||
}
|
||||
playData = this.recordData[i];
|
||||
if (playData.t < this.playerCurrentTime) {
|
||||
this.terminal.write(playData.c);
|
||||
|
||||
if ((this.playedCount + 1) === this.recordData.length) {
|
||||
//播放完成
|
||||
this.progress = 100;
|
||||
this.isFinished = true;
|
||||
this.isPlaying = false;
|
||||
return;
|
||||
} else {
|
||||
this.playedCount++;
|
||||
}
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.isNeedStop) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.needSkip) {
|
||||
if (playData.t - this.playerCurrentTime > 800) {
|
||||
this.playerCurrentTime = playData.t; // - this.record_tick * this.speed_table[this.speed_offset].speed;
|
||||
recordTick = 800;
|
||||
}
|
||||
}
|
||||
// 同步进度条
|
||||
this.progress = parseInt(this.playerCurrentTime * 100 / this.timeUsed);
|
||||
|
||||
if (this.playedCount >= this.recordData.length) {
|
||||
this.progress = 100;
|
||||
//播放完成
|
||||
this.isFinished = true;
|
||||
this.isPlaying = false;
|
||||
} else {
|
||||
if (!this.isNeedStop)
|
||||
this.playerTimer = setTimeout(this.doPlay, recordTick);
|
||||
}
|
||||
|
||||
},
|
||||
play() {
|
||||
if (this.isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isFinished) {
|
||||
this.restart();
|
||||
return;
|
||||
}
|
||||
|
||||
this.isNeedStop = false;
|
||||
this.isPlaying = true;
|
||||
this.playerTimer = setTimeout(this.doPlay, this.recordTick);
|
||||
},
|
||||
|
||||
speedChange() {
|
||||
let length = this.speedTable.length;
|
||||
this.speedOffset += 1;
|
||||
if (this.speedOffset === length) {
|
||||
this.speedOffset = 0;
|
||||
}
|
||||
},
|
||||
|
||||
pause() {
|
||||
if (this.playerTimer) {
|
||||
clearTimeout(this.playerTimer);
|
||||
}
|
||||
this.isNeedStop = true;
|
||||
this.isPlaying = false;
|
||||
},
|
||||
|
||||
restart() {
|
||||
if (this.playerTimer) {
|
||||
clearTimeout(this.playerTimer);
|
||||
}
|
||||
this.playerCurrentTime = 0;
|
||||
this.initAndPlay();
|
||||
},
|
||||
jumpProgress(e) {
|
||||
e.preventDefault();
|
||||
if (this.playerTimer) {
|
||||
clearTimeout(this.playerTimer);
|
||||
}
|
||||
this.progress = parseInt(e.offsetX*100/500);
|
||||
this.playerCurrentTime = parseInt(this.timeUsed * this.progress / 100);
|
||||
this.initAndPlay();
|
||||
},
|
||||
startDragging(e) {
|
||||
e.preventDefault();
|
||||
if (this.playerTimer) {
|
||||
clearTimeout(this.playerTimer);
|
||||
}
|
||||
let vm = this;
|
||||
|
||||
this.pause();
|
||||
this.draggingOriginalX = e.clientX;
|
||||
this.draggingOriginalProgress = this.progress;
|
||||
this.isDragging = true;
|
||||
document.addEventListener("mousemove", dragging);
|
||||
document.addEventListener("mouseup", endDragging);
|
||||
|
||||
function endDragging(e) {
|
||||
e.preventDefault();
|
||||
|
||||
vm.isDragging = false;
|
||||
document.removeEventListener("mousemove", dragging);
|
||||
document.removeEventListener("mouseup", endDragging);
|
||||
vm.initAndPlay();
|
||||
}
|
||||
function dragging(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (vm.isDragging) {
|
||||
let nowX = e.clientX;
|
||||
let diff = nowX - vm.draggingOriginalX; // x变化量
|
||||
|
||||
let diffProgress = parseInt(diff*100/500);
|
||||
if ((diffProgress + vm.draggingOriginalProgress) > 100) {
|
||||
vm.progress = 100;
|
||||
} else if ((diffProgress + vm.draggingOriginalProgress) < 0) {
|
||||
vm.progress = 0;
|
||||
} else {
|
||||
vm.progress = diffProgress + vm.draggingOriginalProgress;
|
||||
}
|
||||
vm.playerCurrentTime = parseInt(vm.timeUsed * vm.progress / 100);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
dateFormat(time) {
|
||||
if (!time) {
|
||||
return '-';
|
||||
}
|
||||
let date = new Date(time);
|
||||
let date = new Date(time * 1000);
|
||||
let year = date.getFullYear();
|
||||
let month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
|
||||
let day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
|
||||
@@ -167,86 +308,99 @@
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
// 入口,监听terminal session的变化,开始功能
|
||||
obj: {
|
||||
immediate: true,
|
||||
deep: true,
|
||||
handler(n) {
|
||||
if (n.uuid) {
|
||||
this.recordData = [];
|
||||
this.filter.uuid = n.uuid;
|
||||
this.playerCurrentTime = 0;
|
||||
if (this.playerTimer) {
|
||||
clearTimeout(this.playerTimer);
|
||||
}
|
||||
setTimeout(() => {this.initAndPlay();}, 200);
|
||||
}
|
||||
}
|
||||
},
|
||||
progress(n) {
|
||||
let progressController = document.getElementById("progressController");
|
||||
progressController.style.left = `${n}%`;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initData(this.filter);
|
||||
computed: {
|
||||
parseCurrentTime() {
|
||||
let currentTime = parseInt(this.playerCurrentTime/1000);
|
||||
let totalTime = parseInt(this.timeUsed/1000);
|
||||
if (currentTime > totalTime) {
|
||||
currentTime = totalTime;
|
||||
}
|
||||
return `${currentTime} / ${totalTime}`;
|
||||
}
|
||||
},
|
||||
created() {
|
||||
window.addEventListener('resize', bus.debounce(this.consoleResize, 1000));
|
||||
},
|
||||
beforeDestroy() {
|
||||
window.removeEventListener('resize', bus.debounce);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.record-container {
|
||||
height: calc(100% - 50px);
|
||||
overflow: auto;
|
||||
.replay-tab {
|
||||
height: 100%;
|
||||
}
|
||||
.record-container--record {
|
||||
background-color: white;
|
||||
width: calc(50% - 14px);
|
||||
padding: 16px 15px 14px 15px;
|
||||
border: 1px solid #d8dce1;
|
||||
box-sizing: border-box;
|
||||
min-height: 100px;
|
||||
|
||||
.record--title {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.record--list {
|
||||
display: grid;
|
||||
gap: 6px 12px;
|
||||
grid-template-columns: 150px auto;
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
padding-left: 16px;
|
||||
|
||||
.detail--time {
|
||||
line-height: 18px;
|
||||
grid-column: 1/span 1;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
span {
|
||||
background-color: #ECECEC;
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail--cmd {
|
||||
line-height: 18px;
|
||||
grid-column: 2/span 1;
|
||||
display: flex;
|
||||
|
||||
span {
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail--cmd__green {
|
||||
background-color: #B4FDB1;
|
||||
}
|
||||
.detail--cmd__red {
|
||||
background-color: #FFD2C2;
|
||||
}
|
||||
}
|
||||
|
||||
.record--more {
|
||||
text-align: center;
|
||||
.replay-container {
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
.record-console {
|
||||
padding: 10px 4px 10px 10px;
|
||||
background-color: black;
|
||||
height: calc(100% - 80px);
|
||||
}
|
||||
.terminal-replay-progress {
|
||||
height: 20px;
|
||||
padding: 3px 0;
|
||||
position: relative;
|
||||
width: 500px;
|
||||
}
|
||||
.terminal-replay-progress-bar {
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
|
||||
.el-progress-bar__inner {
|
||||
transition: unset;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
.record-container--record.record-container--record__tip {
|
||||
margin-top: 10px;
|
||||
min-height: unset;
|
||||
.replay-operate {
|
||||
.nz-btn {
|
||||
margin-right: 8px;
|
||||
|
||||
.nz-icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.operate-skip {
|
||||
margin: 0 12px !important;
|
||||
}
|
||||
.time-box {
|
||||
border: none;
|
||||
border-radius: 16px;
|
||||
}
|
||||
.progress-controller {
|
||||
position: absolute;
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
border-radius: 50%;
|
||||
background-color: #409eef;
|
||||
top: 50%;
|
||||
transform: translate(-7px, -50%);
|
||||
}
|
||||
.progress-controller:hover {
|
||||
background-color: #207ecf;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,268 +0,0 @@
|
||||
<template>
|
||||
<div style="height: 100%;">
|
||||
<div class="sub-top-tools">
|
||||
<div class="sub-list-tabs">
|
||||
<div class="sub-list-tab-title">ID:{{obj.id}}</div><div
|
||||
class="sub-list-tab sub-list-tab-active">{{$t("config.terminallog.replay")}}</div><div
|
||||
@click="changeTab('record')" class="sub-list-tab">{{$t("config.terminallog.record.record")}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="replay-container">
|
||||
<div class="replay-operate">
|
||||
<button @click="pause" class="nz-btn nz-btn-style-light nz-btn-size-large">暂停</button>
|
||||
<button @click="play" class="nz-btn nz-btn-style-light nz-btn-size-large">播放</button>
|
||||
<button @click="restart" class="nz-btn nz-btn-style-light nz-btn-size-large">重新播放</button>
|
||||
<el-tag>{{progress}}</el-tag>
|
||||
</div>
|
||||
<div class="replay-console">
|
||||
<div :id="obj.uuid" class="replay-terminal"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Terminal from '../../js/Xterm';
|
||||
|
||||
export default {
|
||||
name: "terminalLogReplayTab",
|
||||
components: {
|
||||
Terminal
|
||||
},
|
||||
props: {
|
||||
obj: Object, //关联的实体对象
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filter: {
|
||||
size: 1,
|
||||
uuid: ""
|
||||
},
|
||||
operate: {
|
||||
pause: false, // 是否暂停
|
||||
|
||||
},
|
||||
terminal: null,
|
||||
|
||||
recordData: [],
|
||||
isNeedStop: false, // 是否需要停止
|
||||
playedCount: 0, // 当前已经播放完的数量
|
||||
isPlaying: true, // 是否正在播放
|
||||
isFinish: false, //是否已结束
|
||||
recordTick: 50, // 输出间隔时间ms,默认50
|
||||
playerTimer: null, // 定时器
|
||||
playerCurrentTime: 0, // 当前时间进度
|
||||
speedTable: [ // 快进倍速选项
|
||||
{speed: 1, name: 'Normal'},
|
||||
{speed: 2, name: 'x2'},
|
||||
{speed: 4, name: 'x4'},
|
||||
{speed: 8, name: 'x8'},
|
||||
{speed: 16, name: 'x16'}
|
||||
],
|
||||
speedOffset: 0, // 快进倍数index
|
||||
progress: 0, // 进度条进度
|
||||
needSkip: false, // 需要时间刻度,即是否跳过无操作时间,为true时表示需要,即不跳过无操作时间
|
||||
timeUsed: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 切换tab
|
||||
changeTab(tab) {
|
||||
this.$emit('changeTab', tab);
|
||||
},
|
||||
|
||||
getReplayData() {
|
||||
return new Promise(resolve => {
|
||||
this.$get("/terminal/record", this.filter).then(res => {
|
||||
if (res.code === 200) {
|
||||
this.recordData = res.data.list;
|
||||
this.timeUsed = res.data.endTime;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
initAndPlay() {
|
||||
// terminal初始化
|
||||
if (!this.terminal) {
|
||||
this.terminal = new Terminal(
|
||||
{
|
||||
cols: 70,
|
||||
rows: 28
|
||||
}
|
||||
);
|
||||
} else {
|
||||
this.terminal.destroy();
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.terminal.open(document.getElementById(this.obj.uuid));
|
||||
this.terminal.resize(70, 28);
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (this.recordData.length > 0) {
|
||||
this.isNeedStop = false;
|
||||
this.isPlaying = true;
|
||||
this.isFinished = false;
|
||||
this.playedCount = 0;
|
||||
this.doPlay();
|
||||
} else {
|
||||
let req = this.getReplayData();
|
||||
req.then(() => {
|
||||
if (this.recordData.length > 0) {
|
||||
// 请求得到数据后,开始播放
|
||||
this.isNeedStop = false;
|
||||
this.isPlaying = true;
|
||||
this.isFinished = false;
|
||||
this.playedCount = 0;
|
||||
this.doPlay();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 800);
|
||||
},
|
||||
|
||||
/*原理:利用setTimeout和数据的时间偏移量来模拟实现视频播放效果*/
|
||||
doPlay() {
|
||||
if (this.isNeedStop) {
|
||||
this.isPlaying = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.recordData.length <= this.playedCount) {
|
||||
this.playerTimer = setTimeout(this.doPlay, this.recordTick);
|
||||
return;
|
||||
}
|
||||
this.playerCurrentTime += this.recordTick * this.speedTable[this.speedOffset].speed;
|
||||
|
||||
let recordTick = this.recordTick;
|
||||
|
||||
let playData;
|
||||
for (let i = this.playedCount; i < this.recordData.length; i++) {
|
||||
if (this.isNeedStop) {
|
||||
break;
|
||||
}
|
||||
playData = this.recordData[i];
|
||||
if (playData.t < this.playerCurrentTime) {
|
||||
this.terminal.write(playData.c);
|
||||
|
||||
if ((this.playedCount + 1) === this.recordData.length) {
|
||||
//播放完成
|
||||
this.progress = 100;
|
||||
this.isFinished = true;
|
||||
this.isPlaying = false;
|
||||
return;
|
||||
} else {
|
||||
this.playedCount++;
|
||||
}
|
||||
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this.isNeedStop) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.needSkip) {
|
||||
if (playData.t - this.playerCurrentTime > 800) {
|
||||
this.playerCurrentTime = playData.t; // - this.record_tick * this.speed_table[this.speed_offset].speed;
|
||||
recordTick = 800;
|
||||
}
|
||||
}
|
||||
// 同步进度条
|
||||
this.progress = parseInt(this.playerCurrentTime * 100 / this.timeUsed);
|
||||
|
||||
if (this.playedCount >= this.recordData.length) {
|
||||
this.progress = 100;
|
||||
//播放完成
|
||||
this.isFinished = true;
|
||||
this.isPlaying = false;
|
||||
} else {
|
||||
if (!this.isNeedStop)
|
||||
this.playerTimer = setTimeout(this.doPlay, recordTick);
|
||||
}
|
||||
|
||||
},
|
||||
play() {
|
||||
if (this.isPlaying) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isFinished) {
|
||||
this.restart();
|
||||
return;
|
||||
}
|
||||
|
||||
this.isNeedStop = false;
|
||||
this.isPlaying = true;
|
||||
this.playerTimer = setTimeout(this.doPlay, this.recordTick);
|
||||
},
|
||||
|
||||
pause() {
|
||||
if (this.playerTimer) {
|
||||
clearTimeout(this.playerTimer);
|
||||
}
|
||||
this.isNeedStop = true;
|
||||
this.isPlaying = false;
|
||||
},
|
||||
|
||||
restart() {
|
||||
if (this.playerTimer) {
|
||||
clearTimeout(this.playerTimer);
|
||||
}
|
||||
this.playerCurrentTime = 0;
|
||||
this.initAndPlay();
|
||||
},
|
||||
|
||||
dateFormat(time) {
|
||||
if (!time) {
|
||||
return '-';
|
||||
}
|
||||
let date = new Date(time * 1000);
|
||||
let year = date.getFullYear();
|
||||
let month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
|
||||
let day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
|
||||
let hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
|
||||
let minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
|
||||
let seconds = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
|
||||
|
||||
return year + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds;
|
||||
},
|
||||
formatUpdateTime(date) {
|
||||
let time=new Date(date);
|
||||
let hours=time.getHours()>9?time.getHours():'0'+time.getHours();
|
||||
let minutes=time.getMinutes()>9?time.getMinutes():'0'+time.getMinutes();
|
||||
|
||||
return hours+':'+minutes;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
// 入口,监听terminal session的变化,开始功能
|
||||
obj: {
|
||||
immediate: true,
|
||||
deep: true,
|
||||
handler(n) {
|
||||
if (n.uuid) {
|
||||
this.filter.uuid = n.uuid;
|
||||
this.initAndPlay();
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.replay-console {
|
||||
width: 660px;
|
||||
height: 480px;
|
||||
padding: 10px 4px 10px 10px;
|
||||
background-color: black;
|
||||
}
|
||||
</style>
|
||||
@@ -383,7 +383,6 @@ export const chartResizeTool = {
|
||||
//将resize-box的宽高设为resize-shadow的宽高
|
||||
box.style.width = `${shadow.offsetWidth}px`;
|
||||
box.style.height = `${Math.round((shadow.offsetHeight )/chartPaddingTop)*chartPaddingTop}px`;
|
||||
console.log('box height:',box.style.height)
|
||||
data.height = Math.round((box.offsetHeight+chartPaddingTop)/stepHeight)*stepHeight;
|
||||
data.span = Math.round((box.offsetWidth+chartBlankWidth)/stepWidth);
|
||||
//请求后台,保存变更
|
||||
|
||||
@@ -641,7 +641,6 @@ const cn = {
|
||||
},
|
||||
option: "操作",
|
||||
host: "主机",
|
||||
cmd: "命令",
|
||||
port: "端口",
|
||||
userId: "用户ID",
|
||||
protocol: "协议",
|
||||
@@ -668,12 +667,20 @@ const cn = {
|
||||
duration: "持续",
|
||||
remote: "远程连接",
|
||||
replay: "回放",
|
||||
source: "源IP",
|
||||
log: "日志",
|
||||
cmd: {
|
||||
cmd: "命令",
|
||||
history: "历史命令",
|
||||
dangerTip: "可能是危险命令",
|
||||
legendTip: "图例说明"
|
||||
},
|
||||
record: {
|
||||
record: "记录",
|
||||
history: "历史记录",
|
||||
dangerTip: "这条命令可能是危险的",
|
||||
legendTip: "图例说明",
|
||||
record: "回放",
|
||||
pause: "暂停",
|
||||
play: "播放",
|
||||
replay: "重播",
|
||||
skipTip: "跳过无操作时间"
|
||||
}
|
||||
},
|
||||
dc: {
|
||||
|
||||
@@ -679,7 +679,6 @@ const en = {
|
||||
},
|
||||
option: 'Operation',//"操作",
|
||||
host: 'Host',
|
||||
cmd: 'CMD',
|
||||
port: 'Port',
|
||||
userId: 'UserID',
|
||||
protocol: 'Protocol',
|
||||
@@ -705,13 +704,20 @@ const en = {
|
||||
startTime: "Start time",
|
||||
duration: "Duration",
|
||||
remote: "Remote",
|
||||
replay: "Replay",
|
||||
log: "Log",
|
||||
source: "Source IP",
|
||||
cmd: {
|
||||
cmd: "Command",
|
||||
history: "History command",
|
||||
dangerTip: "This command may be dangerous",
|
||||
legendTip: "Legend description",
|
||||
},
|
||||
record: {
|
||||
record: "Record",
|
||||
history: "History record",
|
||||
dangerTip: "This CMD may be dangerous",
|
||||
legendTip: "Legend description",
|
||||
pause: "Pause",
|
||||
play: "Play",
|
||||
replay: "Replay",
|
||||
skipTip: "Skip no operation time"
|
||||
}
|
||||
},
|
||||
operationlog: {
|
||||
|
||||
@@ -58,9 +58,9 @@
|
||||
<span>{{getDuration(scope.row)}}</span>
|
||||
</template>
|
||||
<template v-else-if="item.prop == 'option'">
|
||||
<span :id="'terminalLog-replay-'+scope.row.id" :title="$t('config.terminallog.replay')" @click="showReplay(scope.row)" class="content-right-option"><i class="el-icon-video-play"></i></span>
|
||||
<span :id="'terminalLog-replay-'+scope.row.id" :title="$t('config.terminallog.record.record')" @click="showRecord(scope.row)" class="content-right-option"><i class="nz-icon nz-icon-replay2"></i></span>
|
||||
|
||||
<span :id="'terminalLog-log-'+scope.row.id" :title="$t('config.terminallog.log')" @click="showRecord(scope.row)" class="content-right-option"><i class="el-icon-tickets"></i></span>
|
||||
<span :id="'terminalLog-log-'+scope.row.id" :title="$t('config.terminallog.log')" @click="showHistoryCMD(scope.row)" class="content-right-option"><i class="nz-icon nz-icon-terminal-log"></i></span>
|
||||
|
||||
</template>
|
||||
<span v-else>{{scope.row[item.prop]}}</span>
|
||||
@@ -159,6 +159,11 @@
|
||||
prop: 'username',
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('config.terminallog.source'),
|
||||
prop: 'remoteAddr',
|
||||
show: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('config.terminallog.remote'),
|
||||
prop: 'remote',
|
||||
@@ -233,43 +238,6 @@
|
||||
searchLabel: {}, //搜索参数
|
||||
scrollbarWrap: null,
|
||||
|
||||
testData: {
|
||||
code: 200,
|
||||
data: {
|
||||
pageNo: 1,
|
||||
pageSize: 20,
|
||||
total: 2,
|
||||
pages: 1,
|
||||
list: [
|
||||
{
|
||||
id: 1,
|
||||
uuid: "abcdde",
|
||||
host: "192.168.40.42",
|
||||
port: 22,
|
||||
protocol: "SSH",
|
||||
authType: 1,
|
||||
username: "admin",
|
||||
loginUser: "root",
|
||||
startTime: "2021-02-01 14:20:08",
|
||||
endTime: "2021-02-01 14:30:08",
|
||||
status: 3,
|
||||
killUserName: "leader",
|
||||
}, {
|
||||
id: 2,
|
||||
uuid: "zpppoe",
|
||||
host: "192.168.40.42",
|
||||
port: 22,
|
||||
protocol: "SSH",
|
||||
authType: 1,
|
||||
username: "admin",
|
||||
loginUser: "root",
|
||||
startTime: "2021-02-01 14:41:08",
|
||||
endTime: "2021-02-01 14:51:08",
|
||||
status: 2,
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -292,11 +260,16 @@
|
||||
}
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'bottomBox.showSubList': function (n) {
|
||||
let vm = this;
|
||||
this.$bottomBoxWindow.showSubListWatch(vm, n);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getTableData() {
|
||||
this.$get('terminal/session', this.searchLabel).then(response => {
|
||||
this.tools.loading = false;
|
||||
//response = this.testData;
|
||||
if (response.code === 200) {
|
||||
this.tableData = response.data.list;
|
||||
this.pageObj.total = response.data.total;
|
||||
@@ -310,32 +283,13 @@
|
||||
})
|
||||
},
|
||||
|
||||
/*getTableData: function () {
|
||||
this.$set(this.searchLabel, "pageNo", this.pageObj.pageNo);
|
||||
this.$set(this.searchLabel, "pageSize", this.pageObj.pageSize);
|
||||
this.tools.loading = true;
|
||||
this.$get('terminal/log', this.searchLabel).then(response => {
|
||||
this.tools.loading = false;
|
||||
response = this.testData;
|
||||
if (response.code === 200) {
|
||||
this.tableData = response.data.list;
|
||||
this.pageObj.total = response.data.total;
|
||||
if (!this.scrollbarWrap) {
|
||||
this.$nextTick(() => {
|
||||
this.scrollbarWrap = this.$refs.terminalLogTable.bodyWrapper;
|
||||
this.toTopBtnHandler(this.scrollbarWrap);
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
},*/
|
||||
showReplay(record) {
|
||||
this.bottomBox.targetTab = 'replay';
|
||||
showRecord(record) {
|
||||
this.bottomBox.targetTab = 'record';
|
||||
this.bottomBox.terminalLog = JSON.parse(JSON.stringify(record));
|
||||
this.bottomBox.showSubList = true;
|
||||
},
|
||||
showRecord(record) {
|
||||
this.bottomBox.targetTab = 'record';
|
||||
showHistoryCMD(record) {
|
||||
this.bottomBox.targetTab = 'cmd';
|
||||
this.bottomBox.terminalLog = JSON.parse(JSON.stringify(record));
|
||||
this.bottomBox.showSubList = true;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user