index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. <template>
  2. <div style="background: #FAFAFA;height: 100%;">
  3. <div class="contentAlbunMain">
  4. <div class="topBox">
  5. <div>
  6. <div class="numBox">
  7. <img src="../../../../image/analysis0.png"/>
  8. <div>{{format_number(totalData.knowledge)}}</div>
  9. <div>知识仓库总量</div>
  10. </div>
  11. </div >
  12. <div>
  13. <div class="numBox">
  14. <img src="../../../../image/analysis1.png"/>
  15. <div>{{format_number(totalData.map)}}</div>
  16. <div>知识地图总量</div>
  17. </div>
  18. </div>
  19. <div>
  20. <div class="numBox">
  21. <img src="../../../../image/analysis2.png"/>
  22. <div>{{format_number(totalData.album)}}</div>
  23. <div>知识专辑总量</div>
  24. </div>
  25. </div>
  26. </div>
  27. <div class="middleBox">
  28. <div class="topTitle" style="width: 240px;">
  29. <div>搜索访问量分布(pv)</div>
  30. <div>{{format_number(barTotalNum)}}
  31. </div>
  32. <div style="display:none">
  33. <div class="barNameBox" v-for="(item, index) in NameArr" :key="index">
  34. <div :style="{'background':colorbarArr[index]}"></div>
  35. <div>{{ item }}</div>
  36. </div>
  37. </div>
  38. </div>
  39. <div ref="eCharts0" class="barBox"></div>
  40. </div>
  41. <div class="bottomBox">
  42. <div class="bottomBoxLeft">
  43. <div class="topTitle textBorder">
  44. <div>高频搜索词</div>
  45. </div>
  46. <div ref="eCharts1" class="wordCloudBox"></div>
  47. </div>
  48. <div class="bottomBoxRight">
  49. <div class="topTitle">
  50. <div>知识类型分布</div>
  51. <div>{{format_number(pieTotalNum)}}</div>
  52. </div>
  53. <div ref="eCharts2" style="height: 100%;width: 100%;"></div>
  54. </div>
  55. </div>
  56. </div>
  57. </div>
  58. </template>
  59. <script>
  60. import {mapState} from "vuex";
  61. import analysis from '@/api/knowledge/analysis'
  62. import * as echarts from 'echarts'
  63. import 'echarts-wordcloud'
  64. export default {
  65. name: 'albumIndex',
  66. components: {
  67. },
  68. computed: {
  69. ...mapState({
  70. user: (state) => state.appSetting.user,
  71. })
  72. },
  73. data() {
  74. return {
  75. pieTotalNum:0,
  76. barTotalNum:0,
  77. totalData:{},
  78. textData:[{
  79. "name": "花鸟市场",
  80. "value": 1446
  81. }],
  82. colorbarArr:['#406cc4','#00c8dc','#f84e4c','#ff900d','#ffbe00','#cacd96','#31339a','#67ce97','#cc9b97','#99ce64','#ccce00','#fb012e','#cb9b97','#003263','#2e3699','#cbfe65','#cb9bcb'],
  83. NameArr:[],
  84. delId:'',
  85. delVisible:false,
  86. scope:2,//1-我的专辑 2-全部专辑 3-我的点评
  87. searchName:'',
  88. categoryId:'',
  89. pageSize:6,
  90. total:18,
  91. pageNum:1,
  92. dataList:[],
  93. imgUrl: require('@img/avatar2.jpg'),
  94. menuArr:['知识地图','新人地图','岗位地图','制度地图'],
  95. actionMenu:0,
  96. level1Action:-1,
  97. level2Action:-1,
  98. showLevel1Num:-1,
  99. classifyArr:[],
  100. colorArr:['#1890ff','#3e4c84','#379eff','#379eff','#69d289','#facd1b']
  101. }
  102. },
  103. created() {
  104. if (this.user.photo && this.user.photo != '') {
  105. this.imgUrl = '/api/api-system/system/core/sysFile/previewFile?fileId='+this.user.photo
  106. }
  107. if(this.$router.query){
  108. if(this.$router.query.scope) {
  109. this.scope = this.$router.query.scope
  110. }
  111. }
  112. },
  113. mounted(){
  114. this.getTotalAmount();
  115. this.getSearchVisitHistogram();
  116. this.getKnowledgeTypeAmount();
  117. this.getSearchParticipleWordCloud();
  118. },
  119. methods: {
  120. //获取数量
  121. getTotalAmount(){
  122. analysis.totalAmount().then((res) => {
  123. this.totalData=res.data
  124. })
  125. },
  126. //搜索访问量分布
  127. getSearchVisitHistogram(){
  128. let that = this
  129. analysis.searchVisitHistogram().then((res) => {
  130. let barData=res.data
  131. that.barTotalNum=barData.total
  132. let xAxisData=barData.lables.map(item=>{return item.name})
  133. let seriesData=[]
  134. barData.lables.forEach((el, index) => {
  135. el.values.forEach((item,num) =>{
  136. if(index==0){
  137. that.NameArr.push(item.legend)
  138. let tempData={
  139. color:that.colorbarArr[num],
  140. name: item.legend,
  141. type: 'bar',
  142. barGap:'0%',
  143. barCategoryGap:'40%',
  144. stack: 'AllData',
  145. dataGroupId:11,
  146. stackStrategy:'all',
  147. emphasis: {
  148. focus: 'series'
  149. },
  150. data: [{value:item.value,itemStyle:{ barBorderRadius: [0, 0, 0, 0] }}],
  151. percentage:[item.percentage]
  152. }
  153. /*if(num==(el.values.length-1)){
  154. tempData.itemStyle={
  155. normal: {
  156. //这里设置柱形图圆角 [左上角,右上角,右下角,左下角]
  157. barBorderRadius:[6, 6, 0, 0]
  158. }
  159. }
  160. }*/
  161. seriesData.push(tempData)
  162. }else{
  163. seriesData[num].data.push({value:item.value,itemStyle:{ barBorderRadius: [0, 0, 0, 0] }})
  164. seriesData[num].percentage.push(item.percentage)
  165. }
  166. })
  167. });
  168. //for (let i=(seriesData[0].data.length-1);i>-1;i--) { // 遍历所有的x轴数据(总数为n),为单根柱条提供data下标(0 ~ n-1)
  169. for (let i in seriesData[0].data) {
  170. for (let j=(seriesData.length-1);j>-1;j--) {
  171. if (seriesData[j].data[i].value != 0) { // 找到第一个不为0的值,为该项添加itemStyle
  172. seriesData[j].data[i]['itemStyle'] = { barBorderRadius: [4, 4, 0, 0] };
  173. break; //退出该柱条的循环
  174. }
  175. }
  176. }
  177. let offsetX = window.innerWidth/150
  178. let fontSize = 19.2*window.innerWidth/1920
  179. let boxSize = 14*window.innerWidth/1920
  180. let paddingSize = 8*window.innerWidth/1920
  181. var option0 = {
  182. legend:{
  183. show:true,
  184. itemWidth:boxSize,
  185. itemHeight:boxSize,
  186. itemGap:fontSize,
  187. textStyle:{
  188. color:'#202124',
  189. fontSize:fontSize+'px',
  190. padding:[0,fontSize,0,paddingSize]
  191. }
  192. },
  193. tooltip: {
  194. backgroundColor:'#999999',
  195. borderColor:'rgba(0,0,0,0.0)',
  196. textStyle:{
  197. 'color':'#FAFAFB',
  198. 'lineHeight': 14,
  199. 'fontSize':14
  200. },
  201. position: 'top',
  202. formatter: params => {
  203. let dataIndex = params.dataIndex
  204. let resStr = ''
  205. for (let i=0;i<seriesData.length;i++) {
  206. if(i==0){
  207. resStr=resStr+"<div class='tooltipBox' style='margin-top:0px'><div class='tooltipLeft' style='background:"+that.colorbarArr[i]+"'></div>&nbsp;&nbsp;&nbsp;&nbsp;"+that.format_number(seriesData[i].data[dataIndex].value)+"&nbsp;&nbsp;&nbsp;&nbsp;"+seriesData[i].percentage[dataIndex]*100+"%</div>"
  208. }else{
  209. resStr=resStr+"<div class='tooltipBox'><div class='tooltipLeft' style='background:"+that.colorbarArr[i]+"'></div>&nbsp;&nbsp;&nbsp;&nbsp;"+that.format_number(seriesData[i].data[dataIndex].value)+"&nbsp;&nbsp;&nbsp;&nbsp;"+seriesData[i].percentage[dataIndex]*100+"%</div>"
  210. }
  211. }
  212. //const { name, value } = params
  213. return resStr
  214. }
  215. },
  216. /* tooltip: {
  217. position: function (point, params, dom, rect, size) {
  218. console.log(dom.clientWidth)
  219. let dataIndex = params[0].dataIndex
  220. let basNum = window.innerWidth/1920
  221. //let marginNum = (dom.clientWidth-126-basNum*100)/2
  222. let marginNum = 0
  223. return {left: 10+(70+110*dataIndex)*basNum-marginNum, top: point[1]};
  224. // return {left: 1300, top: point[1]};
  225. },
  226. backgroundColor:'rgba(0,0,0,0.5)',
  227. borderWidth:'0',
  228. textStyle:{
  229. 'color':'#FAFAFB',
  230. 'lineHeight': 14,
  231. 'fontSize':14
  232. },
  233. trigger: 'axis',
  234. axisPointer: {
  235. type: 'shadow'
  236. },
  237. formatter: params => {
  238. let dataIndex = params[0].dataIndex
  239. let resStr = ''
  240. for (let i=0;i<seriesData.length;i++) {
  241. if(i==0){
  242. resStr=resStr+"<div class='tooltipBox' style='margin-top:0px'><div class='tooltipLeft' style='background:"+that.colorbarArr[i]+"'></div>&nbsp;&nbsp;&nbsp;&nbsp;"+seriesData[i].data[dataIndex].value+"&nbsp;&nbsp;&nbsp;&nbsp;"+seriesData[i].percentage[dataIndex]*100+"%</div>"
  243. }else{
  244. resStr=resStr+"<div class='tooltipBox'><div class='tooltipLeft' style='background:"+that.colorbarArr[i]+"'></div>&nbsp;&nbsp;&nbsp;&nbsp;"+seriesData[i].data[dataIndex].value+"&nbsp;&nbsp;&nbsp;&nbsp;"+seriesData[i].percentage[dataIndex]*100+"%</div>"
  245. }
  246. }
  247. //const { name, value } = params
  248. return resStr
  249. }
  250. },*/
  251. /*tooltip: {
  252. position: function (point, params, dom, rect, size) {
  253. // 固定在顶部
  254. return [point[0], '10%'];
  255. },
  256. trigger: 'item',
  257. formatter: params => {
  258. const { name, value } = params
  259. return `${name} <br/>数量:${value}`
  260. }
  261. },*/
  262. grid: {
  263. top:'20%',
  264. left: '2%',
  265. right: '4%',
  266. bottom: '3%',
  267. containLabel: true
  268. },
  269. xAxis: [
  270. {
  271. show: true,
  272. type: 'category',
  273. data: xAxisData,
  274. offset:offsetX,
  275. // 坐标 轴线
  276. axisLine: {
  277. show: true,
  278. lineStyle: {
  279. type: 'solid',
  280. color: '#F1F1F5',
  281. width: 1
  282. },
  283. },
  284. axisTick:{
  285. show:false
  286. },
  287. axisLabel:{
  288. color:'#92929D',
  289. fontSize:14
  290. }
  291. }
  292. ],
  293. yAxis: [
  294. {
  295. type: 'value',
  296. splitLine:{
  297. lineStyle: {
  298. type: 'solid',
  299. color: '#F1F1F5',
  300. width: 1
  301. }
  302. },
  303. axisLabel:{
  304. color:'#92929D',
  305. fontSize:14
  306. }
  307. }
  308. ],
  309. series: seriesData
  310. };
  311. var pieEl0=this.$refs.eCharts0;
  312. var pieChart0=echarts.init(pieEl0);
  313. pieChart0.setOption(option0);
  314. })
  315. },
  316. // 饼状图
  317. getKnowledgeTypeAmount(){
  318. let that = this
  319. analysis.knowledgeTypeAmount().then((res) => {
  320. let pieData=res.data
  321. that.pieTotalNum=pieData.total
  322. var option2 = {
  323. tooltip: {
  324. trigger: 'item',
  325. backgroundColor:'rgba(0,0,0,0.5)',
  326. borderWidth:'0',
  327. textStyle:{
  328. 'color':'#FAFAFB'
  329. },
  330. formatter: params => {
  331. //console.log(params.data.name)
  332. //const { name, value } = params
  333. return params.data.name
  334. }
  335. },
  336. grid: {
  337. left: '3%',
  338. top: '20%',
  339. bottom: '3%',
  340. containLabel: true
  341. },
  342. series: [
  343. {
  344. roseType: 'radius',
  345. top:'10%',
  346. name: '知识类型分布',
  347. type: 'pie',
  348. radius: '60%',
  349. data: [
  350. { value: pieData.wiki, name: '维基知识\n'+pieData.wiki, itemStyle:{color:'#406cc4'}},
  351. { value: pieData.archive, name: '文档知识\n'+pieData.archive, itemStyle:{color:'#aebfee'},selected:true}
  352. ],
  353. selectedOffset:100,
  354. labelLayout(params) {
  355. return {
  356. x: params.labelLinePoints[2][0]<params.rect.x?params.labelLinePoints[2][0]-params.labelRect.width:params.labelLinePoints[2][0],
  357. verticalAlign: 'middle',
  358. align: 'left'
  359. }
  360. },
  361. label:{
  362. fontSize:window.innerWidth/100,
  363. lineHeight:window.innerWidth/100
  364. },
  365. labelLine:{
  366. lineStyle:{
  367. color:'#000'
  368. },
  369. length:window.innerWidth/100,
  370. length2:0
  371. },
  372. emphasis: {
  373. scaleSize:10,
  374. itemStyle: {
  375. shadowBlur: 10,
  376. shadowOffsetX: 0,
  377. shadowColor: 'rgba(0, 0, 0, 0.5)'
  378. }
  379. }
  380. }
  381. ]
  382. };
  383. var pieEl2=that.$refs.eCharts2;
  384. var pieChart2=echarts.init(pieEl2);
  385. pieChart2.setOption(option2);
  386. })
  387. },
  388. //高频搜索词
  389. getSearchParticipleWordCloud(){
  390. let that = this
  391. analysis.searchParticipleWordCloud().then((res) => {
  392. let textData=[]
  393. res.data.forEach(item => {
  394. let tempData={
  395. name:item.participle,
  396. value:item.frequency
  397. }
  398. textData.push(tempData)
  399. })
  400. var option1={
  401. backgroundColor:'#fff',
  402. tooltip: {
  403. trigger: 'item',
  404. backgroundColor:'rgba(0,0,0,0.5)',
  405. borderWidth:'0',
  406. textStyle:{
  407. 'color':'#FAFAFB'
  408. },
  409. formatter: params => {
  410. const { name, value } = params
  411. return `${name} <br/>数量:${value}`
  412. }
  413. },
  414. series: [{
  415. type: 'wordCloud',
  416. // shape这个属性虽然可配置,但是在词的数量不太多的时候,效果不明显,它会趋向于画一个椭圆
  417. shape: 'line',
  418. // 这个功能还没用过
  419. keepAspect: false,
  420. // 下面就是位置的配置
  421. left: '0',
  422. top: '0',
  423. width: '100%',
  424. height: '100%',
  425. // 词的大小,最小12px,最大60px,可以在这个范围调整词的大小
  426. sizeRange: [window.innerWidth/100, window.innerWidth/30],
  427. // 每个词旋转的角度范围和旋转的步进
  428. rotationRange: [0, 90],
  429. rotationStep: 90,
  430. // 词间距,数值越小,间距越小,这里间距太小的话,会出现大词把小词套住的情况,比如一个大的口字,中间会有比较大的空隙,这时候他会把一些很小的字放在口字里面,这样的话,鼠标就无法选中里面的那个小字,这里可以用函数根据词云的数量动态返回间距
  431. gridSize: 12,
  432. // 允许词太大的时候,超出画布的范围
  433. drawOutOfBound: false,
  434. // 布局的时候是否有动画
  435. layoutAnimation: true,
  436. // 这是全局的文字样式,相对应的还可以对每个词设置字体样式
  437. textStyle: {
  438. fontFamily: 'sans-serif',
  439. fontWeight: 'bold',
  440. // 颜色可以用一个函数来返回字符串,这里是随机色
  441. color: function () {
  442. // Random color
  443. return that.colorArr[Math.floor(Math.random()*6)]
  444. }
  445. },
  446. emphasis: {
  447. shadowBlur: 10,
  448. shadowColor: '#333'
  449. },
  450. // 数据必须是一个数组,数组是对象,对象必须有name和value属性
  451. data: textData
  452. }]
  453. }
  454. var pieEl1=that.$refs.eCharts1;
  455. var pieChart1=echarts.init(pieEl1);
  456. pieChart1.setOption(option1);
  457. })
  458. },
  459. //数字分隔符
  460. format_number(n) {
  461. var b = parseInt(n).toString();
  462. var len = b.length;
  463. if (len <= 3) { return b; }
  464. var r = len % 3;
  465. return r > 0 ? b.slice(0, r) + "," + b.slice(r, len).match(/\d{3}/g).join(",") : b.slice(r, len).match(/\d{3}/g).join(",");
  466. },
  467. //搜索
  468. searchResult(data){
  469. this.searchName = decodeURI(data.keyword)
  470. this.getData()
  471. },
  472. //删除start
  473. del(id){
  474. this.delId = id
  475. this.delVisible = true
  476. },
  477. //删除确认
  478. confirmOk(){
  479. let postData = {ids:this.delId}
  480. album.del(postData).then((res) => {
  481. if(res.code == 200) {
  482. this.delVisible = false
  483. this.$message.success("删除成功!");
  484. this.getData()
  485. }
  486. })
  487. },
  488. closeDel(){
  489. this.delVisible = false
  490. },
  491. //删除end
  492. changeScope(num){
  493. this.scope = num
  494. this.pageNum = 1
  495. this.getData()
  496. },
  497. //查询数据
  498. getData(){
  499. },
  500. //新增专辑
  501. goCreatData(){
  502. this.$router.push({
  503. name: "albumDetail",
  504. query: {
  505. isAdd: 1,
  506. scope: this.scope
  507. }
  508. })
  509. },
  510. //修改页码
  511. pageChange(num){
  512. this.pageNum = num
  513. this.getData()
  514. },
  515. //查看2级分类
  516. showMore(num){
  517. if(this.classifyArr[num].children.length!=0){
  518. this.showLevel1Num = num
  519. }
  520. },
  521. //关闭所有分类
  522. clearAllLevel(){
  523. if(this.level2Action==-1){
  524. this.showLevel1Num = -1
  525. }
  526. },
  527. //选择分类1级
  528. selectLevel(num,pkId){
  529. this.level2Action = -1
  530. if(this.level1Action == num){
  531. this.level1Action = -1
  532. this.categoryId = ''
  533. }else{
  534. this.level1Action = num
  535. this.categoryId = pkId
  536. }
  537. this.getData()
  538. },
  539. //选择分类2级
  540. selectLevel2(num,pkId){
  541. this.level1Action = -1
  542. if(this.level2Action == num){
  543. this.level2Action = -1
  544. }else{
  545. this.level2Action = num
  546. this.categoryId = pkId
  547. this.getData()
  548. }
  549. }
  550. }
  551. }
  552. </script>
  553. <style lang="less" scoped>
  554. .contentAlbunMain{
  555. overflow: scroll;
  556. padding: 0vw 10.93vw;
  557. width: 100%;
  558. display: flex;
  559. background: #FAFAFA;
  560. flex-direction: column;
  561. padding-bottom: 2vw;
  562. }
  563. .numBox{
  564. width: 24.73vw;
  565. height: 11.51vw;
  566. background: #fff;
  567. border-radius: 10px;
  568. display: flex;
  569. flex-direction: column;
  570. align-items: center;
  571. margin-top:3.6465vw;
  572. }
  573. .topBox{
  574. display: flex;
  575. justify-content: space-between;
  576. width: 100%;
  577. }
  578. .middleBox{
  579. width: 100%;
  580. background: #fff;
  581. border-radius: 10px;
  582. height: 24.896vw;
  583. margin-top: 1.25vw;
  584. }
  585. .bottomBox{
  586. width: 100%;
  587. display: flex;
  588. justify-content: space-between;
  589. margin-top: 1.4vw;
  590. }
  591. .bottomBoxLeft{
  592. height: 20vw;
  593. background: #fff;
  594. border-radius: 10px;
  595. width: 49.6vw;
  596. }
  597. .bottomBoxRight{
  598. height: 20vw;
  599. background: #fff;
  600. border-radius: 10px;
  601. width: 26vw;
  602. }
  603. .numBox img{
  604. width: 5.15625vw;
  605. height: 5.15625vw;
  606. margin-top: -2.135vw;
  607. }
  608. .numBox div:nth-child(2){
  609. font-size: 1.5625vw;
  610. width: 100%;
  611. word-break: break-all;
  612. color: #202124;
  613. margin-top: 1.2vw;
  614. text-align: center;
  615. }
  616. .numBox div:last-child{
  617. font-size: 0.9375vw;
  618. width: 100%;
  619. color: #92929D;
  620. margin-top: 1.2vw;
  621. text-align: center;
  622. }
  623. .topTitle{
  624. width: 15.625vw;
  625. margin-top: 1.5625vw;
  626. margin-left: 1.5625vw;
  627. position: absolute;
  628. }
  629. .topTitle div:nth-child(2){
  630. color: #202124;
  631. font-size: 1.5625vw;
  632. word-break: break-all;
  633. }
  634. .topTitle div:first-child{
  635. color: rgb(146, 146, 157);
  636. font-size: 0.9375vw;
  637. }
  638. .topTitle div:nth-child(3){
  639. color: #202124;
  640. width: 74vw;
  641. display: flex;
  642. justify-content: center;
  643. margin-top: -1.8vw;
  644. }
  645. .barBox{
  646. height: 80%;
  647. margin-top: 3.6vw;
  648. }
  649. .wordCloudBox{
  650. height: 73%;
  651. margin-top: 4.2vw;
  652. width: 46vw;
  653. margin-left: 30px;
  654. }
  655. .barNameBox{
  656. display: flex;
  657. flex-direction: row;
  658. align-items: end;
  659. width: auto!important;
  660. margin-right: 0.8333vw;
  661. font-size: 0.9375;
  662. }
  663. .barNameBox div:nth-child(1){
  664. width: 0.72vw;
  665. height: 0.72vw;
  666. margin-right: 0.52vw;
  667. margin-bottom: 0.3vw;
  668. border-radius: 2px;
  669. }
  670. .barNameBox div:nth-child(2){
  671. font-size: 1vw;
  672. }
  673. </style>
  674. <style>
  675. .tooltipLeft{
  676. width: 0.6vw;
  677. height: 0.6vw;
  678. border-radius: 2px;
  679. display: inline-block;
  680. }
  681. .tooltipBox{
  682. margin-left: 16px;
  683. margin-right: 16px;
  684. margin-top:8px;
  685. }
  686. .textBorder{
  687. width: 46vw!important;
  688. padding-bottom: 1vw;
  689. border-bottom: 1px solid rgb(244, 246, 249);
  690. }
  691. </style>