大湾社区城市书房智慧大屏
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.

430 lines
17 KiB

1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
  1. <template>
  2. <div class="page-wrapper ">
  3. <div class="page-three">
  4. <div class="three-item three01">
  5. <div class="database-title">本年累计借阅数量</div>
  6. <div class="three-lending">
  7. <div class="three-lending-left">
  8. <h5>本年累计借阅</h5>
  9. <ul class="totalItem">
  10. <li
  11. v-for="(item, index) in yearTotal"
  12. :key="index"
  13. :class="[{'yearTotal': item.id === 'yearTotal'}]"
  14. >
  15. <div class="pageLeft-flop-box">
  16. <div>
  17. <span v-for="(ls, i) in item.valueArr" :key="item.id + i" :class="[{'flop-figure': !isNaN(ls)}, {'flop-comma': isNaN(ls)}]">
  18. <i v-if="!isNaN(ls)">0123456789</i>
  19. </span>
  20. </div>
  21. </div>
  22. </li>
  23. </ul>
  24. <YearCircle :year-all-num="yearAllNum" />
  25. </div>
  26. <div class="three-lending-right lending-ranking">
  27. <h5>分馆累计借阅排行榜</h5>
  28. <div class="ranking-cont">
  29. <ul class="ranking-title">
  30. <li style="width: 0.625rem;">排名</li>
  31. <li style="width: 1.875rem; text-align: left;">图书馆名称</li>
  32. <li style="flex:1;" />
  33. <li style="width: 1.25rem; padding-right: .125rem; text-align: right;">借阅数量</li>
  34. </ul>
  35. <ul class="ranking-list">
  36. <li v-for="(item,index) in rankingYearWithPercentage" :key="index" :class="{ 'hovered': index === currentHover }">
  37. <div style="width: .625rem; color: #79B8FF;" :class="[{'ranking-num1':index===0},{'ranking-num2':index===1},{'ranking-num3':index===2}]">{{ index>=3 ? index+1 : null }}</div>
  38. <div style="width: 1.75rem; text-align: left;">{{ item.name }}</div>
  39. <div class="ranking-progress" style="flex:1; align-self: center;">
  40. <el-progress :percentage="item.percentage" :stroke-width="8" :show-text="false" color="#009afb" />
  41. </div>
  42. <div style="width: 1.25rem; padding-right: .125rem; text-align: right;">{{ item.JCC_YEAR }}<i style="padding-left:.0625rem;"></i></div>
  43. </li>
  44. </ul>
  45. </div>
  46. </div>
  47. </div>
  48. </div>
  49. <div class="three-item three02">
  50. <div class="database-title">今日借阅数量</div>
  51. <div class="three-lending">
  52. <div class="three-lending-left">
  53. <h5>今日累计借阅</h5>
  54. <ul class="totalItem">
  55. <li
  56. v-for="(item, index) in todayTotal"
  57. :key="index"
  58. :class="[{'todayTotal': item.id === 'todayTotal'}]"
  59. >
  60. <div class="pageLeft-flop-box">
  61. <div>
  62. <span v-for="(ls, i) in item.valueArr" :key="item.id + i" :class="[{'flop-figure': !isNaN(ls)}, {'flop-comma': isNaN(ls)}]">
  63. <i v-if="!isNaN(ls)">0123456789</i>
  64. </span>
  65. </div>
  66. </div>
  67. </li>
  68. </ul>
  69. <TodayCircle :today-all-num="todayAllNum" />
  70. </div>
  71. <div class="three-lending-right lending-ranking">
  72. <h5>分馆今日借阅排行榜 </h5>
  73. <div class="ranking-cont">
  74. <ul class="ranking-title">
  75. <li style="width: 0.625rem;">排名</li>
  76. <li style="width: 1.5rem; text-align: left;">图书馆名称</li>
  77. <li style="flex:1;" />
  78. <li style="width: 1.25rem; padding-right: .125rem; text-align: right;">借阅数量</li>
  79. </ul>
  80. <ul class="ranking-list">
  81. <li v-for="(item,index) in rankingTodayWithPercentage" :key="index" :class="{ 'hovered': index === currentHover }">
  82. <div style="width: 0.625rem; color: #79B8FF;" :class="[{'ranking-num1':index===0},{'ranking-num2':index===1},{'ranking-num3':index===2}]">{{ index>=3 ? index+1 : null }}</div>
  83. <div style="width: 1.75rem; text-align: left;">{{ item.name }}</div>
  84. <div class="ranking-progress" style="flex:1; align-self: center;">
  85. <el-progress :percentage="item.percentage" :stroke-width="8" :show-text="false" color="#009afb" />
  86. </div>
  87. <div style="width: 1.25rem; padding-right: .125rem; text-align: right;">{{ item.JCC_DAY }}<i style="padding-left:.0625rem;"></i></div>
  88. </li>
  89. </ul>
  90. </div>
  91. </div>
  92. </div>
  93. </div>
  94. <div class="three-item three03">
  95. <div class="database-title">今日借阅趋势</div>
  96. <div class="chart-wrapper" style="width: 11.25rem; height: calc(100% - 35px);">
  97. <LineChart :chart-day-data="chartDayData" />
  98. </div>
  99. </div>
  100. <div class="three-item three04">
  101. <div class="database-title">近7日借阅统计</div>
  102. <div class="chart-wrapper" style="width: 11.25rem; height: calc(100% - 20px);">
  103. <BarEcharts :chart-weekly-data="chartWeeklyData" />
  104. </div>
  105. </div>
  106. </div>
  107. </div>
  108. </template>
  109. <script>
  110. import { FetchLibcodeDetails, FetchLendingTotal, FetchTodayJH, FetchWeekJH } from '@/api/library'
  111. import LineChart from '@/components/echart/lineChart'
  112. import BarEcharts from '@/components/echart/barEcharts'
  113. import YearCircle from '@/components/echart/yearCircle'
  114. import TodayCircle from '@/components/echart/todayCircle'
  115. export default {
  116. name: 'PageThree',
  117. components: {
  118. LineChart,
  119. BarEcharts,
  120. YearCircle,
  121. TodayCircle
  122. },
  123. data() {
  124. return {
  125. currentHover: -1,
  126. chartDayData: {
  127. timeData: [],
  128. returnData: [],
  129. borrowedData: []
  130. },
  131. chartWeeklyData: {
  132. date: [],
  133. inchartWeeklyData: [],
  134. outchartWeeklyData: []
  135. },
  136. todayTotal: [],
  137. yearTotal: [],
  138. rankingYearData: [],
  139. rankingTodayData: [],
  140. rankingYearWithPercentage: [],
  141. rankingTodayWithPercentage: [],
  142. yearAllNum: {
  143. headerLib: 0,
  144. branchLib: 0
  145. },
  146. todayAllNum: {
  147. headerLib: 0,
  148. branchLib: 0
  149. },
  150. rankInterval: null,
  151. swiperOptionThumbs: {
  152. direction: 'vertical',
  153. loopedSlides: 6,
  154. slidesPerView: 6,
  155. slidesPerGroup: 6,
  156. autoplay: {
  157. delay: 3000,
  158. stopOnLastSlide: false,
  159. disableOnInteraction: true
  160. }
  161. },
  162. isKeep: false
  163. }
  164. },
  165. computed: {
  166. swiper() {
  167. return this.$refs.swiperThumbs.swiper
  168. }
  169. },
  170. beforeDestroy() {
  171. clearInterval(this.rankInterval)
  172. this.rankInterval = null
  173. // 主动清除父组件的 todayTotal/yearTotal 定时器
  174. this.$parent.clearExistingTimer('todayTotal')
  175. this.$parent.clearExistingTimer('yearTotal')
  176. },
  177. created() {
  178. this.getWeekJH()
  179. },
  180. activated() {
  181. this.getLendingTotal()
  182. this.getTodayJH()
  183. this.isKeep = true
  184. },
  185. deactivated() {
  186. clearInterval(this.rankInterval)
  187. this.rankInterval = null
  188. this.isKeep = false
  189. // 主动清除父组件的 todayTotal/yearTotal 定时器
  190. this.$parent.clearExistingTimer('todayTotal')
  191. this.$parent.clearExistingTimer('yearTotal')
  192. },
  193. mounted() {
  194. },
  195. methods: {
  196. paddingNum(num, length) {
  197. for (var len = (num + '').length; len < length; len = num.length) {
  198. num = '0' + num
  199. }
  200. return num
  201. },
  202. // 获取本年/今日借阅情况
  203. getLendingTotal() {
  204. this.todayTotal = []
  205. this.yearTotal = []
  206. FetchLendingTotal().then(res => {
  207. const result = JSON.parse(res.data)
  208. if (result.success & result.resultlist.length !== 0) {
  209. // JCC_YEAR 本年借阅册数
  210. // JCC_DAY 今日借阅册数
  211. const dayNum = result.resultlist.filter(item => item.LIBCODE === 'DWSF').reduce((acc, obj) => acc + obj.JCC_DAY, 0)
  212. const yearNum = result.resultlist.filter(item => item.LIBCODE === 'DWSF').reduce((acc, obj) => acc + obj.JCC_YEAR, 0)
  213. this.todayTotal.push({
  214. id: 'todayTotal',
  215. name: '今日累计借阅',
  216. value: this.$parent.formatter(this.paddingNum(dayNum, 5)),
  217. valueArr: this.$parent.formatter(this.paddingNum(dayNum, 5)).split('')
  218. })
  219. this.yearTotal.push({
  220. id: 'yearTotal',
  221. name: '本年累计借阅',
  222. value: this.$parent.formatter(this.paddingNum(yearNum, 5)),
  223. valueArr: this.$parent.formatter(this.paddingNum(yearNum, 5)).split('')
  224. })
  225. // 总管就是QYTSG的数据,分馆就是其他除去999以为的合计
  226. this.yearAllNum = {
  227. 'headerLib': result.resultlist.filter(item => item.LIBCODE === 'DWSF')[0].JCC_YEAR,
  228. 'branchLib': result.resultlist.filter(item => item.LIBCODE === 'ZJWSF' && item.LIBCODE !== '999').reduce((acc, obj) => acc + obj.JCC_YEAR, 0)
  229. }
  230. this.todayAllNum = {
  231. 'headerLib': result.resultlist.filter(item => item.LIBCODE === 'DWSF')[0].JCC_DAY,
  232. 'branchLib': result.resultlist.filter(item => item.LIBCODE === 'ZJWSF' && item.LIBCODE !== '999').reduce((acc, obj) => acc + obj.JCC_DAY, 0)
  233. }
  234. // 排行榜显示前6的
  235. this.getLibcodeDetails(result.resultlist)
  236. this.$parent.timedRefresh(this.todayTotal, 'todayTotal')
  237. this.$parent.timedRefresh(this.yearTotal, 'yearTotal')
  238. } else {
  239. this.todayTotal = []
  240. this.yearTotal = []
  241. }
  242. }).catch(error => {
  243. console.error('Error', error)
  244. })
  245. },
  246. // 分管显示内容
  247. getLibcodeDetails(data) {
  248. console.log('data', data)
  249. FetchLibcodeDetails().then(res => {
  250. const result = JSON.parse(res.data)
  251. if (result.length !== 0) {
  252. const newDataArray = []
  253. const nameToLibcodeMap = {
  254. '葛店城市书房·大湾分馆': 'DWSF',
  255. '葛店城市书房·张家湾分馆': 'ZJWSF'
  256. }
  257. const allowedLibcodes = ['DWSF', 'ZJWSF']
  258. data.forEach(item => {
  259. console.log('item', item)
  260. if (!allowedLibcodes.includes(item.LIBCODE)) {
  261. return
  262. }
  263. const foundItem = result.find(library => {
  264. // 用nameToLibcodeMap反向查找:library.name对应的LIBCODE === 当前item.LIBCODE
  265. return nameToLibcodeMap[library.name] === item.LIBCODE
  266. })
  267. if (!foundItem) {
  268. return
  269. }
  270. const yearValue = item.JCC_YEAR || 0
  271. const dayValue = item.JCC_DAY || 0
  272. const newObj = {
  273. name: foundItem.name,
  274. JCC_YEAR: yearValue,
  275. JCC_DAY: dayValue
  276. }
  277. newDataArray.push(newObj)
  278. console.log('newDataArray', newDataArray)
  279. })
  280. // 2. 根据JCC_YEAR的值进行降序排序
  281. this.rankingYearData = newDataArray.sort((a, b) => b.JCC_YEAR - a.JCC_YEAR)
  282. // this.rankingYearWithPercentage = this.rankingDataComputed(this.rankingYearData, 'JCC_YEAR')
  283. // 不滚动只显示6条
  284. this.rankingYearWithPercentage = this.rankingDataComputed(this.rankingYearData, 'JCC_YEAR').splice(0, 6)
  285. // 3. 根据JCC_DAY的值进行降序排序
  286. this.rankingTodayData = newDataArray.sort((a, b) => b.JCC_DAY - a.JCC_DAY)
  287. // this.rankingYearWithPercentage = this.rankingDataComputed(this.rankingYearData, 'JCC_YEAR')
  288. // 不滚动只显示6条
  289. this.rankingTodayWithPercentage = this.rankingDataComputed(this.rankingTodayData, 'JCC_DAY').splice(0, 6)
  290. // 不滚动只显示6条
  291. this.rankInterval = setInterval(() => {
  292. this.currentHover = (this.currentHover + 1) % this.rankingYearWithPercentage.length
  293. }, 1000)
  294. }
  295. }).catch(error => {
  296. console.error('Error', error)
  297. })
  298. },
  299. rankingDataComputed(rankingData, numType) {
  300. if (!rankingData || rankingData.length === 0) {
  301. console.log('没有数据')
  302. return []
  303. }
  304. const firstPlaceNum = rankingData[0][numType] // NAN
  305. if (firstPlaceNum === 0) {
  306. // 处理除数为0的情况
  307. console.log('firstPlaceNum为0,不可用于被除')
  308. return rankingData.map(item => {
  309. return { ...item, percentage: 0 } // 直接将 percentage 设置为 0
  310. })
  311. }
  312. return rankingData.map(item => {
  313. const percentage = (item[numType] / firstPlaceNum) * 100
  314. return { ...item, percentage }
  315. })
  316. },
  317. // 今日借还
  318. getTodayJH() {
  319. FetchTodayJH().then(res => {
  320. this.chartDayData = {
  321. timeData: [],
  322. returnData: [],
  323. borrowedData: []
  324. }
  325. const result = res.data
  326. const time = ['07:00', '08:00', '09:00', '10:00', '11:00', '12:00', '13:00', '14:00', '15:00', '16:00', '17:00', '18:00']
  327. time.forEach((hour, index) => {
  328. // 查找 result 中是否有对应的 logHour
  329. const foundItem = result.find(item => item.logHour === index + 7) // 因为 logHour 是从 7 开始,所以需要加上 7
  330. if (foundItem) {
  331. // 如果找到了对应的 logHour,则将数据加入 chartDayData
  332. this.chartDayData.timeData.push(`${foundItem.logHour}:00`)
  333. this.chartDayData.returnData.push(foundItem.hccDay)
  334. this.chartDayData.borrowedData.push(foundItem.jccDay)
  335. } else {
  336. // 如果没找到对应的 logHour,则将默认值加入 chartDayData
  337. this.chartDayData.timeData.push(`${hour}`)
  338. this.chartDayData.returnData.push(0) // 默认值为 0
  339. this.chartDayData.borrowedData.push(0) // 默认值为 0
  340. }
  341. })
  342. }).catch(error => {
  343. console.error('Error', error)
  344. })
  345. },
  346. getWeekJH() {
  347. FetchWeekJH().then(res => {
  348. this.chartWeeklyData = {
  349. date: [],
  350. inchartWeeklyData: [],
  351. outchartWeeklyData: []
  352. }
  353. const result = res.data
  354. console.log('result', result)
  355. // 获取当天日期
  356. const currentDate = new Date()
  357. const today = currentDate.toISOString().slice(0, 10)
  358. // 根据数据排除当天的数据
  359. const filteredData = result.filter(entry => {
  360. const entryDate = new Date(entry.createTime).toISOString().slice(0, 10)
  361. return entryDate !== today
  362. })
  363. // 获取过去一周的
  364. const pastWeekDates = []
  365. for (let i = 1; i <= 7; i++) {
  366. const date = new Date()
  367. date.setDate(currentDate.getDate() - i)
  368. pastWeekDates.push(date.toISOString().slice(0, 10))
  369. }
  370. console.log('filteredData', filteredData)
  371. const matchData = filteredData.reduce((accData, item) => {
  372. // 根据已有的数据获取相关日期
  373. const entryDate = new Date(item.createTime).toISOString().slice(0, 10)
  374. if (accData[entryDate]) {
  375. accData[entryDate].jccDayTotal += item.jccDayTotal
  376. accData[entryDate].hccDayTotal += item.hccDayTotal
  377. } else {
  378. accData[entryDate] = {
  379. jccDayTotal: item.jccDayTotal,
  380. hccDayTotal: item.hccDayTotal
  381. }
  382. }
  383. return accData
  384. }, {})
  385. console.log('matchData', matchData)
  386. const completeData = pastWeekDates.map(date => ({
  387. date: date.split('-').join('/'),
  388. jccDayTotal: matchData[date] ? matchData[date].jccDayTotal : 0,
  389. hccDayTotal: matchData[date] ? matchData[date].hccDayTotal : 0
  390. }))
  391. // 根据时间排序
  392. completeData.sort((a, b) => new Date(a.date) - new Date(b.date))
  393. console.log('completeData', completeData)
  394. // 日期X轴数据
  395. this.chartWeeklyData.date = completeData.map(item => item.date)
  396. // in 归还
  397. this.chartWeeklyData.inchartWeeklyData = completeData.map(item => item.hccDayTotal)
  398. // // out 借出
  399. this.chartWeeklyData.outchartWeeklyData = completeData.map(item => item.jccDayTotal)
  400. console.log('this.chartWeeklyData', this.chartWeeklyData)
  401. }).catch(error => {
  402. console.error('Error', error)
  403. })
  404. }
  405. }
  406. }
  407. </script>
  408. <style lang="scss">
  409. @import "~@/assets/styles/index.scss";
  410. @import "~@/assets/styles/font-some.css";
  411. </style>