Dashboard.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. <script>
  2. import { get } from '../../utils/request'
  3. import * as echarts from 'echarts'
  4. export default {
  5. data () {
  6. return {
  7. overview: {
  8. totalLicenses: null,
  9. assignedLicenses: null,
  10. availableLicenses: null,
  11. activatedDevices: null,
  12. },
  13. productList: [],
  14. overviewProduct: {
  15. totalLicenses: null,
  16. availableLicenses: null,
  17. activatedDevices: null,
  18. validPeriod: null,
  19. expireDate: null,
  20. timeLeft: null
  21. },
  22. dataFilterProductSelect: '',
  23. dataFilterSelectLoading: false,
  24. chartData: {
  25. date: [],
  26. assignedLicensesYData: [],
  27. activatedLicenseYData: []
  28. },
  29. chartSelectValue: '',
  30. chartSelectLoading: false,
  31. teamData: {
  32. totalTeam: null,
  33. totalMember: null,
  34. assignedMember: null
  35. },
  36. teamMemberData: {
  37. teamMember: null,
  38. assignedMember: null,
  39. teamAvailableLicense: null
  40. },
  41. teamList: [],
  42. teamSelect: '',
  43. teamFilterProductSelect: '',
  44. teamSelectLoading: false
  45. }
  46. },
  47. created () {
  48. this.getOverview()
  49. this.getOverviewProduct()
  50. this.getChartStatistics(2)
  51. this.getTeamData()
  52. this.getTeamMemberData()
  53. this.getProductList()
  54. this.getTeamList()
  55. },
  56. mounted () {
  57. this.drawLine()
  58. },
  59. methods: {
  60. // 获取全局预览数据,不区分产品
  61. getOverview () {
  62. get('/pdf-tech/vppDashboard/getOverview').then((res) => {
  63. if (res.data.code === 200) {
  64. this.overview.totalLicenses = res.data.result.totalLicenses
  65. this.overview.assignedLicenses = res.data.result.assignedLicenses
  66. this.overview.availableLicenses = res.data.result.availableLicenses
  67. this.overview.activatedDevices = res.data.result.activatedDevices
  68. }
  69. })
  70. },
  71. // 获取全局预览数据,区分产品
  72. getOverviewProduct () {
  73. if (this.dataFilterSelectLoading) return
  74. this.dataFilterSelectLoading = true
  75. get('/pdf-tech/vppDashboard/getOverviewProduct', {
  76. codeList: this.dataFilterProductSelect
  77. }).then((res) => {
  78. setTimeout(() => {
  79. this.dataFilterSelectLoading = false
  80. }, 1000)
  81. Object.keys(this.overviewProduct).forEach(key => (this.overviewProduct[key] = ''))
  82. if (res.data.code === 200) {
  83. this.overviewProduct.totalLicenses = res.data.result.totalLicenses
  84. this.overviewProduct.availableLicenses = res.data.result.availableLicenses
  85. this.overviewProduct.activatedDevices = res.data.result.activatedDevices
  86. this.overviewProduct.validPeriod = res.data.result.validPeriod
  87. this.overviewProduct.expireDate = res.data.result.expireDate
  88. this.overviewProduct.timeLeft = res.data.result.timeLeft
  89. }
  90. })
  91. },
  92. // 获取图表数据
  93. getChartStatistics (type) {
  94. if (this.chartSelectLoading) return
  95. this.chartSelectLoading = true
  96. if (this.chartSelectValue !== '') {
  97. type = this.chartSelectValue
  98. } else {
  99. type = 2
  100. }
  101. get('/pdf-tech/vppDashboard/getChartStatistics/' + type).then((res) => {
  102. setTimeout(() => {
  103. this.chartSelectLoading = false
  104. }, 1000)
  105. if (res.data.code === 200) {
  106. this.chartData.date = []
  107. this.chartData.assignedLicensesYData = []
  108. this.chartData.activatedLicenseYData = []
  109. res.data.result.forEach((item) => {
  110. this.chartData.date.push(this.formatterDate(item.date))
  111. this.chartData.assignedLicensesYData.push(item.licences.assignedLicenses)
  112. this.chartData.activatedLicenseYData.push(item.licences.activatedLicense)
  113. })
  114. this.drawLine()
  115. } else {
  116. this.$message.error(res.data.msg)
  117. }
  118. })
  119. },
  120. // 获取团队数据
  121. getTeamData () {
  122. get('/pdf-tech/vppDashboard/getTeamData').then((res) => {
  123. if (res.data.code === 200) {
  124. this.teamData.totalTeam = res.data.result.totalTeam
  125. this.teamData.totalMember = res.data.result.totalMember
  126. this.teamData.assignedMember = res.data.result.assignedMember
  127. }
  128. })
  129. },
  130. // 获取团队成员数据
  131. getTeamMemberData () {
  132. if (this.teamSelectLoading) return
  133. this.teamSelectLoading = true
  134. get('/pdf-tech/vppDashboard/getTeamMemberData', {
  135. teamId: this.teamSelect,
  136. codeList: this.teamFilterProductSelect
  137. }).then((res) => {
  138. setTimeout(() => {
  139. this.teamSelectLoading = false
  140. }, 1000)
  141. Object.keys(this.teamMemberData).forEach(key => (this.teamMemberData[key] = ''))
  142. if (res.data.code === 200) {
  143. this.teamMemberData.teamMember = res.data.result.teamMember
  144. this.teamMemberData.assignedMember = res.data.result.assignedMember
  145. this.teamMemberData.teamAvailableLicense = res.data.result.teamAvailableLicense
  146. }
  147. })
  148. },
  149. // 绘制Echarts图表
  150. drawLine () {
  151. let myChart = echarts.getInstanceByDom(
  152. this.$refs.chart
  153. )
  154. if (myChart == null) {
  155. myChart = echarts.init(this.$refs.chart)
  156. }
  157. myChart.setOption({
  158. color: ['#1460F3', '#FFAE49'],
  159. tooltip: {
  160. trigger: 'axis',
  161. backgroundColor: '#F6F7F9',
  162. borderColor: '#D9D9D9',
  163. extraCssText: 'box-shadow: none;'
  164. },
  165. legend: {
  166. right: 0,
  167. top: -30,
  168. itemWidth: 124,
  169. itemHeight: 0,
  170. itemGap: 24,
  171. textStyle: {
  172. color: '#808185',
  173. fontSize: 14,
  174. lineHeight: 14,
  175. padding: 7
  176. },
  177. formatter: '\n\n{name}',
  178. align:'none'
  179. },
  180. grid: {
  181. left: '3%',
  182. right: '4%',
  183. bottom: '3%',
  184. containLabel: true
  185. },
  186. xAxis: {
  187. type: 'category',
  188. boundaryGap: false,
  189. data: this.chartData.date,
  190. axisPointer: {
  191. type: 'line',
  192. lineStyle: {
  193. color: 'rgba(81, 140, 255, 0.16)',
  194. width: 2,
  195. type: 'solid'
  196. }
  197. },
  198. axisTick: {
  199. show: false
  200. },
  201. axisLine: {
  202. lineStyle: {
  203. color: '#D9D9D9'
  204. }
  205. },
  206. axisLabel: {
  207. margin: 10,
  208. color: '#505258'
  209. }
  210. },
  211. yAxis: {
  212. type: 'value',
  213. axisLabel: {
  214. margin: 20,
  215. color: '#505258'
  216. },
  217. splitLine: {
  218. lineStyle: {
  219. color: ['#D9D9D9']
  220. }
  221. }
  222. },
  223. series: [
  224. {
  225. name: 'Assigned Licenses',
  226. type: 'line',
  227. data: this.chartData.assignedLicensesYData,
  228. lineStyle: {
  229. width: 3
  230. },
  231. showSymbol: false,
  232. symbol: 'circle',
  233. symbolSize: 12,
  234. itemStyle: {
  235. borderColor: '#fff',
  236. borderWidth: 4,
  237. shadowBlur: 4,
  238. shadowColor: 'rgba(28, 78, 174, 0.31)'
  239. }
  240. },
  241. {
  242. name: 'Activated Licenses',
  243. type: 'line',
  244. data: this.chartData.activatedLicenseYData,
  245. lineStyle: {
  246. width: 3
  247. },
  248. showSymbol: false,
  249. symbol: 'circle',
  250. symbolSize: 12,
  251. itemStyle: {
  252. borderColor: '#fff',
  253. borderWidth: 4,
  254. shadowBlur: 4,
  255. shadowColor: 'rgba(148, 98, 37, 0.22)'
  256. }
  257. }
  258. ]
  259. }, true)
  260. window.onresize = function () {
  261. myChart.resize()
  262. }
  263. },
  264. // 获取所有产品
  265. getProductList () {
  266. get('/pdf-tech/product/listWithAdmin').then((res) => {
  267. if (res.data.code === 200) {
  268. this.productList = res.data.result
  269. }
  270. })
  271. },
  272. // 获取所有团队
  273. getTeamList() {
  274. get('/pdf-tech/vppTeam/getManageTeamList', {
  275. teamId: '',
  276. keyword: ''
  277. }).then((res) => {
  278. if (res.data.code === 200) {
  279. res.data.result.list.forEach(item => {
  280. this.teamList.push({
  281. label: item.name,
  282. value: item.id
  283. })
  284. })
  285. }
  286. })
  287. },
  288. // 日期自定格式
  289. formatterDate (data) {
  290. if (!data) return ''
  291. const dateArr = data.split('-')
  292. return dateArr[1] + '/' + dateArr[2]
  293. }
  294. }
  295. }
  296. </script>
  297. <template>
  298. <div>
  299. <h1>Dashboard</h1>
  300. <div class="flex justify-between mt-24px mb-32px">
  301. <div class="block flex items-center p-24px basis-full mr-24px">
  302. <img src="@/../static/images/dashboard/total_licenses.png" alt="total_licenses" class="w-48px h-48px mr-16px">
  303. <div>
  304. <p class="text-32px font-700 leading-36px text-[#232A40]">{{ overview.totalLicenses }}</p>
  305. <p class="text-16px font-700 leading-20px text-[#505258]">Total licenses</p>
  306. </div>
  307. </div>
  308. <div class="block flex items-center p-24px basis-full mr-24px">
  309. <img src="@/../static/images/dashboard/assigned_licenses.png" alt="assigned_licenses" class="w-48px h-48px mr-16px">
  310. <div>
  311. <p class="text-32px font-700 leading-36px text-[#232A40]">{{ overview.assignedLicenses }}</p>
  312. <p class="text-16px font-700 leading-20px text-[#505258]">Assigned Licenses</p>
  313. </div>
  314. </div>
  315. <div class="block flex items-center p-24px basis-full mr-24px">
  316. <img src="@/../static/images/dashboard/availqble_licenses.png" alt="availqble_licenses" class="w-48px h-48px mr-16px">
  317. <div>
  318. <p class="text-32px font-700 leading-36px text-[#232A40]">{{ overview.availableLicenses }}</p>
  319. <p class="text-16px font-700 leading-20px text-[#505258]">Available Licenses</p>
  320. </div>
  321. </div>
  322. <div class="block flex items-center p-24px basis-full">
  323. <img src="@/../static/images/dashboard/activated_devices.png" alt="activated_devices" class="w-48px h-48px mr-16px">
  324. <div>
  325. <p class="text-32px font-700 leading-36px text-[#232A40]">{{ overview.activatedDevices }}</p>
  326. <p class="text-16px font-700 leading-20px text-[#505258]">Activated Devices</p>
  327. </div>
  328. </div>
  329. </div>
  330. <h2>Data Filter</h2>
  331. <div class="block p-24px mt-12px mb-32px">
  332. <div class="flex">
  333. <select v-model="dataFilterProductSelect" name="dataFilterProduct" class="min-w-180px mr-16px">
  334. <option value="">Product</option>
  335. <option v-for="item in productList" :key="item.id" :value="item.code">{{ item.name }}</option>
  336. </select>
  337. <div @click="getOverviewProduct" class="w-70px h-28px border-[#1460F3] border-1px rounded-4px px-10px py-4px text-14px leading-20px text-[#1460F3] cursor-pointer">Confirm</div>
  338. </div>
  339. <div class="flex flex-wrap justify-between mt-24px">
  340. <div class="h-56px flex-1 bg-[#F6F7F9] border-[#D9D9D9] border-1px rounded-4px py-18px pl-24px pr-40px flex justify-between items-center mr-24px">
  341. <span class="text-14px font-bold text-[#505258]">Total Licenses</span>
  342. <span class="text-16px font-bold text-[#232A40]">{{ overviewProduct.totalLicenses }}</span>
  343. </div>
  344. <div class="h-56px flex-1 bg-[#F6F7F9] border-[#D9D9D9] border-1px rounded-4px py-18px pl-24px pr-40px flex justify-between items-center mr-24px">
  345. <span class="text-14px font-bold text-[#505258]">Available Licenses</span>
  346. <span class="text-16px font-bold text-[#232A40]">{{ overviewProduct.availableLicenses }}</span>
  347. </div>
  348. <div class="h-56px flex-1 bg-[#F6F7F9] border-[#D9D9D9] border-1px rounded-4px py-18px pl-24px pr-40px flex justify-between items-center">
  349. <span class="text-14px font-bold text-[#505258]">Actived Licenses</span>
  350. <span class="text-16px font-bold text-[#232A40]">{{ overviewProduct.activatedDevices }}</span>
  351. </div>
  352. </div>
  353. <div class="flex flex-wrap justify-between mt-24px">
  354. <div class="h-56px flex-1 bg-[#F6F7F9] border-[#D9D9D9] border-1px rounded-4px py-18px pl-24px pr-40px flex justify-between items-center mr-24px">
  355. <span class="text-14px font-bold text-[#505258]">Valid Period (months)</span>
  356. <span class="text-16px font-bold text-[#232A40]">{{ overviewProduct.validPeriod }}</span>
  357. </div>
  358. <div class="h-56px flex-1 bg-[#F6F7F9] border-[#D9D9D9] border-1px rounded-4px py-18px pl-24px pr-40px flex justify-between items-center mr-24px">
  359. <span class="text-14px font-bold text-[#505258]">Expire date</span>
  360. <span class="text-16px font-bold text-[#232A40]">{{ overviewProduct.expireDate }}</span>
  361. </div>
  362. <div class="h-56px flex-1 bg-[#F6F7F9] border-[#D9D9D9] border-1px rounded-4px py-18px pl-24px pr-40px flex justify-between items-center">
  363. <span class="text-14px font-bold text-[#505258]">Time Left (day)</span>
  364. <span class="text-16px font-bold text-[#232A40]">{{ overviewProduct.timeLeft }}</span>
  365. </div>
  366. </div>
  367. </div>
  368. <h2>Chart Statistics</h2>
  369. <div class="block p-24px mt-12px mb-32px">
  370. <div class="flex">
  371. <div class="flex justify-between">
  372. <select v-model="chartSelectValue" name="date" class="min-w-180px mr-16px">
  373. <option value="" selected disabled>Statistics Time</option>
  374. <option value="1">Today</option>
  375. <option value="2">Last 7 Days</option>
  376. <option value="3">Last 30 Days</option>
  377. <option value="4">This Month</option>
  378. </select>
  379. <div @click="getChartStatistics()" class="w-70px h-28px border-[#1460F3] border-1px rounded-4px px-10px py-4px text-14px leading-20px text-[#1460F3] cursor-pointer">Confirm</div>
  380. </div>
  381. <div></div>
  382. </div>
  383. <div class="w-[100%] h-320px" ref="chart"></div>
  384. </div>
  385. <h2>Team Data</h2>
  386. <div class="flex justify-between mt-12px">
  387. <div class="block py-24px flex-auto mr-24px text-center">
  388. <div class="relative inline-block w-96px h-96px inline-flex items-center justify-center mb-12px">
  389. <img src="@/../static/images/dashboard/team_data_blue.png" class="w-96px h-96px absolute top-0 left-0">
  390. <p class="text-32px text-[#1460F3] leading-36px font-700">{{ teamData.totalTeam }}</p>
  391. </div>
  392. <p class="text-16px leading-20px font-700 text-[#505258]">Total Team</p>
  393. </div>
  394. <div class="block py-24px flex-auto mr-24px text-center">
  395. <div class="relative inline-block w-96px h-96px inline-flex items-center justify-center mb-12px">
  396. <img src="@/../static/images/dashboard/team_data_yellow.png" class="w-96px h-96px absolute top-0 left-0">
  397. <p class="text-32px text-[#FFAE49] leading-36px font-700">{{ teamData.totalMember }}</p>
  398. </div>
  399. <p class="text-16px leading-20px font-700 text-[#505258]">Total Member</p>
  400. </div>
  401. <div class="block py-24px flex-auto text-center">
  402. <div class="relative inline-block w-96px h-96px inline-flex items-center justify-center mb-12px">
  403. <img src="@/../static/images/dashboard/team_data_purple.png" class="w-96px h-96px absolute top-0 left-0">
  404. <p class="text-32px text-[#664FF5] leading-36px font-700">{{ teamData.assignedMember }}</p>
  405. </div>
  406. <p class="text-16px leading-20px font-700 text-[#505258]">Assigned Member</p>
  407. </div>
  408. </div>
  409. <div class="block p-24px mt-24px mb-32px">
  410. <div class="flex">
  411. <select v-model="teamSelect" name="team" class="min-w-140px mr-16px">
  412. <option value="">Team</option>
  413. <option v-for="item in teamList" :key="item.value" :value="item.value">{{ item.label }}</option>
  414. </select>
  415. <select v-model="teamFilterProductSelect" name="teamFilterProduct" class="min-w-180px mr-16px">
  416. <option value="">Product</option>
  417. <option v-for="item in productList" :key="item.id" :value="item.code">{{ item.name }}</option>
  418. </select>
  419. <div @click="getTeamMemberData" class="w-70px h-28px border-[#1460F3] border-1px rounded-4px px-10px py-4px text-14px leading-20px text-[#1460F3] cursor-pointer">Confirm</div>
  420. </div>
  421. <div class="flex flex-wrap justify-between mt-24px">
  422. <div class="h-56px bg-[#F6F7F9] border-[#D9D9D9] border-1px rounded-4px py-18px pl-24px pr-40px flex-auto flex justify-between items-center mr-24px">
  423. <span class="text-14px font-bold text-[#505258]">Team Member</span>
  424. <span class="text-16px font-bold text-[#232A40]">{{ teamMemberData.teamMember }}</span>
  425. </div>
  426. <div class="h-56px bg-[#F6F7F9] border-[#D9D9D9] border-1px rounded-4px py-18px pl-24px pr-40px flex-auto flex justify-between items-center mr-24px">
  427. <span class="text-14px font-bold text-[#505258]">Assigned Member</span>
  428. <span class="text-16px font-bold text-[#232A40]">{{ teamMemberData.assignedMember }}</span>
  429. </div>
  430. <div class="h-56px bg-[#F6F7F9] border-[#D9D9D9] border-1px rounded-4px py-18px pl-24px pr-40px flex-auto flex justify-between items-center">
  431. <span class="text-14px font-bold text-[#505258]">Team Available License</span>
  432. <span class="text-16px font-bold text-[#232A40]">{{ teamMemberData.teamAvailableLicense }}</span>
  433. </div>
  434. </div>
  435. </div>
  436. </div>
  437. </template>
  438. <style lang="scss" scoped>
  439. </style>