AIQA.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  1. <template>
  2. <div class="ai-content-wrap">
  3. <div class="window-list-wrap">
  4. <div class="window-title">
  5. <div class="title-wrap">
  6. <p class="text-ellipsis" style="color: #333333;font-size: 20px;font-weight: 600;">{{companyName}}</p>
  7. <span style="color: #666666;font-size: 16px;">{{$t('ToolBox.AIQuestion.title')}}</span>
  8. </div>
  9. <div class="icon"><img src="~@/assets/img/icons/ai_company.png"/></div>
  10. </div>
  11. <div class="add-btn" @click="handleAddNewWindow"><i class="el-icon-circle-plus-outline"></i>{{$t('ToolBox.AIQuestion.add_new_window')}}</div>
  12. <div class="list-wrap hidden-scrollbar">
  13. <Window-List-Item
  14. ref="windowListItem"
  15. v-for="item in windowList" :key="item.AiChatTopicId"
  16. :activeWindowId="activeWindowId"
  17. :item="item"
  18. @click.native="changeActiveWindow(item)"
  19. @changeEdit="changeWindowTitle"
  20. @delete="deleteWindowItem"
  21. />
  22. <div class="empty-list" v-if="windowList.length===0">
  23. <img src="~@/assets/img/ai_m/empty_list.png" />
  24. </div>
  25. </div>
  26. </div>
  27. <div class="content-wrap">
  28. <div class="content-header">
  29. <div class="title-wrap">
  30. <p>{{activeWindowId<=0?$t('ToolBox.AIQuestion.new_window'):activeWindow.TopicName||''}}</p>
  31. <span>{{activeWindowId<=0?$t('ToolBox.AIQuestion.AI_use_intro'):`${historyList.length||0} messages`}}</span>
  32. </div>
  33. </div>
  34. <!-- 仅这一部分滚动 -->
  35. <div class="window-content-wrap hidden-scrollbar">
  36. <div class="content-item" v-for="item in historyList" :key="item.AiChatId" >
  37. <!-- user 提问 -->
  38. <Message-Item :messageInfo="formatMsg(item,'user')"
  39. @startTyping="handleStartTyping"
  40. @finishedTyping="handleFinishedTyping"
  41. />
  42. <!-- 模型回答 -->
  43. <Message-Item :messageInfo="formatMsg(item,'model')"
  44. @startTyping="handleStartTyping"
  45. @finishedTyping="handleFinishedTyping"
  46. />
  47. </div>
  48. <New-Window-Hint v-if="activeWindowId===0" />
  49. </div>
  50. <div class="input-box" id="input-box">
  51. <div class="upload-row">
  52. <el-upload
  53. style="display: inline-block; margin-right: 8px"
  54. accept=".pptx,.pdf,.docx"
  55. action=""
  56. :http-request="handleUpload"
  57. :before-upload="handleBeforeUpload"
  58. :show-file-list="false"
  59. :disabled="startUploadAudio">
  60. <img src="~@/assets/img/icons/ai-upload.png" />
  61. </el-upload>
  62. <span>{{ $t('ToolBox.AIQuestion.support_formats') }}:PDF、PPTX、DOCX;{{ $t('ToolBox.AIQuestion.max_file_text') }}</span>
  63. </div>
  64. <textarea rows="6" v-model="inputText" :placeholder="$t('ToolBox.AIQuestion.input_placeholder')" @keydown.enter="handleSendMsg"></textarea>
  65. <div class="send-btn" @click="handleSendMsg"><img src="~@/assets/img/ai_m/send.png" />{{$t('ToolBox.AIQuestion.send_btn')}}</div>
  66. </div>
  67. </div>
  68. </div>
  69. </template>
  70. <script>
  71. /* components */
  72. import MessageItem from './components/messageItem.vue';
  73. import NewWindowHint from './components/newWindowHint.vue';
  74. import WindowListItem from './components/windowListItem';
  75. /* api */
  76. import {aiQAInterence} from '@/api/modules/aiApi.js';
  77. import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
  78. export default {
  79. components: { WindowListItem,NewWindowHint, MessageItem },
  80. data() {
  81. return {
  82. /* window */
  83. activeWindowId:0,//当前激活的窗口id
  84. activeWindow:null,//当前激活窗口
  85. windowList:[],//窗口列表
  86. listWrapLoading:null,
  87. /* window-content*/
  88. historyList:[],//当前窗口历史记录
  89. inputText:'',
  90. model:'Kimi',//当前选择的模型
  91. modelOldValue:'',
  92. showHint:false,//选择模型提示
  93. isTyping:false,//是否处于打字动画中
  94. windowContentLoading:null,
  95. answerLoading:false,//回答中
  96. companyName:'',
  97. aiFileIds:[],
  98. // 上传窗口的队列
  99. windowSet:new Set(),
  100. fileTypeRule:new RegExp(/\.pdf|\.pptx|\.docx$/,'i')
  101. };
  102. },
  103. watch:{
  104. model(newVal,oldVal){
  105. this.modelOldValue = oldVal
  106. }
  107. },
  108. computed:{
  109. },
  110. methods: {
  111. //改变活跃窗口
  112. changeActiveWindow(item){
  113. if(item.AiChatTopicId===0){
  114. this.handleAddNewWindow()
  115. return
  116. }
  117. if(item.AiChatTopicId===this.activeWindowId) return
  118. if(this.windowContentLoading&&this.windowContentLoading.visible){
  119. this.$message.warning('上个窗口未加载完成,请稍等')
  120. return
  121. }
  122. this.activeWindowId=item.AiChatTopicId
  123. this.activeWindow = this.windowList.find(i=>i.AiChatTopicId===item.AiChatTopicId)||{}
  124. this.historyList = []
  125. this.isTyping = false
  126. this.getWindowDetail()
  127. },
  128. //获取对话窗口具体信息
  129. getWindowDetail(){
  130. this.windowContentLoading = this.$loading({
  131. target:document.querySelector('.window-content-wrap'),
  132. });
  133. aiQAInterence.getTopicDetail({
  134. AiChatTopicId:this.activeWindowId
  135. }).then(res=>{
  136. if(res.Ret!==200) return
  137. const {List} = res.Data
  138. this.historyList = List||[]
  139. this.aiFileIds=this.historyList.map(item => item.OpenaiFileId).filter(Boolean)
  140. this.windowContentLoading&&this.windowContentLoading.close()
  141. //使用模型
  142. this.model = this.historyList.length?this.historyList[this.historyList.length-1].Model:'Kimi'
  143. //如果有历史记录,则滚动到底部
  144. this.windowContentToBottom()
  145. })
  146. },
  147. // 滚动到聊天窗口底部
  148. windowContentToBottom(){
  149. this.$nextTick(()=>{
  150. const windowContentWrap = document.querySelector('.window-content-wrap')
  151. windowContentWrap.scrollTo({
  152. top:windowContentWrap.scrollHeight,
  153. behavior:'smooth'
  154. })
  155. })
  156. },
  157. //格式化对话信息
  158. formatMsg(msg,type){
  159. let msgObj = {
  160. messageId:msg.AiChatId,
  161. messageTime:'',
  162. messageText:'',
  163. messageType:'',
  164. modelName:''
  165. }
  166. const {Ask,Answer,CreateTime,ModifyTime,isPlay,Model,OpenaiFilePath} = msg
  167. if(type==='user'){
  168. msgObj.messageText = Ask||''
  169. msgObj.messageType = 'question'
  170. msgObj.messageTime = CreateTime||''
  171. msgObj.askFileUrl = OpenaiFilePath || ''
  172. }
  173. else{
  174. msgObj.messageText = Answer||''
  175. msgObj.messageType = 'answer'
  176. msgObj.messageTime = ModifyTime||''
  177. msgObj.modelName = Model||''
  178. msgObj.isPlay = Boolean(isPlay)
  179. msgObj.askFileUrl = OpenaiFilePath || ''
  180. }
  181. return msgObj
  182. },
  183. //新建对话窗口
  184. handleAddNewWindow(){
  185. //禁止重复新建
  186. if(this.activeWindowId===0){
  187. this.$message.warning(this.$t('ToolBox.AIQuestion.add_new_window_hint'))
  188. return
  189. }
  190. //将相关值置空
  191. this.activeWindowId=0
  192. this.activeWindow=null
  193. this.historyList=[]
  194. this.model='Kimi'
  195. this.aiFileIds=[]
  196. this.isTyping = false
  197. },
  198. //开始播放动画
  199. handleStartTyping(){
  200. this.isTyping = true
  201. },
  202. //结束播放动画
  203. handleFinishedTyping(item){
  204. this.isTyping = false
  205. const {messageId} = item
  206. const index = this.historyList.findIndex(i=>i.AiChatId===messageId)
  207. index!==-1&&(this.historyList[index].isPlay = false)
  208. },
  209. //编辑对话窗口名称
  210. changeWindowTitle(title){
  211. aiQAInterence.editTopicName({
  212. AiChatTopicId:this.activeWindowId,
  213. TopicName:title
  214. }).then(res=>{
  215. if(res.Ret!==200) return
  216. this.$message.success(/* '保存成功' */this.$t('MsgPrompt.saved_msg'))
  217. this.getWindowList()
  218. })
  219. },
  220. //删除对话窗口
  221. deleteWindowItem(){
  222. const index = this.windowList.findIndex(i=>i.AiChatTopicId===this.activeWindowId)||0
  223. //更改activeWindowId
  224. /**
  225. * 一般情况:指向下一个
  226. * 若当前为最后一个,指向上一个
  227. * 如果是唯一一个,则置为0
  228. */
  229. let AiChatTopicId = 0
  230. if(this.windowList.length===1){
  231. AiChatTopicId=0
  232. }else if(index===this.windowList.length-1){
  233. AiChatTopicId = this.windowList[index-1].AiChatTopicId
  234. }else {
  235. AiChatTopicId = this.windowList[index+1].AiChatTopicId
  236. }
  237. aiQAInterence.deleteTopic({
  238. AiChatTopicId:this.activeWindowId
  239. }).then(res=>{
  240. if(res.Ret!==200) return
  241. this.getWindowList()
  242. this.changeActiveWindow({AiChatTopicId})
  243. })
  244. },
  245. //点击模型选择框
  246. //发送消息
  247. handleSendMsg(e){
  248. e.preventDefault()
  249. if(e.shiftKey===true) {
  250. this.inputText+='\n'
  251. return
  252. }
  253. if(this.isTyping||this.answerLoading){
  254. this.$message.warning('请等待回答完成')
  255. return
  256. }
  257. //新建窗口,未选择模型
  258. if(this.inputText.length===0){
  259. this.$message.warning(this.$t('ToolBox.AIQuestion.inter_check'))
  260. return
  261. }
  262. this.answerLoading=true
  263. this.activeWindowId===0&&(this.activeWindowId = -1)
  264. //mock 加入到historyList中
  265. const msgObj = {
  266. AiChatId:-1,
  267. AiChatTopicId:this.activeWindowId || 0,
  268. Ask:this.inputText,
  269. Answer:'回答生成中...',
  270. CreateTime:'',
  271. ModifyTime:'',
  272. Model:this.model
  273. }
  274. this.historyList.push(msgObj)
  275. //滚动到底部
  276. this.windowContentToBottom()
  277. const inputText = this.inputText
  278. this.inputText = ''
  279. let apiName = "sendChatMsg"
  280. let params={
  281. AiChatTopicId:this.activeWindowId<=0?0:this.activeWindowId,
  282. Ask:inputText,
  283. Model:this.model
  284. }
  285. if(this.aiFileIds && this.aiFileIds.length>0){
  286. // 文件检索功能
  287. apiName="fileRetrieve"
  288. params.OpenaiFileId=this.aiFileIds
  289. }
  290. aiQAInterence[apiName](params).then(res=>{
  291. this.answerLoading=false
  292. //在回答未获取前切换了新窗口
  293. if(this.historyList.length===0){
  294. this.getWindowList()
  295. return
  296. }
  297. const msg = this.historyList[this.historyList.length-1]
  298. if(res.Ret!==200){
  299. //提问失败
  300. msg.Answer = res.ErrMsg||res.Msg||''
  301. msg.isPlay = true
  302. this.historyList.splice(this.historyList.length-1,1,msg)
  303. return
  304. }
  305. //提问成功,替换对应数据
  306. const {AiChatTopicId,Answer,Ask,Model} = res.Data
  307. if(this.activeWindowId<=0){
  308. const windowItem = {
  309. AiChatTopicId:AiChatTopicId||0,
  310. TopicName:Ask,
  311. }
  312. this.windowList.push(windowItem)
  313. this.activeWindow = windowItem
  314. this.getWindowList()
  315. }
  316. //在回答未获取前切换了已有窗口
  317. if(this.activeWindowId>0&&this.activeWindowId!==AiChatTopicId) return
  318. this.activeWindowId = AiChatTopicId||0
  319. msg.Answer = Answer||''
  320. msg.Model = Model
  321. msg.isPlay = true
  322. this.historyList.splice(this.historyList.length-1,1,msg)
  323. }).catch(()=>{
  324. this.answerLoading=false
  325. const msg = this.historyList[this.historyList.length-1]
  326. msg.Answer = '回答超时,请重试!'
  327. msg.isPlay = true
  328. this.historyList.splice(this.historyList.length-1,1,msg)
  329. })
  330. },
  331. //获取窗口列表
  332. /**
  333. * @param {*} topicId AiChatTopicId 定位到具体窗口
  334. */
  335. getWindowList(topicId){
  336. this.listWrapLoading = this.$loading({
  337. target:document.querySelector('.list-wrap'),
  338. background: 'rgba(244, 245, 249, 1)'
  339. });
  340. aiQAInterence.getTopicList().then(res=>{
  341. if(res.Ret!==200) return
  342. this.windowList = res.Data.List||[]
  343. if(topicId){
  344. this.changeActiveWindow({AiChatTopicId:topicId})
  345. }
  346. this.listWrapLoading&&this.listWrapLoading.close()
  347. })
  348. },
  349. getBaseConfig(){
  350. etaBaseConfigInterence.getBaseConfig().then(res=>{
  351. if(res.Ret===200){
  352. this.companyName=res.Data.CompanyName||''
  353. }
  354. })
  355. },
  356. inputBoxDragover(event){
  357. event.preventDefault(); //阻止默认行为,允许放置
  358. },
  359. inputBoxDrop(event){
  360. event.preventDefault(); //阻止浏览器默认行为
  361. // 获取文件的数据
  362. const DataTransferItemList = event.dataTransfer.files
  363. if(DataTransferItemList && DataTransferItemList.length){
  364. if(DataTransferItemList.length>1){
  365. return this.$message.error("单次只能上传一个文件,请重试");
  366. }else{
  367. let file = DataTransferItemList[0]
  368. if(file.type && this.fileTypeRule.test(file.name)){
  369. if(file.size/1024/1024 > 50.1){
  370. this.$message.error("上传文件大小不超过50MB");
  371. return false;
  372. }
  373. this.handleUpload({file})
  374. }else{
  375. return this.$message.error("上传文件格式只支持PDF、PPTX、DOCX");
  376. }
  377. }
  378. }else{
  379. // 没有文件数据
  380. let txt = event.dataTransfer.getData("text/plain")
  381. this.inputText=txt
  382. }
  383. },
  384. handleBeforeUpload(e) {
  385. if(!this.fileTypeRule.test(e.name)){
  386. this.$message.error("上传文件格式只支持PDF、PPTX、DOCX");
  387. return false;
  388. }
  389. if(!(e.size/1024/1024 < 50.1)){
  390. this.$message.error("上传文件大小不超过50MB");
  391. return false;
  392. }
  393. },
  394. handleUpload(e){
  395. if(this.windowSet.has(this.activeWindowId)){
  396. return this.$message.warning("请等待文件上传完成")
  397. }
  398. let {file} = e
  399. let downloadHint = this.$message({
  400. type:"info",
  401. message:/* '上传中,请稍后······' */this.$t('ReportManage.CloudPage.upload_msg'),
  402. duration:0,
  403. iconClass:'el-icon-loading'
  404. })
  405. let formData = new FormData()
  406. formData.append('File',file)
  407. formData.append('AiChatTopicId',this.activeWindowId)
  408. formData.append('Model',this.model)
  409. this.windowSet.add(this.activeWindowId)
  410. aiQAInterence.fileUpload(formData).then(res=>{
  411. downloadHint.close()
  412. if(res.Ret == 200){
  413. let Data = res.Data || {}
  414. this.$message.success(`${Data.ResourceName}上传成功`)
  415. if(this.windowList.find(item => item.AiChatTopicId == Data.AiChatTopicId)){
  416. // 窗口存在
  417. this.windowSet.delete(Data.AiChatTopicId)
  418. if(Data.AiChatTopicId == this.activeWindowId){
  419. this.aiFileIds.push(Data.OpenaiFileId)
  420. const msgObj = {
  421. AiChatId:Data.AiChatId || -1,
  422. AiChatTopicId:Data.AiChatTopicId,
  423. Ask:Data.ResourceName,
  424. OpenaiFilePath:Data.ResourceUrl,
  425. Answer:Data.Answer || '',
  426. CreateTime:Data.CreateTime||'',
  427. ModifyTime:Data.ModifyTime || '',
  428. Model:this.model
  429. }
  430. this.historyList.push(msgObj)
  431. this.windowContentToBottom()
  432. }
  433. }else{
  434. //窗口不存在
  435. this.windowSet.delete(0)
  436. this.getWindowList(this.activeWindowId==0 ? Data.AiChatTopicId:0)
  437. }
  438. }
  439. }).catch(()=>{
  440. downloadHint.close()
  441. // 失败,清空
  442. this.windowSet.clear()
  443. })
  444. }
  445. },
  446. mounted(){
  447. this.getWindowList()
  448. this.getBaseConfig()
  449. const dropDom = document.getElementById('input-box')
  450. dropDom.addEventListener('dragover',this.inputBoxDragover);
  451. dropDom.addEventListener('drop',this.inputBoxDrop);
  452. },
  453. beforeDestroy(){
  454. const dropDom = document.getElementById('input-box')
  455. dropDom.removeEventListener('dragover',this.inputBoxDragover);
  456. dropDom.removeEventListener('drop',this.inputBoxDrop);
  457. }
  458. };
  459. </script>
  460. <style lang="scss">
  461. .ai-content-wrap{
  462. .el-select.hint{
  463. .el-input.is-focus .el-input__inner{
  464. border-color: red;
  465. }
  466. .el-input__inner:focus{
  467. border-color: red;
  468. }
  469. }
  470. }
  471. </style>
  472. <style scoped lang="scss">
  473. $border-color:#3D52A1;
  474. .ai-content-wrap{
  475. width:calc(100% - 64px);
  476. height:calc(100% - 64px);
  477. display: flex;
  478. position:relative;
  479. margin:30px;
  480. border:1px solid $border-color;
  481. border-radius: 32px;
  482. overflow: hidden;
  483. min-width: 960px;
  484. .window-list-wrap{
  485. width:380px;
  486. border-right: 1px solid #E2E2E2;
  487. padding:30px;
  488. box-sizing: border-box;
  489. background-color: #F4F5F9;
  490. display: flex;
  491. flex-direction: column;
  492. .window-title{
  493. display: flex;
  494. justify-content: space-between;
  495. align-items: center;
  496. .icon img{
  497. width:58px;
  498. height:58px;
  499. }
  500. .title-wrap{
  501. overflow: hidden;
  502. }
  503. .text-ellipsis{
  504. overflow: hidden;
  505. white-space: nowrap;
  506. text-overflow: ellipsis;
  507. }
  508. }
  509. .add-btn{
  510. border:2px dashed $border-color;
  511. border-radius:16px;
  512. padding:14px;
  513. margin-top:40px;
  514. text-align: center;
  515. font-size: 16px;
  516. color:#333333;
  517. cursor: pointer;
  518. background-color: #F4F5F9;
  519. transition: background-color .5s, color .5s;
  520. &:hover{
  521. background-color: white;
  522. color: $border-color;
  523. border-style: solid;
  524. i{
  525. color: $border-color;
  526. }
  527. }
  528. i{
  529. margin-right: 10px;
  530. font-weight: bold;
  531. font-size: 16px;
  532. }
  533. }
  534. .list-wrap{
  535. margin-top:30px;
  536. flex: 1;
  537. overflow-y: scroll;
  538. position:relative;
  539. .empty-list img{
  540. width:150px;
  541. height:150px;
  542. margin:0 auto;
  543. display: block;
  544. }
  545. }
  546. }
  547. .content-wrap{
  548. flex: 1;
  549. display: flex;
  550. flex-direction: column;
  551. min-width: 588px;
  552. .content-header{
  553. display: flex;
  554. justify-content: space-between;
  555. align-items: center;
  556. padding:20px 30px;
  557. box-sizing: border-box;
  558. border-bottom: 1px solid #E2E2E2;
  559. .title-wrap{
  560. p{
  561. color: #333333;
  562. font-size: 18px;
  563. margin-bottom: 5px;
  564. }
  565. span{
  566. color: #999999;
  567. line-height: 18px;
  568. }
  569. }
  570. }
  571. .window-content-wrap{
  572. flex: 1;
  573. padding:30px;
  574. text-align: center;
  575. overflow-y: scroll;
  576. overflow-x:hidden;
  577. position:relative;
  578. .content-item{
  579. text-align: left;
  580. .item{
  581. width: 100%;
  582. display: flex;
  583. padding:15px 0;
  584. border-bottom: 1px solid black;
  585. .content-item-avatar{
  586. width: 50px;
  587. margin-right: 20px;
  588. img{
  589. width:38px;
  590. height:38px;
  591. }
  592. }
  593. .text{
  594. flex: 1;
  595. }
  596. }
  597. }
  598. }
  599. .input-box{
  600. padding:12px 30px 30px;
  601. position: relative;
  602. .upload-row{
  603. display: flex;
  604. align-items: center;
  605. padding: 0 20px;
  606. margin-bottom: 12px;
  607. img{
  608. height: 20px;
  609. width: 20px;
  610. vertical-align: bottom;
  611. box-shadow: 3px 3px 8px 0px #182c421f;
  612. }
  613. span{
  614. color: #A5A5A5;
  615. font-size: 15px;
  616. font-weight: 400;
  617. }
  618. }
  619. textarea{
  620. width:100%;
  621. border-radius: 16px;
  622. box-sizing: border-box;
  623. padding:20px 95px 20px 20px;
  624. font-size: 16px;
  625. resize: none;
  626. border-color: #E3E3E3;
  627. box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.08);
  628. }
  629. .send-btn{
  630. position:absolute;
  631. bottom:50px;
  632. right:50px;
  633. padding:8px 12px;
  634. background-color: $border-color;
  635. border-radius: 6px;
  636. font-size: 14px;
  637. color: white;
  638. line-height: 14px;
  639. cursor: pointer;
  640. opacity: .7;
  641. transition: opacity .5s;
  642. img{
  643. width:14px;
  644. height:14px;
  645. margin-right: 8px;
  646. }
  647. &:hover,&.canClick{
  648. opacity: 1;
  649. }
  650. }
  651. }
  652. }
  653. .hidden-scrollbar{
  654. &::-webkit-scrollbar-track{
  655. display: none;
  656. }
  657. div::-webkit-scrollbar-track{
  658. display: none;
  659. }
  660. }
  661. }
  662. </style>