index.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. <template>
  2. <div style="height:100vh; min-height:1080px;">
  3. <!-- 头部 -->
  4. <div class="header">
  5. <h1 style="color: #77F8FF;">惠州市就业驿站大数据</h1>
  6. <div class="time">{{ formattedTime }}</div>
  7. </div>
  8. <!-- 内容区 -->
  9. <div class="body-content">
  10. <!-- 左 -->
  11. <div class="side" style="padding-left: 20px;">
  12. <div class="content-box">
  13. <div class="box-title">驿站运行情况</div>
  14. <div class="chart-box" id="yearSystemApplyBox"></div>
  15. </div>
  16. <div class="content-box">
  17. <div class="box-title">就业情况</div>
  18. <div class="chart-box" id="employedCountBox"></div>
  19. </div>
  20. <div class="content-box">
  21. <div class="box-title">区县就业困难人员</div>
  22. <div class="chart-box" id="ordinaryDifficultyCountBox"></div>
  23. </div>
  24. </div>
  25. <!-- 中 -->
  26. <div class="center">
  27. <div class="center-1">
  28. <div class="nav">
  29. <div class="nav-items nav-active">
  30. <div class="nav-1"></div>
  31. <h2 style="color: #77F8FF;">总体概况</h2></div>
  32. <div class="nav-items" @click="goCompany">
  33. <div class="nav-2"></div>
  34. <h2 style="color: #77F8FF;">企业情况</h2></div>
  35. <div class="nav-items" @click="goJobUser">
  36. <div class="nav-3"></div>
  37. <h2 style="color: #77F8FF;">求职情况</h2></div>
  38. <div class="nav-items">
  39. <div class="nav-4"></div>
  40. <h2 style="color: #77F8FF;">服务情况</h2></div>
  41. </div>
  42. <div class="s-box">
  43. <div class="statistics t-1">
  44. <div style="margin: 8px 0 0 18px; position: revert;">
  45. <div class="s-title">岗位数</div>
  46. <div class="s-number">{{ allSystemDataCountList.count.postCount }}</div>
  47. <div class="waves" style="right: -187px; top: 42px"></div>
  48. </div>
  49. </div>
  50. <div class="statistics t-2">
  51. <div style="margin: 8px 0 0 78px; position: revert;">
  52. <div class="s-title">企业数</div>
  53. <div class="s-number">{{ allSystemDataCountList.count.companyCount }}</div>
  54. <div class="waves" style="left: -86px; top: 42px"></div>
  55. </div>
  56. </div>
  57. <div class="statistics t-3">
  58. <div style="margin: 78px 0 0 98px; position: revert;">
  59. <div class="s-title">求职人员数</div>
  60. <div class="s-number">{{ allSystemDataCountList.count.jobUserCount }}</div>
  61. <div class="waves" style="left: -106px; top: -141px"></div>
  62. </div>
  63. </div>
  64. </div>
  65. </div>
  66. <div class="center-2">
  67. <div class="box-bigtitle">全市情况一览</div>
  68. <div class="chart-box" id="allSystemDatBox"></div>
  69. </div>
  70. </div>
  71. <!-- 右 -->
  72. <div class="side" style="padding-right: 20px;">
  73. <div class="content-box">
  74. <div class="box-title">区县服务榜</div>
  75. <div class="chart-box">
  76. <div class="tab-content" style="margin-bottom: 40px;">
  77. <div class="tab-item" :class="{'tab-active': regionTabAct == 'all'}" @click="changeRegionTab('all')">
  78. 总榜
  79. </div>
  80. <div class="tab-item" :class="{'tab-active': regionTabAct == 'month'}" @click="changeRegionTab('month')">
  81. 月榜
  82. </div>
  83. <div class="tab-item" :class="{'tab-active': regionTabAct == 'week'}" @click="changeRegionTab('week')">
  84. 周榜
  85. </div>
  86. </div>
  87. <div class="ranking-1">
  88. <div class="ranking-1-item NO2">
  89. <div class="ranking-1-item-name">{{ regionServiceData.second.regionName }}</div>
  90. <div class="ranking-1-item-number">{{ regionServiceData.second.count }}</div>
  91. </div>
  92. <div class="ranking-1-item NO1">
  93. <div class="ranking-1-item-name">{{ regionServiceData.first.regionName }}</div>
  94. <div class="ranking-1-item-number">{{ regionServiceData.first.count }}</div>
  95. </div>
  96. <div class="ranking-1-item NO3">
  97. <div class="ranking-1-item-name">{{ regionServiceData.third.regionName }}</div>
  98. <div class="ranking-1-item-number">{{ regionServiceData.third.count }}</div>
  99. </div>
  100. </div>
  101. </div>
  102. </div>
  103. <div class="content-box">
  104. <div class="box-title">驿站服务榜</div>
  105. <div class="chart-box">
  106. <div class="tab-content">
  107. <div class="tab-item" :class="{'tab-active': siteTabAct == 'all'}" @click="changeSiteTab('all')">总榜
  108. </div>
  109. <div class="tab-item" :class="{'tab-active': siteTabAct == 'month'}" @click="changeSiteTab('month')">月榜
  110. </div>
  111. <div class="tab-item" :class="{'tab-active': siteTabAct == 'week'}" @click="changeSiteTab('week')">周榜
  112. </div>
  113. </div>
  114. <div class="ranking-2">
  115. <div class="ranking-2-item">
  116. <div class="ranking-number">1</div>
  117. <div class="ranking-column" style="width:60%;">
  118. {{ siteServiceData[0] ? siteServiceData[0].count : '' }}
  119. </div>
  120. <div class="ranking-name">{{ siteServiceData[0] ? siteServiceData[0].siteName : '' }}</div>
  121. </div>
  122. <div class="ranking-2-item">
  123. <div class="ranking-number">2</div>
  124. <div class="ranking-column" style="width:50%;">
  125. {{ siteServiceData[1] ? siteServiceData[1].count : '' }}
  126. </div>
  127. <div class="ranking-name">{{ siteServiceData[1] ? siteServiceData[1].siteName : '' }}</div>
  128. </div>
  129. <div class="ranking-2-item">
  130. <div class="ranking-number">3</div>
  131. <div class="ranking-column" style="width:40%;">
  132. {{ siteServiceData[2] ? siteServiceData[2].count : '' }}
  133. </div>
  134. <div class="ranking-name">{{ siteServiceData[2] ? siteServiceData[2].siteName : '' }}</div>
  135. </div>
  136. <div class="ranking-2-item">
  137. <div class="ranking-number">4</div>
  138. <div class="ranking-column" style="width:30%;">
  139. {{ siteServiceData[3] ? siteServiceData[3].count : '' }}
  140. </div>
  141. <div class="ranking-name">{{ siteServiceData[3] ? siteServiceData[3].siteName : '' }}</div>
  142. </div>
  143. <div class="ranking-2-item">
  144. <div class="ranking-number">5</div>
  145. <div class="ranking-column" style="width:20%;">
  146. {{ siteServiceData[4] ? siteServiceData[4].count : '' }}
  147. </div>
  148. <div class="ranking-name">{{ siteServiceData[4] ? siteServiceData[4].siteName : '' }}</div>
  149. </div>
  150. </div>
  151. </div>
  152. </div>
  153. <div class="content-box">
  154. <div class="box-title">驿站实时服务</div>
  155. <div class="chart-box">
  156. <div class="text-list">
  157. <div class="text-list-item" v-for="(item, key) in systemServiceList" :key="key">
  158. <div class="list-left">{{ item.serviceContent }}</div>
  159. <div class="list-right">{{ dayjs(item.serviceTime).format("MM-DD HH:mm:ss") }}</div>
  160. </div>
  161. </div>
  162. <div class="text-list">
  163. <div class="text-list-item" v-for="(item, key) in systemServiceList" :key="key">
  164. <div class="list-left">{{ item.serviceContent }}</div>
  165. <div class="list-right">{{ dayjs(item.serviceTime).format("MM-DD HH:mm:ss") }}</div>
  166. </div>
  167. </div>
  168. </div>
  169. </div>
  170. </div>
  171. </div>
  172. </div>
  173. </template>
  174. <script setup lang="ts">
  175. import {
  176. getEmployedJobUserCount,
  177. getJobUserByRegionAndDifficulty,
  178. getSystemApplyCountBySite,
  179. getYearSystemDataCount
  180. } from "@/api/statistics";
  181. import {computed, onBeforeUnmount, onMounted, reactive, ref} from "vue";
  182. import {
  183. initDataSetBarImageTable,
  184. initLineImageTable,
  185. initRingPieImageTable,
  186. PieColorData
  187. } from "@/views/dataScreen/echarts";
  188. import dayjs from "dayjs";
  189. import weekOfYear from 'dayjs/plugin/weekOfYear';
  190. import weekday from 'dayjs/plugin/weekday';
  191. import {getSystemServiceList} from "@/api/jobUserManager/jobuser/jobUserService";
  192. import {useRouter} from "vue-router";
  193. dayjs.extend(weekOfYear);
  194. dayjs.extend(weekday);
  195. const router = useRouter();
  196. // 查询参数
  197. const searchParams = reactive({
  198. monthStartDate: "",
  199. monthEndDate: "",
  200. weekStartDate: "",
  201. weekEndDate: "",
  202. })
  203. // 系统年度使用情况
  204. const yearSystemDataCountList = ref([]);
  205. // 全市数据情况
  206. const allSystemDataCountList = ref({
  207. count: {
  208. companyCount: 0,
  209. postCount: 0,
  210. jobUserCount: 0
  211. },
  212. list: []
  213. });
  214. // 普通求职者与就业困难人员
  215. const ordinaryDifficultyUser = ref([]);
  216. // 已就业人数
  217. const employedData = ref({
  218. count: 0,
  219. list: []
  220. })
  221. // 区县榜当前显示tab
  222. const regionTabAct = ref("all");
  223. // 区县服务榜数据
  224. const regionServiceData = reactive({
  225. first: {
  226. regionName: "",
  227. count: 0,
  228. },
  229. second: {
  230. regionName: "",
  231. count: 0,
  232. },
  233. third: {
  234. regionName: "",
  235. count: 0,
  236. }
  237. });
  238. // 驿站榜当前显示tab
  239. const siteTabAct = ref("all");
  240. // 驿站服务榜数据
  241. const siteServiceData = ref<Array<any>>([]);
  242. // 系统服务记录信息
  243. const systemServiceList = ref<Array<any>>([]);
  244. // 实时时间
  245. const currentTime = ref(new Date());
  246. const formattedTime = computed(() => {
  247. const days = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
  248. const year = currentTime.value.getFullYear();
  249. const month = (currentTime.value.getMonth() + 1).toString().padStart(2, '0');
  250. const date = currentTime.value.getDate().toString().padStart(2, '0');
  251. const day = days[currentTime.value.getDay()];
  252. const hours = currentTime.value.getHours().toString().padStart(2, '0');
  253. const minutes = currentTime.value.getMinutes().toString().padStart(2, '0');
  254. // const seconds = currentTime.value.getSeconds().toString().padStart(2, '0');
  255. return `${year}-${month}-${date} ${day} ${hours}:${minutes}`;
  256. });
  257. // 获取年度使用数据
  258. function loadYearData() {
  259. const currentYear = new Date().getFullYear();
  260. getYearSystemDataCount({year: currentYear}).then((result: any) => {
  261. yearSystemDataCountList.value = result;
  262. let regionNameList = new Array<any>();
  263. let yearNameList = new Array<any>();
  264. // 获取到区县名称信息
  265. if (yearSystemDataCountList.value && Object.keys(yearSystemDataCountList.value).length > 0) {
  266. // 获取到查询结果Map中的第一个键值对,解析获取到县区信息,填充进初始数组中
  267. yearSystemDataCountList.value[Object.keys(yearSystemDataCountList.value)[0]].forEach((item: any) => {
  268. if (item.regionCode != 100) {
  269. regionNameList.push(item.regionName);
  270. }
  271. });
  272. }
  273. // 初始化折线图数据
  274. let yearLineData = [
  275. {
  276. name: '驿站人员',
  277. type: 'line',
  278. data: new Array<any>(),
  279. symbol: 'circle',
  280. itemStyle: {
  281. color: '#f6b400'
  282. }
  283. },
  284. {
  285. name: '企业数量',
  286. type: 'line',
  287. data: new Array<any>(),
  288. symbol: 'circle',
  289. itemStyle: {
  290. color: "#006efe"
  291. }
  292. },
  293. {
  294. name: '岗位数量',
  295. type: 'line',
  296. data: new Array<any>(),
  297. symbol: 'circle',
  298. itemStyle: {
  299. color: "#6cd300"
  300. }
  301. },
  302. {
  303. name: '求职人数',
  304. type: 'line',
  305. data: new Array<any>(),
  306. symbol: 'circle',
  307. itemStyle: {
  308. color: "#76f7fe"
  309. }
  310. },
  311. ]
  312. // 解析1到12月的统计数据
  313. for (let i = 1; i <= 12; i++) {
  314. if (yearSystemDataCountList.value[i + '月']) {
  315. yearNameList.push(i + '月');
  316. // 查询获取到每周的合计总数,填充进折线图数据中
  317. const hjData = yearSystemDataCountList.value[i + '月'].find(item => item.regionCode == '100');
  318. if (hjData) {
  319. yearLineData[0].data.push(hjData.siteUserCount);
  320. yearLineData[1].data.push(hjData.companyCount);
  321. yearLineData[2].data.push(hjData.postCount);
  322. yearLineData[3].data.push(hjData.jobUserCount);
  323. }
  324. }
  325. }
  326. // 初始化图表
  327. initLineImageTable(yearNameList, yearLineData, ["驿站人员", "企业数量", "岗位数量", "求职人数"], "yearSystemApplyBox");
  328. })
  329. }
  330. // 获取已就业人数
  331. function loadEmployedUser() {
  332. getEmployedJobUserCount().then((result: any) => {
  333. employedData.value.list = result;
  334. let arr = new Array<any>();
  335. result.forEach((item: any) => {
  336. if (item.regionName != "市本级") {
  337. employedData.value.count += item.jobUserCount;
  338. let data = {
  339. value: item.jobUserCount,
  340. name: item.regionName,
  341. itemStyle: {
  342. color: PieColorData[item.regionName]
  343. }
  344. };
  345. arr.push(data);
  346. }
  347. })
  348. // 设置中间的文本
  349. const graphicChildren = [
  350. {
  351. type: 'text',
  352. left: 'center',
  353. top: '43%',
  354. style: {
  355. fill: 'rgba(119,248,255,0.7)',
  356. text: '已就业人数',
  357. font: 'bold 12px Arial',
  358. textAlign: 'center'
  359. }
  360. },
  361. {
  362. type: 'text',
  363. left: 'center',
  364. top: '53%',
  365. style: {
  366. fill: '#77F8FF',
  367. text: employedData.value.count,
  368. font: 'bold 16px Arial',
  369. textAlign: 'center'
  370. }
  371. }
  372. ]
  373. // 生成图表
  374. initRingPieImageTable(arr, graphicChildren, "employedCountBox", "已就业人数", 10);
  375. })
  376. }
  377. // 获取区县普通求职人员与就业困难人员
  378. function loadDifficultyUser() {
  379. getJobUserByRegionAndDifficulty({}).then((result: any) => {
  380. // 保存原始数据
  381. ordinaryDifficultyUser.value = result;
  382. let arr: any[] = [];
  383. arr.push(['类型', '失业人数', '就业困难人数'])
  384. result.forEach((item: any) => {
  385. if (item.regionName != "市本级") {
  386. arr.push([item.regionName, item.jobUserCount, item.difficultyCount]);
  387. }
  388. })
  389. initDataSetBarImageTable(arr, [{type: 'bar', barMaxWidth: '10px', color: "#0062cc"}, {
  390. type: 'bar',
  391. barMaxWidth: '10px',
  392. color: '#73ecf3'
  393. }], 'ordinaryDifficultyCountBox', 3)
  394. })
  395. }
  396. // 获取年度使用数据
  397. function loadAllData() {
  398. getYearSystemDataCount({}).then((result: any) => {
  399. allSystemDataCountList.value.list = result['汇总'];
  400. allSystemDataCountList.value.count = result['汇总'].filter(item => item.regionCode == '100')[0];
  401. let arr = new Array<any>();
  402. arr.push(['类型', '企业数', '岗位数', "求职人员数"]);
  403. result['汇总'].forEach((item: any) => {
  404. if (item.regionName != '合计' && item.regionName != '市本级') {
  405. arr.push([item.regionName, item.companyCount, item.postCount, item.jobUserCount]);
  406. }
  407. })
  408. initDataSetBarImageTable(arr,
  409. [
  410. {type: 'bar', barMaxWidth: '15px', color: "#0062cc"},
  411. {type: 'bar', barMaxWidth: '15px', color: '#73ecf3'},
  412. {type: 'bar', barMaxWidth: '15px', color: '#67ca00'},
  413. ], 'allSystemDatBox', 6)
  414. })
  415. }
  416. // 查询区县服务榜
  417. function loadRegionTop(params: any) {
  418. getYearSystemDataCount(params).then((result: any) => {
  419. let countMap: { [key: string]: number } = {}
  420. result['汇总'].forEach((item: any) => {
  421. if (item.regionName != '市本级' && item.regionName != '合计') {
  422. countMap[item.regionName] = item.companyCount + item.postCount + item.jobUserCount;
  423. }
  424. })
  425. // 按相加结果的大小进行排序,分别获取前三名
  426. const topThreeRegions = Object.entries(countMap)
  427. .sort((a, b) => b[1] - a[1])
  428. .slice(0, 3);
  429. // 保存到regionServiceData变量中
  430. if (topThreeRegions.length > 0) {
  431. regionServiceData.first.regionName = topThreeRegions[0][0];
  432. regionServiceData.first.count = topThreeRegions[0][1];
  433. }
  434. if (topThreeRegions.length > 1) {
  435. regionServiceData.second.regionName = topThreeRegions[1][0];
  436. regionServiceData.second.count = topThreeRegions[1][1];
  437. }
  438. if (topThreeRegions.length > 2) {
  439. regionServiceData.third.regionName = topThreeRegions[2][0];
  440. regionServiceData.third.count = topThreeRegions[2][1];
  441. }
  442. })
  443. }
  444. // 改变区县服务榜展示的tab
  445. function changeRegionTab(value: any) {
  446. regionTabAct.value = value;
  447. if (value == 'all') {
  448. // 查询总榜
  449. loadRegionTop({});
  450. }
  451. if (value == 'month') {
  452. // 查询月榜
  453. loadRegionTop({startDate: searchParams.monthStartDate, endDate: searchParams.monthEndDate});
  454. }
  455. if (value == 'week') {
  456. // 查询周榜
  457. loadRegionTop({startDate: searchParams.weekStartDate, endDate: searchParams.weekEndDate});
  458. }
  459. }
  460. // 查询驿站服务榜
  461. function loadSiteTop(params: any) {
  462. getSystemApplyCountBySite(params).then((result: any) => {
  463. let countMap: { [key: string]: number } = {}
  464. result.forEach((item: any) => {
  465. if (item.regionName != '市本级' && item.siteName != '惠州市就业驿站') {
  466. countMap[item.siteName] = item.companyCount + item.postCount + item.jobUserCount;
  467. }
  468. })
  469. siteServiceData.value = Object.entries(countMap)
  470. .sort((a, b) => b[1] - a[1])
  471. .slice(0, 5)
  472. .map(entry => ({siteName: entry[0], count: entry[1]}));
  473. })
  474. }
  475. // 改变驿站服务榜展示的tab
  476. function changeSiteTab(value: any) {
  477. siteTabAct.value = value;
  478. if (value == 'all') {
  479. loadSiteTop({});
  480. }
  481. if (value == 'month') {
  482. // 查询月榜
  483. loadSiteTop({startDate: searchParams.monthStartDate, endDate: searchParams.monthEndDate});
  484. }
  485. if (value == "week") {
  486. // 查询周榜
  487. loadSiteTop({startDate: searchParams.weekStartDate, endDate: searchParams.weekEndDate})
  488. }
  489. }
  490. // 加载服务记录
  491. function loadSystemService() {
  492. getSystemServiceList().then((result) => {
  493. systemServiceList.value = result;
  494. })
  495. }
  496. function updateTime() {
  497. currentTime.value = new Date();
  498. }
  499. // 跳转企业面板
  500. function goCompany() {
  501. router.push({name: "dataScreenCompany"})
  502. }
  503. // 跳转求职人员面板
  504. function goJobUser() {
  505. router.push({name: "dataScreenJobUser"})
  506. }
  507. onMounted(() => {
  508. const now = dayjs();
  509. searchParams.monthStartDate = now.startOf('month').format('YYYY-MM-DD');
  510. searchParams.monthEndDate = now.endOf('month').format('YYYY-MM-DD');
  511. searchParams.weekStartDate = now.startOf('week').weekday(1).format('YYYY-MM-DD');
  512. searchParams.weekEndDate = now.endOf('week').weekday(7).format('YYYY-MM-DD');
  513. loadYearData();
  514. loadDifficultyUser();
  515. loadEmployedUser();
  516. loadAllData();
  517. setInterval(loadAllData, 1000 * 60 * 5)
  518. changeRegionTab("all");
  519. changeSiteTab("all");
  520. loadSystemService();
  521. setInterval(loadSystemService, 1000 * 60 * 5);
  522. updateTime();
  523. const timer = setInterval(updateTime, 1000);
  524. onBeforeUnmount(() => {
  525. clearInterval(timer);
  526. });
  527. })
  528. </script>
  529. <style scoped>
  530. @import url('@/views/dataScreen/html/css/reset.css');
  531. @import url('@/views/dataScreen/html/css/style.css');
  532. </style>