祁阳图书馆智慧大屏
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

919 lines
32 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. <template>
  2. <div style="padding: 0 .4rem;">
  3. <div class="pageOne-database">
  4. <!-- 到馆统计 -->
  5. <div class="database-left">
  6. <h3 class="database-title">到馆统计</h3>
  7. <ul class="inLib-num">
  8. <li
  9. v-for="(item, index) in leftData"
  10. :key="index"
  11. :class="[{'allTotal': item.id === 'allTotal'}, {'lastYearTotal': item.id === 'lastYearTotal'}]"
  12. >
  13. <div class="pageLeft-flop-box">
  14. <div>
  15. <span v-for="(ls, i) in item.valueArr" :key="item.id + i" :class="[{'flop-figure': !isNaN(ls)}, {'flop-comma': isNaN(ls)}]">
  16. <i v-if="!isNaN(ls)">0123456789</i>
  17. <span v-else>{{ ls }}</span>
  18. </span>
  19. <em></em>
  20. </div>
  21. </div>
  22. <div class="flop-item-name">{{ item.name }}</div>
  23. </li>
  24. </ul>
  25. <ul class="pageOne-left-progress">
  26. <li v-for="(item,index) in progressData" :key="index" :class="[{'blue-progress':item.type===1 || item.type === 2},{'orange-progress':item.type===3 || item.type === 4}]">
  27. <p>{{ item.name }}</p>
  28. <span class="progress-num">{{ item.value }}<i></i></span>
  29. <el-progress :percentage="computedPercentage(item)" :stroke-width="8" :show-text="false" />
  30. </li>
  31. </ul>
  32. </div>
  33. <!-- 中间大数据 -->
  34. <!-- <div class="database-middle">
  35. <div class="database-box">
  36. <a class="logo" href="#" />
  37. <div class="ring ring1">
  38. <div class="particle" />
  39. </div>
  40. <div class="ring ring2">
  41. <div class="particle" />
  42. </div>
  43. <div class="ring ring3">
  44. <div class="particle" />
  45. </div>
  46. </div>
  47. <div v-for="(item,index) in middleData" :key="index" :class="['middle-item', {'totalBook': item.id === 'totalBook'}, {'fansNum': item.id === 'fansNum'}, {'lendingNum': item.id === 'lendingNum'}, {'cardNum': item.id === 'cardNum'}]">
  48. <p>{{ item.name }}</p>
  49. <div class="small-module">
  50. <div class="chartNum">
  51. <div class="box-items">
  52. <li v-for="(e,i) in item.valueArr" :key="i" class="number-item">
  53. <span><i ref="numberItem" class="item">0123456789</i></span>
  54. </li>
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. </div> -->
  60. <div class="database-middle">
  61. <div class="middle-img">
  62. <div class="middle-img-book" />
  63. <div class="wq" />
  64. <!-- <div class="line-box">
  65. <div class="box">
  66. <div class="ball" />
  67. </div>
  68. </div> -->
  69. <div class="middle-img-bottom">
  70. <div style="width: 360; height: 200px; position: relative; margin: 50px 0 0 30px;">
  71. <svg width="360" height="200">
  72. <path d="M0 80 S 170 160, 400 70" />
  73. </svg>
  74. <div class="rect qxRect" />
  75. </div>
  76. </div>
  77. <div class="middle-img-dot" />
  78. </div>
  79. <div v-for="(item,index) in middleData" :key="index" :class="['middle2-item', {'totalBook': item.id === 'totalBook'}, {'fansNum': item.id === 'fansNum'}, {'lendingNum': item.id === 'lendingNum'}, {'cardNum': item.id === 'cardNum'}]">
  80. <p>{{ item.name }}</p>
  81. <div class="middle-num">
  82. <div class="small-module">
  83. <div class="chartNum">
  84. <div class="box-items">
  85. <li v-for="(e,i) in item.valueArr" :key="i" :class="!isNaN(e) ? 'number-item':'number-item num-dot'">
  86. <span v-if="!isNaN(e)" class="items-int"><i ref="numberItem" class="item">0123456789</i></span>
  87. <span v-else>{{ e }}</span>
  88. <!-- <span><i ref="numberItem" class="item">0123456789</i></span> -->
  89. </li>
  90. </div>
  91. </div>
  92. </div>
  93. <span v-if="item.id === 'totalBook'" class="middle-unit"></span>
  94. <span v-if="item.id === 'fansNum'" class="middle-unit"></span>
  95. <span v-if="item.id === 'cardNum'" class="middle-unit"></span>
  96. <span v-if="item.id === 'lendingNum'" class="middle-unit"></span>
  97. </div>
  98. </div>
  99. </div>
  100. <!-- 热门搜索 -->
  101. <div class="database-right">
  102. <h3 class="database-title">热门搜索</h3>
  103. <div class="tagcloud-main">
  104. <div v-if="tagList.length !== 0" id="tagscloud" ref="tagcloudall" class="tagscloud">
  105. <!-- <a v-for="(item,index) in hotTagData" :key="index" :class="'tagc' + ((index % 4) + 1)">
  106. {{ item }}
  107. </a> -->
  108. <a v-for="(item,index) in tagList" :key="index" :class="'tagc' + ((index % 4) + 1)">{{ item }}</a>
  109. </div>
  110. </div>
  111. </div>
  112. </div>
  113. <!-- 底部 图书推荐 -->
  114. <div class="pageOne-book">
  115. <h3 class="database-title">图书推荐</h3>
  116. <div class="pageOne-book-content">
  117. <div class="scrollBox">
  118. <vue-seamless-scroll
  119. ref="listData"
  120. :data="listData1"
  121. :class-option="defaultOption"
  122. class="seamless01"
  123. >
  124. <ul>
  125. <li v-for="(item, index) in listData1" :key="index">
  126. <div class="bord">
  127. <div class="book-img">
  128. <img :src="item.nbImgPath" :onerror="defaultImg">
  129. </div>
  130. </div>
  131. </li>
  132. </ul>
  133. </vue-seamless-scroll>
  134. <vue-seamless-scroll
  135. ref="listData2"
  136. :data="listData2"
  137. :class-option="default2Option"
  138. class="seamless02"
  139. >
  140. <ul>
  141. <li v-for="(item, index) in listData2" :key="index">
  142. <div class="bord">
  143. <div class="book-img">
  144. <img :src="item.nbImgPath" :onerror="defaultImg">
  145. </div>
  146. </div>
  147. </li>
  148. </ul>
  149. </vue-seamless-scroll>
  150. </div>
  151. <div class="wechat-code">
  152. <div class="wechat-img">
  153. <img :src="wecharQrCodeSrc">
  154. </div>
  155. <span>微信扫一扫关注</span>
  156. </div>
  157. </div>
  158. </div>
  159. </div>
  160. </template>
  161. <script>
  162. import { FetchInitSetting, FetchUsertotal, FetchLibBookTotal, FetchHotSearch, FetchFansCount, FetchLendingTotal, FetchNewBook, FetchMarcByISBN } from '@/api/library'
  163. export default {
  164. name: 'PageOne',
  165. data() {
  166. return {
  167. intervalLeft: null,
  168. isDataLoaded: false,
  169. pageOneVisitBase: '0', // 本年到馆基础数
  170. wecharQrCodeSrc: null,
  171. newList: [],
  172. listData1: [],
  173. listData2: [],
  174. defaultImg: 'this.src="' + require('@/assets/images/book_03.png') + '"',
  175. leftData: [],
  176. progressData: [],
  177. hotTagData: [],
  178. middleData: [],
  179. tagList: [],
  180. // 热门搜索的
  181. radius: 160,
  182. dtr: Math.PI / 180,
  183. d: 200,
  184. mcList: [],
  185. active: false,
  186. lasta: 1,
  187. lastb: 1,
  188. distr: true,
  189. tspeed: 4,
  190. size: 200,
  191. mouseX: 0,
  192. mouseY: 20,
  193. howElliptical: 1,
  194. oList: null,
  195. oA: null,
  196. sa: 0,
  197. ca: 0,
  198. sb: 0,
  199. cb: 0,
  200. sc: 0,
  201. cc: 0
  202. }
  203. },
  204. computed: {
  205. defaultOption() {
  206. return {
  207. step: 0.5, // 数值越大速度滚动越快
  208. limitMoveNum: 4, // 开始无缝滚动的数据量 this.dataList.length
  209. hoverStop: true, // 是否开启鼠标悬停stop
  210. direction: 2, // 0向下 1向上 2向左 3向右
  211. openWatch: true, // 开启数据实时监控刷新dom
  212. singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
  213. singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
  214. waitTime: 1000 // 单步运动停止的时间(默认值1000ms)
  215. }
  216. },
  217. default2Option() {
  218. return {
  219. step: 0.5, // 数值越大速度滚动越快
  220. limitMoveNum: 4, // 开始无缝滚动的数据量 this.dataList.length
  221. hoverStop: true, // 是否开启鼠标悬停stop
  222. direction: 3, // 0向下 1向上 2向左 3向右
  223. openWatch: true, // 开启数据实时监控刷新dom
  224. singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
  225. singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
  226. waitTime: 1000 // 单步运动停止的时间(默认值1000ms)
  227. }
  228. },
  229. computedPercentage() {
  230. return (item) => {
  231. if (item.type === 1) {
  232. return item.value > this.getType3Value() ? 100 : 70
  233. } else if (item.type === 2) {
  234. return item.value > this.getType4Value() ? 100 : 70
  235. } else if (item.type === 3) {
  236. return item.value > this.getType1Value() ? 100 : 70
  237. } else if (item.type === 4) {
  238. return item.value > this.getType2Value() ? 100 : 70
  239. }
  240. }
  241. }
  242. },
  243. async created() {
  244. this.getInitData()
  245. this.getMiddleAllData()
  246. this.getHotSearch()
  247. this.getNewBook()
  248. },
  249. beforeDestroy() {
  250. clearInterval(this.intervalLeft)
  251. this.intervalLeft = null
  252. },
  253. activated() {
  254. this.pageOneVisitBase = 0
  255. this.getInitData()
  256. },
  257. deactivated() {
  258. },
  259. mounted() {
  260. if (localStorage.getItem('wecharQrCodeSrc')) {
  261. this.wecharQrCodeSrc = localStorage.getItem('wecharQrCodeSrc')
  262. }
  263. },
  264. methods: {
  265. getInitData() {
  266. // visitBase 本年到馆基础数
  267. // wecharQrCode 二维码 用/downloadFile/+wecharQrCode
  268. // iNotice 公告
  269. const linkSrc = process.env.VUE_APP_BASE_API
  270. FetchInitSetting().then(res => {
  271. const result = JSON.parse(res.data)
  272. this.pageOneVisitBase = result.visitBase
  273. this.wecharQrCodeSrc = linkSrc + '/downloadFile' + result.wecharQrCode
  274. this.initLeftPreview(result)
  275. // this.intervalLeft = setInterval(() => {
  276. // this.getInitData()
  277. // }, 10000)
  278. })
  279. },
  280. initLeftPreview(result) {
  281. this.progressData = []
  282. this.leftData = []
  283. // visitBase 本年累计人次
  284. // visitBaseCheck 是否直接显示 0false 1true
  285. // lastYearVisitBase 去年累计人次
  286. // todayVisitBase 今日人次
  287. // todayVisitBaseCheck 是否显示
  288. // yesterdayVisitBase 昨天人次
  289. // yesterdayVisitBaseCheck 是否显示
  290. // thisMonthVisitBase 本月人次
  291. // thisMonthVisitBaseCheck 是否显示
  292. // lastMonthVisitBase 上个月人次
  293. // lastMonthVisitBaseCheck 是否显示
  294. const baseTotal = this.pageOneVisitBase // 本年到馆人数
  295. console.log('假设本年到馆人数', baseTotal)
  296. // 本年到馆/12个月 = 月基数
  297. const monthBase = Math.floor(baseTotal / 12) // 月基数
  298. console.log('月基数', monthBase)
  299. // 月随机数(-100到200之间)
  300. const randomMonth = Math.floor(Math.random() * (200 - (-100) + 1)) + (-100)
  301. const now = new Date()
  302. const year = now.getFullYear() // 当前年份
  303. const month = now.getMonth() + 1 // 当前月份
  304. const daysInMonth = new Date(year, month, 0).getDate() // 当月天数
  305. console.log('当月天数', daysInMonth)
  306. // 月基数/当月天数(28、29、30、31)= 日基数
  307. const dayBase = Math.floor(monthBase / daysInMonth) // 日基数
  308. console.log('日基数', dayBase)
  309. // 本年累计=月基数*月份+月随机数(-100到200之间)
  310. let nowYearCount
  311. if (result.visitBaseCheck === '1') {
  312. nowYearCount = result.visitBase
  313. } else {
  314. nowYearCount = Math.floor(monthBase * month + randomMonth) // 本年累计
  315. }
  316. console.log('本年累计', nowYearCount)
  317. // 昨日到馆=日基数+日随机数(-20到50之间)
  318. let yesterdayCount = 0
  319. if (result.yesterdayVisitBaseCheck === '1') {
  320. yesterdayCount = result.yesterdayVisitBase
  321. } else {
  322. const randomDay = Math.floor(Math.random() * (50 - (-20) + 1)) + (-20) // 日随机数(-20到50之间)
  323. yesterdayCount = localStorage.getItem('yesterdayCountCache') ? localStorage.getItem('yesterdayCountCache') : dayBase + randomDay // 昨日到馆
  324. }
  325. console.log('昨日到馆', yesterdayCount)
  326. // 上月到馆=月基数+月随机数(-100到200之间)
  327. let lastMonthCount = 0
  328. if (result.lastMonthVisitBaseCheck === '1') {
  329. lastMonthCount = result.lastMonthVisitBase
  330. } else {
  331. lastMonthCount = localStorage.getItem('lastMonthCountCache') ? localStorage.getItem('lastMonthCountCache') : monthBase + randomMonth
  332. }
  333. console.log('上月到馆', lastMonthCount)
  334. // 日基数/10小时=小时基数
  335. const hourBase = Math.floor(dayBase / 10) // 小时基数
  336. console.log('小时基数', hourBase)
  337. // 图书馆营业时间(8:00-18:00共10小时)
  338. // 8:00-9:00 算第1个小时、9:00-10:00算第2个小时、以此类推
  339. const openTime = 8 // 开门时间
  340. const closeTime = 18 // 结束时间
  341. const currentHour = now.getHours() // 当前时间点
  342. // 今日到馆=小时基数 * 第N小时+小时随机数(-5到10之间)
  343. let todayCount = 0
  344. if (result.todayVisitBaseCheck === '1') {
  345. todayCount = result.todayVisitBase
  346. } else {
  347. if (currentHour < openTime || currentHour >= closeTime) {
  348. console.log('当前时间不在图书馆营业时间内')
  349. todayCount = 0
  350. } else {
  351. const N = currentHour - openTime
  352. console.log('第N个小时', N)
  353. const randomHour = Math.floor(Math.random() * (10 - (-5) + 1)) + (-5) // 小时随机数(-5到10之间)
  354. todayCount = Math.floor(hourBase * N + randomHour) // 今日到馆
  355. }
  356. }
  357. console.log('今日到馆', todayCount)
  358. // 本月到馆=月基数 * (当前月的日期dd/当前月的天数)+ 月随机数(-100到200之间)
  359. let nowMonthCount = 0
  360. if (result.thisMonthVisitBaseCheck === '1') {
  361. nowMonthCount = result.thisMonthVisitBase
  362. } else {
  363. nowMonthCount = Math.floor(monthBase * (now.getDate() / daysInMonth) + randomMonth) // 本月到馆
  364. }
  365. console.log('本月到馆', nowMonthCount)
  366. this.progressData.push(
  367. {
  368. name: '今日到馆',
  369. value: todayCount,
  370. type: 1
  371. },
  372. {
  373. name: '本月到馆',
  374. value: nowMonthCount,
  375. type: 2
  376. },
  377. {
  378. name: '昨日到馆',
  379. value: yesterdayCount,
  380. type: 3
  381. },
  382. {
  383. name: '上月到馆',
  384. value: lastMonthCount,
  385. type: 4
  386. }
  387. )
  388. this.leftData.push({
  389. id: 'allTotal',
  390. name: '本年累计到馆',
  391. value: this.$parent.formatter(nowYearCount),
  392. valueArr: this.$parent.formatter(nowYearCount).split('')
  393. },
  394. {
  395. id: 'lastYearTotal',
  396. name: '去年累计到馆',
  397. value: this.$parent.formatter(result.lastYearVisitBase),
  398. valueArr: this.$parent.formatter(result.lastYearVisitBase).split('')
  399. })
  400. this.$parent.timedRefresh(this.leftData, 'left')
  401. // 昨日到馆、上月到馆存一个缓存!当前第一次计算好之后就不变了!
  402. localStorage.setItem('yesterdayCountCache', yesterdayCount)
  403. localStorage.setItem('lastMonthCountCache', lastMonthCount)
  404. },
  405. // 热门搜索
  406. getHotSearch() {
  407. const params = {
  408. 'size': 40
  409. }
  410. FetchHotSearch(params).then(res => {
  411. this.hotTagData = res.data.replace(/^\[|\]$/g, '').split(', ')
  412. this.$nextTick(() => {
  413. this.tagList = this.hotTagData
  414. this.onReady()
  415. })
  416. })
  417. },
  418. getMiddleAllData() {
  419. Promise.all([
  420. this.getLibBookTotal(),
  421. this.getUserTotal(),
  422. this.getFansNum(),
  423. this.getLendingTotal()
  424. ]).then(([libBookTotal, userCardNum, fansNum, lendingTotal]) => {
  425. this.middleData.push(
  426. {
  427. id: 'totalBook',
  428. name: '藏书总量',
  429. value: libBookTotal,
  430. valueArr: this.$parent.formatter(libBookTotal).toString().split('')
  431. },
  432. {
  433. id: 'cardNum',
  434. name: '累计办证',
  435. value: userCardNum,
  436. valueArr: this.$parent.formatter(userCardNum).toString().split('')
  437. },
  438. {
  439. id: 'fansNum',
  440. name: '粉丝数量',
  441. value: fansNum,
  442. valueArr: this.$parent.formatter(fansNum).toString().split('')
  443. },
  444. {
  445. id: 'lendingNum',
  446. name: '累计借出',
  447. value: lendingTotal,
  448. valueArr: this.$parent.formatter(lendingTotal).toString().split('')
  449. }
  450. )
  451. this.$parent.timedRefresh(this.middleData, 'middle')
  452. // setTimeout(() => {
  453. // this.$parent.timedRefresh(this.middleData, 'middle')
  454. // }, 8000)
  455. }).catch(error => {
  456. console.error('Error fetching data:', error)
  457. })
  458. },
  459. // 馆藏量
  460. getLibBookTotal() {
  461. const params = {
  462. 'libcode': 'LSJDFG,LJPFG,DCDFG,QYTSG,SJLFG,XMDFG,FXLFG,QLQFG,SEDSG,MZZFG,GYTZFG,KJSKCFG,JBTZFG,SKTZFG,XJZFG,PSZFG,DZQZFG,WXJDFG,CHJDFG,BSZFG,BZHFG',
  463. 'starttime': '2000-01-01',
  464. 'endtime': '2034-01-01'
  465. }
  466. return FetchLibBookTotal(params).then(res => {
  467. const result = JSON.parse(res.data)
  468. if (result.success & result.resultlist.length !== 0) {
  469. return result.resultlist.reduce((acc, obj) => acc + obj.GCL, 0)
  470. } else {
  471. return 0
  472. }
  473. }).catch(error => {
  474. console.error('Error', error)
  475. return 0
  476. })
  477. },
  478. // 累计办证
  479. getTotalForLibcode(libcode) {
  480. const params = {
  481. 'libcode': libcode,
  482. 'startdate': this.getFormattedDate(new Date(), -1),
  483. 'enddate': this.getFormattedDate(new Date()),
  484. 'isrdtype': 0
  485. }
  486. return FetchUsertotal(params).then(res => {
  487. const result = JSON.parse(res.data)
  488. if (result.success && result.pagedata.length > 0) {
  489. return result.pagedata[0].count
  490. } else {
  491. throw new Error('Failed' + libcode)
  492. }
  493. }).catch(error => {
  494. console.error('Error' + libcode, error)
  495. return 0
  496. })
  497. },
  498. getUserTotal() {
  499. const libraries = ['QYTSG', 'SJLFG', 'FXLFG', 'SEDSG', 'BZHFG']
  500. const getTotalPromises = libraries.map(libcode => this.getTotalForLibcode(libcode))
  501. return Promise.all(getTotalPromises)
  502. .then(counts => counts.reduce((sum, count) => sum + parseInt(count, 10), 0))
  503. .catch(error => {
  504. console.error('Error', error)
  505. return 0
  506. })
  507. },
  508. // 粉丝数量
  509. getFansNum() {
  510. return FetchFansCount().then(res => {
  511. return res.data ? parseInt(res.data) : 0
  512. }).catch(error => {
  513. console.error('Error', error)
  514. return 0
  515. })
  516. },
  517. // 累计借出
  518. getLendingTotal() {
  519. return FetchLendingTotal().then(res => {
  520. const result = JSON.parse(res.data)
  521. if (result.success & result.resultlist.length !== 0) {
  522. return result.resultlist.filter(item => item.LIBCODE !== '999').reduce((acc, obj) => acc + obj.JCC, 0)
  523. } else {
  524. return 0
  525. }
  526. }).catch(error => {
  527. console.error('Error', error)
  528. return 0
  529. })
  530. },
  531. // bottom - 图书推荐
  532. getNewBook() {
  533. const params = {
  534. 'size': 40
  535. }
  536. FetchNewBook(params).then(res => {
  537. // 图片地址格式 http://192.168.99.67:8080/downloadFile/qytsg/ae281b90-b100-4541-9379-3e104854652c.png
  538. const linkSrc = process.env.VUE_APP_BASE_API
  539. this.newList = res.data.map(item => {
  540. if (item.nbImgPath) {
  541. item.nbImgPath = linkSrc + '/downloadFile' + item.nbImgPath
  542. return Promise.resolve(item)
  543. } else {
  544. const params = {
  545. 'sIsbn': item.isbn
  546. }
  547. return FetchMarcByISBN(params).then(response => {
  548. const result = JSON.parse(response.data)[0]
  549. if (result.srcurl) {
  550. item.nbImgPath = result.srcurl
  551. return item
  552. } else if (result.img) {
  553. item.nbImgPath = 'data:image/png;base64,' + result.img
  554. return item
  555. } else {
  556. return null // 或者根据需求返回其他值或处理
  557. }
  558. })
  559. }
  560. })
  561. Promise.all(this.newList).then(results => {
  562. // 过滤掉返回的空项(根据实际需求)
  563. this.newList = results.filter(item => item !== null)
  564. // 一分为二得两行
  565. const halfLength = Math.ceil(this.newList.length / 2)
  566. this.listData1 = this.newList.slice(0, halfLength)
  567. this.listData2 = this.newList.slice(halfLength)
  568. })
  569. })
  570. },
  571. getType1Value() {
  572. const type1Item = this.progressData.find(item => item.type === 1)
  573. return type1Item ? type1Item.value : 0
  574. },
  575. getType2Value() {
  576. const type2Item = this.progressData.find(item => item.type === 2)
  577. return type2Item ? type2Item.value : 0
  578. },
  579. getType3Value() {
  580. const type3Item = this.progressData.find(item => item.type === 3)
  581. return type3Item ? type3Item.value : 0
  582. },
  583. getType4Value() {
  584. const type4Item = this.progressData.find(item => item.type === 4)
  585. return type4Item ? type4Item.value : 0
  586. },
  587. // 以下生成云标签部分
  588. // 三角函数角度计算
  589. sineCosine(a, b, c) {
  590. this.sa = Math.sin(a * this.dtr)
  591. this.ca = Math.cos(a * this.dtr)
  592. this.sb = Math.sin(b * this.dtr)
  593. this.cb = Math.cos(b * this.dtr)
  594. this.sc = Math.sin(c * this.dtr)
  595. this.cc = Math.cos(c * this.dtr)
  596. },
  597. // 设置初始定位
  598. positionAll() {
  599. this.$nextTick(() => { // 注意: 所有的在onReady方法中执行的方法都需要$nextTick确保所有的标签都已经渲染
  600. var phi = 0
  601. var theta = 0
  602. var max = this.mcList.length
  603. var aTmp = []
  604. var oFragment = document.createDocumentFragment()
  605. // 随机排序
  606. for (let i = 0; i < this.tagList.length; i++) {
  607. aTmp.push(this.oA[i])
  608. }
  609. aTmp.sort(() => {
  610. return Math.random() < 0.5 ? 1 : -1
  611. })
  612. for (let i = 0; i < aTmp.length; i++) {
  613. oFragment.appendChild(aTmp[i])
  614. }
  615. this.oList.appendChild(oFragment)
  616. for (let i = 1; i < max + 1; i++) {
  617. if (this.distr) {
  618. phi = Math.acos(-1 + (2 * i - 1) / max)
  619. theta = Math.sqrt(max * Math.PI) * phi
  620. } else {
  621. phi = Math.random() * (Math.PI)
  622. theta = Math.random() * (2 * Math.PI)
  623. }
  624. // 坐标变换
  625. this.mcList[i - 1].cx = this.radius * Math.cos(theta) * Math.sin(phi)
  626. this.mcList[i - 1].cy = this.radius * Math.sin(theta) * Math.sin(phi)
  627. this.mcList[i - 1].cz = this.radius * Math.cos(phi)
  628. this.oA[i - 1].style.left = this.mcList[i - 1].cx + this.oList.offsetWidth / 2 - this.mcList[i - 1].offsetWidth / 2 + 'px'
  629. this.oA[i - 1].style.top = this.mcList[i - 1].cy + this.oList.offsetHeight / 2 - this.mcList[i - 1].offsetHeight / 2 + 'px'
  630. }
  631. })
  632. },
  633. // 坐标更新 让标签动起来
  634. update() {
  635. this.$nextTick(() => { // 注意: 所有的在onReady方法中执行的方法都需要$nextTick确保所有的标签都已经渲染
  636. var a
  637. var b
  638. // if (this.active) {
  639. a = (Math.min(Math.max(-this.mouseY, -this.size), this.size) / this.radius) * this.tspeed
  640. b = (-Math.min(Math.max(-this.mouseX, -this.size), this.size) / this.radius) * this.tspeed
  641. // } else {
  642. // a = this.lasta * 0.98
  643. // b = this.lastb * 0.98
  644. // }
  645. this.lasta = a
  646. this.lastb = b
  647. if (Math.abs(a) <= 0.01 && Math.abs(b) <= 0.01) {
  648. return
  649. }
  650. var c = 0
  651. this.sineCosine(a, b, c)
  652. for (var j = 0; j < this.mcList.length; j++) {
  653. if (this.mcList[j].on) {
  654. continue
  655. }
  656. var rx1 = this.mcList[j].cx
  657. var ry1 = this.mcList[j].cy * this.ca + this.mcList[j].cz * (-this.sa)
  658. var rz1 = this.mcList[j].cy * this.sa + this.mcList[j].cz * this.ca
  659. var rx2 = rx1 * this.cb + rz1 * this.sb
  660. var ry2 = ry1
  661. var rz2 = rx1 * (-this.sb) + rz1 * this.cb
  662. var rx3 = rx2 * this.cc + ry2 * (-this.sc)
  663. var ry3 = rx2 * this.sc + ry2 * this.cc
  664. var rz3 = rz2
  665. this.mcList[j].cx = rx3
  666. this.mcList[j].cy = ry3
  667. this.mcList[j].cz = rz3
  668. var per = this.d / (this.d + rz3)
  669. this.mcList[j].x = (this.howElliptical * rx3 * per) - (this.howElliptical * 2)
  670. this.mcList[j].y = ry3 * per
  671. this.mcList[j].scale = per
  672. var alpha = per
  673. alpha = (alpha - 0.6) * (10 / 6)
  674. this.mcList[j].alpha = alpha * alpha * alpha - 0.2
  675. // this.mcList[j].alpha = (this.mcList[j].alpha - 0.6) * (10 / 6)
  676. this.mcList[j].zIndex = Math.ceil(100 - Math.floor(this.mcList[j].cz))
  677. }
  678. this.doPosition()
  679. this.depthSort()
  680. })
  681. },
  682. //
  683. doPosition() {
  684. this.$nextTick(() => { // 注意: 所有的在onReady方法中执行的方法都需要$nextTick确保所有的标签都已经渲染
  685. var l = this.oList.offsetWidth / 2
  686. var t = this.oList.offsetHeight / 2
  687. for (var i = 0; i < this.mcList.length; i++) {
  688. this.oA[i].style.left = this.mcList[i].cx + l - this.mcList[i].offsetWidth / 2 + 'px'
  689. this.oA[i].style.top = this.mcList[i].cy + t - this.mcList[i].offsetHeight / 2 + 'px'
  690. // this.oA[i].style.fontSize = Math.ceil(12 * this.mcList[i].scale / 2) + 8 + 'px'
  691. this.oA[i].style.filter = 'alpha(opacity=' + 100 * this.mcList[i].alpha + ')'
  692. this.oA[i].style.opacity = this.mcList[i].alpha
  693. }
  694. })
  695. },
  696. depthSort() {
  697. this.$nextTick(() => { // 注意: 所有的在onReady方法中执行的方法都需要$nextTick确保所有的标签都已经渲染
  698. var aTmp = []
  699. for (let i = 0; i < this.oA.length; i++) {
  700. aTmp.push(this.oA[i])
  701. }
  702. aTmp.sort(function(vItem1, vItem2) {
  703. if (vItem1.cz > vItem2.cz) {
  704. return -1
  705. } else if (vItem1.cz < vItem2.cz) {
  706. return 1
  707. } else {
  708. return 0
  709. }
  710. })
  711. for (let i = 0; i < aTmp.length; i++) {
  712. aTmp[i].style.zIndex = i
  713. }
  714. })
  715. },
  716. onReady() {
  717. this.$nextTick(() => {
  718. this.oList = this.$refs.tagcloudall
  719. this.oA = this.oList.getElementsByTagName('a')
  720. var oTag = null
  721. for (var i = 0; i < this.oA.length; i++) {
  722. oTag = {}
  723. oTag.offsetWidth = this.oA[i].offsetWidth
  724. oTag.offsetHeight = this.oA[i].offsetHeight
  725. this.mcList.push(oTag)
  726. }
  727. this.sineCosine(0, 0, 0)
  728. this.positionAll()
  729. this.oList.onmouseover = () => {
  730. this.active = true
  731. }
  732. this.oList.onmouseout = () => {
  733. this.active = false
  734. }
  735. // this.oList.onmousemove = (event) => {
  736. // var oEvent = window.event || event
  737. // this.mouseX = oEvent.clientX - (this.oList.offsetLeft + this.oList.offsetWidth / 2)
  738. // this.mouseY = oEvent.clientY - (this.oList.offsetTop + this.oList.offsetHeight / 2)
  739. // this.mouseX /= 5
  740. // this.mouseY /= 5
  741. // }
  742. setInterval(() => {
  743. this.update()
  744. }, 40) // 定时器执行 不能写setInterval(this.update(), 30)
  745. })
  746. }
  747. }
  748. }
  749. </script>
  750. <style lang="scss">
  751. @import "~@/assets/styles/index.scss";
  752. @import "~@/assets/styles/font-some.css";
  753. #tagscloud{
  754. width:400px;
  755. height:380px;
  756. position:relative;
  757. margin:0 auto;
  758. }
  759. #tagscloud a{
  760. position:absolute;
  761. top:0px;
  762. left:0px;
  763. line-height:24px;
  764. text-align:center;
  765. font-size:18px;
  766. padding:3px 5px;
  767. display:inline-block;
  768. text-wrap: nowrap;
  769. }
  770. #tagscloud a.tagc1{
  771. // border: 1px solid #30ADA6;
  772. // background-color: #106B66;
  773. // color: #51EAE2;
  774. color: #F4C263;
  775. }
  776. #tagscloud a.tagc2{
  777. font-size: 22px;
  778. // border: 1px solid #3A64BE;
  779. // background: rgba(16,45,107,0.7);
  780. color: #7EA7FF;
  781. }
  782. #tagscloud a.tagc3{
  783. font-size: 18px;
  784. // border: 1px solid #9439B6;
  785. // background: rgba(74,18,95,0.8);
  786. // color: #CD63F4;
  787. color: #7EA7FF;
  788. }
  789. #tagscloud a.tagc4{
  790. font-size: 26px;
  791. // border: 1px solid #C2943C;
  792. // background: rgba(107,76,16,0.7);
  793. color: #F4C263;
  794. }
  795. .tagcloud {
  796. width: 10rem;
  797. height: 5rem;
  798. overflow: hidden;
  799. p{
  800. padding: .0625rem;
  801. border-bottom: 2px dashed rgba(24, 77, 97, 0.5);
  802. span{
  803. display: block;
  804. padding: .075rem 8px;
  805. white-space: nowrap;
  806. }
  807. &.color1{
  808. border-top: 2px dashed #1F6374;
  809. border-left: 3px dashed #184D61;
  810. border-right: 3px dashed #184D61;
  811. span{
  812. border: 1px solid #30ADA6;
  813. background-color: #106B66;
  814. color: #51EAE2;
  815. }
  816. }
  817. &.color2{
  818. border-top: 2px dashed #203F7F;
  819. border-left: 3px dashed #102857;
  820. border-right: 3px dashed #102857;
  821. span{
  822. border: 1px solid #3A64BE;
  823. background: rgba(16,45,107,0.7);
  824. color: #7EA7FF;
  825. }
  826. }
  827. &.color3{
  828. border-top: 2px dashed #613689;
  829. border-left: 3px dashed #4C2E75;
  830. border-right: 3px dashed #4C2E75;
  831. span{
  832. border: 1px solid #9439B6;
  833. background: rgba(74,18,95,0.8);
  834. color: #CD63F4;
  835. }
  836. }
  837. &.color4{
  838. border-top: 2px dashed #6A5735;
  839. border-left: 3px dashed #655435;
  840. border-right: 3px dashed #655435;
  841. span{
  842. border: 1px solid #C2943C;
  843. background: rgba(107,76,16,0.7);
  844. color: #F4C263;
  845. }
  846. }
  847. }
  848. }
  849. .scrollBox{
  850. flex: 1;
  851. height: calc(100%);
  852. box-sizing: border-box;
  853. margin-left: 0.45rem;
  854. overflow: hidden;
  855. .seamless01{
  856. margin-bottom: .35rem;
  857. }
  858. ul{
  859. display: flex;
  860. height: 2rem;
  861. // overflow: hidden;
  862. li{
  863. width: 1.375rem;
  864. height: 2rem;
  865. margin-right: .7375rem;
  866. cursor: pointer;
  867. .bord{
  868. display: flex;
  869. flex-wrap: wrap;
  870. justify-content: space-around;
  871. align-items: center;
  872. .book-img{
  873. width: 1.375rem;
  874. height: 2rem;
  875. // background: url('~@/assets/images/book_03.png') no-repeat center center;
  876. // background-size: contain;
  877. display: flex;
  878. align-items: center;
  879. overflow: hidden;
  880. img{
  881. display: block;
  882. width: 100%;
  883. }
  884. }
  885. }
  886. }
  887. }
  888. }
  889. </style>