InterfaceEveryday.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. <template>
  2. <div class="spatial-analysis-statistic">
  3. <div class="title">
  4. <span>{{ title }}</span>
  5. <span class="statistic">
  6. <span class="label">总次数: </span>
  7. <span class="value">{{ allTimes }}</span>
  8. <span :class="(activeBtn === 1 ? 'active' : '') + ' btn'" @click="selectType(1)">按月</span>
  9. <span :class="(activeBtn === 2 ? 'active' : '') + ' btn'" @click="selectType(2)">按年</span>
  10. <span class="select-div">
  11. <a-month-picker
  12. v-if="activeBtn === 1"
  13. v-model:value="month"
  14. format="YYYY-MM"
  15. :disabled-date="disabledDate"
  16. size="small"
  17. style="width: 90px"
  18. placeholder="选择月份"
  19. @change="dataChange"
  20. />
  21. <a-date-picker
  22. v-if="activeBtn === 2"
  23. v-model:value="year"
  24. mode="year"
  25. format="YYYY"
  26. :disabled-date="disabledYear"
  27. size="small"
  28. style="width: 90px"
  29. placeholder="请选择"
  30. :open="yearShow"
  31. @openChange="openChange"
  32. @panelChange="panelChange"
  33. @pressEnter="handleSaveOk()"
  34. @change="dataChange"
  35. />
  36. </span>
  37. </span>
  38. </div>
  39. <div class="echart-container" id="defect-column" ref="domRef"></div>
  40. </div>
  41. </template>
  42. <script>
  43. import {
  44. defineComponent,
  45. reactive,
  46. toRefs,
  47. onMounted,
  48. ref,
  49. watch,
  50. getCurrentInstance,
  51. shallowRef,
  52. onUnmounted,
  53. } from 'vue';
  54. import moment from 'moment';
  55. import Moment from 'moment';
  56. import { queryApiUseCountDays, queryIserverUseCountByType } from '/@/api/interface/interface';
  57. const props = {
  58. type: {
  59. type: Object,
  60. },
  61. };
  62. export default defineComponent({
  63. name: 'InterfaceEveryday',
  64. components: {},
  65. props,
  66. setup(props) {
  67. const data = reactive({
  68. title: '空间服务支撑访问统计',
  69. interval: null,
  70. allTimes: 0,
  71. activeBtn: 1,
  72. month: moment().format('YYYY-MM'),
  73. year: moment().format('YYYY'),
  74. yearShow: false,
  75. timer: null,
  76. loading: false,
  77. });
  78. const domRef = ref(null);
  79. const { proxy } = getCurrentInstance();
  80. const echarts = proxy.$echarts;
  81. const mychart = shallowRef(null);
  82. const disabledDate = (current) => {
  83. // Can not select days before today and today
  84. return current && current > moment().endOf('day');
  85. };
  86. const disabledYear = (current) => {
  87. return current && current > moment().endOf('year');
  88. };
  89. const dataChange = () => {
  90. queryData();
  91. };
  92. /**
  93. * 查询统计数据
  94. */
  95. const queryData = async () => {
  96. let xAxisData = [],
  97. seriesData = [];
  98. // const res = await queryApiUseCountDays();
  99. // if (res.dateArr) {
  100. // res.dateArr.map((item) => {
  101. // const Arr = item.split('-');
  102. // xAxisData.push(`${Arr[1]}/${Arr[2]}`);
  103. // });
  104. // res.list.map((item) => {
  105. // seriesData.push(parseInt(item));
  106. // });
  107. // }
  108. data.loading = true;
  109. let params = null;
  110. //生成查询条件
  111. if (data.activeBtn === 1) {
  112. //月类型统计
  113. params = {
  114. startCreateTimeStr: moment(data.month).startOf('months').format('YYYY-MM-DD'), //获取当月的一号
  115. endCreateTimeStr: moment(data.month).endOf('months').format('YYYY-MM-DD'), //获取当月的最后一天
  116. tjType: data.activeBtn,
  117. };
  118. } else {
  119. //年类型统计
  120. params = {
  121. startCreateTimeStr: moment(data.year + '-01-01')
  122. .startOf('year')
  123. .format('YYYY-MM-DD'), //获取年初第一天
  124. endCreateTimeStr: moment(data.year + '-01-01')
  125. .endOf('year')
  126. .format('YYYY-MM-DD'), //获取年末最后一天
  127. tjType: data.activeBtn,
  128. };
  129. }
  130. data.allTimes = 0;
  131. if (!params) return;
  132. const res = await queryIserverUseCountByType(params);
  133. data.loading = false;
  134. if (res) {
  135. //如果是月类型统计,生成所有日期
  136. if (data.activeBtn === 1) {
  137. for (
  138. let t = params.startCreateTimeStr;
  139. moment(params.endCreateTimeStr).diff(moment(t), 'days') > 0;
  140. t = moment(t).add(1, 'days').format('YYYY-MM-DD')
  141. ) {
  142. //如果日期大于当前日期,跳过
  143. xAxisData.push(moment(t).format('MM/DD'));
  144. if (res.length === 0) seriesData.push(0);
  145. else {
  146. const obj = res.find(
  147. (item) => item['STATISTICS_START_TIME'] === moment(t).format(YYYYMMDD)
  148. );
  149. seriesData.push(obj ? parseInt(obj['SUM(COUNT)']) : 0);
  150. }
  151. }
  152. } else {
  153. for (
  154. let t = moment(params.startCreateTimeStr).format('YYYY-MM');
  155. moment(params.endCreateTimeStr).diff(moment(t), 'months') > 0;
  156. t = moment(t).add(1, 'months').format('YYYY-MM')
  157. ) {
  158. //如果日期大于当前日期,跳过
  159. xAxisData.push(parseInt(moment(t).format('MM')) + '月');
  160. if (res.length === 0) seriesData.push(0);
  161. else {
  162. const obj = res.find(
  163. (item) => item['STATISTICS_START_TIME'] === moment(t).format(YYYYMM)
  164. );
  165. seriesData.push(obj ? parseInt(obj['SUM(COUNT)']) : 0);
  166. }
  167. }
  168. }
  169. let allTimes = 0;
  170. res.map((item) => {
  171. allTimes += parseInt(item['SUM(COUNT)']);
  172. });
  173. data.allTimes = allTimes;
  174. }
  175. if (seriesData.length < 1 || xAxisData.length < 1) return;
  176. const option = getOption(seriesData, xAxisData);
  177. mychart.value.setOption(option, true);
  178. };
  179. const setEcharts = (option) => {
  180. if (mychart.value) mychart.value.clear();
  181. mychart.value = echarts.init(domRef.value);
  182. //const option = getOption(seriesData,xAxisData);
  183. window.onresize = () => {
  184. mychart.value.resize();
  185. };
  186. };
  187. const selectType = (type) => {
  188. data.activeBtn = type;
  189. queryData();
  190. };
  191. const getOption = (seriesData, xAxisData) => {
  192. //const seriesData = [60, 52, 200, 334, 390, 330, 220, 200, 334, 390, 330, 220];
  193. const maxValue = Math.max.apply(null, seriesData);
  194. //const xAxisData = ['09/01','09/02','09/03','09/04', '09/05','09/06','09/07','09/08','09/09','09/10','09/11','09/12'];
  195. const colorList = [
  196. {
  197. type: 'linear',
  198. x: 0,
  199. y: 0,
  200. x2: 0,
  201. y2: 1,
  202. colorStops: [
  203. {
  204. offset: 0,
  205. color: 'rgba(6,113,221,1)', // 0% 处的颜色
  206. },
  207. {
  208. offset: 0.5,
  209. color: 'rgba(6,113,221,0.9)', // 0% 处的颜色
  210. },
  211. {
  212. offset: 1,
  213. color: 'rgba(6,113,221,0)', // 100% 处的颜色
  214. },
  215. ],
  216. global: false, // 缺省为 false
  217. },
  218. {
  219. type: 'linear',
  220. x: 0,
  221. y: 0,
  222. x2: 0,
  223. y2: 1,
  224. colorStops: [
  225. {
  226. offset: 0,
  227. color: 'rgba(237,172,75,1)', // 0% 处的颜色
  228. },
  229. {
  230. offset: 0.5,
  231. color: 'rgba(237,172,75,0.9)', // 0% 处的颜色
  232. },
  233. {
  234. offset: 1,
  235. color: 'rgba(237,172,75,0.2)', // 100% 处的颜色 'rgba(6,113,221,0.2)'
  236. },
  237. ],
  238. global: false, // 缺省为 false
  239. },
  240. ];
  241. return {
  242. tooltip: {
  243. trigger: 'axis',
  244. axisPointer: {
  245. type: 'none', // 'shadow',
  246. },
  247. formatter: (params) => {
  248. if (data.activeBtn === 1) {
  249. const names = params[0].name.split('/');
  250. const nameLable = `${parseInt(names[0])}月${parseInt(names[1])}`;
  251. return nameLable + ': ' + params[0].value + '次';
  252. } else return params[0].name + '月: ' + params[0].value + '次';
  253. },
  254. },
  255. grid: {
  256. top: '10%',
  257. left: '1%',
  258. right: '1%',
  259. bottom: '1%',
  260. containLabel: true,
  261. },
  262. xAxis: [
  263. {
  264. data: xAxisData,
  265. axisTick: { show: false },
  266. axisLine: { show: false },
  267. axisLabel: {
  268. color: '#000',
  269. },
  270. axisLine: {
  271. show: true,
  272. lineStyle: {
  273. color: 'rgba(222, 222, 222, 1)',
  274. },
  275. },
  276. },
  277. ],
  278. yAxis: {
  279. splitLine: { show: false },
  280. axisTick: { show: false },
  281. axisLine: { show: false },
  282. axisLabel: { show: true },
  283. minInterval: 1,
  284. },
  285. series: [
  286. {
  287. name: '调用次数',
  288. type: 'bar',
  289. barWidth: '12',
  290. data: seriesData, //[60, 52, 200, 334, 390, 330, 220, 200, 334, 390, 330, 220],
  291. itemStyle: {
  292. // 柱形图圆角,鼠标移上去效果,如果只是一个数字则说明四个参数全部设置为那么多
  293. normal: {
  294. // 柱形图圆角,初始化效果
  295. borderRadius: [15, 15, 0, 0],
  296. color: (params) => {
  297. let color = colorList[0];
  298. if (params.data === maxValue) color = colorList[1];
  299. return color;
  300. },
  301. },
  302. },
  303. barGap: '0%',
  304. },
  305. ],
  306. animationDuration: 0, //这里两个动画设置可以让图表更顺滑
  307. animationEasing: 'cubicInOut', //这里两个动画设置可以让图表更顺滑
  308. };
  309. };
  310. //选择年度-弹出日历回调
  311. function openChange(status) {
  312. data.yearShow = status;
  313. //日期禁用规则
  314. data.timer = setTimeout(() => {
  315. dateYearDisabledRule();
  316. }, 0);
  317. }
  318. //选择年度-面板关闭回调
  319. function panelChange(value) {
  320. data.yearShow = false;
  321. data.year = moment(value).format('YYYY');
  322. //清除定时器
  323. clearTimeout(data.timer);
  324. }
  325. /**
  326. * 日期禁用规则
  327. * type{String} 规则类型 lteNow(默认) rangeNowStart rangeNowEnd
  328. * value{String} 需要对比值
  329. * */
  330. function dateYearDisabledRule(type, value) {
  331. const typeR = type ? type : 'lteNow';
  332. const valueR = value ? moment(value).format('YYYY') : '';
  333. //获取dom元素
  334. const tableDom = document.querySelectorAll('.ant-calendar-year-panel-body');
  335. const prevBtn = document.querySelector('.ant-calendar-year-panel-prev-decade-btn');
  336. const nextBtn = document.querySelector('.ant-calendar-year-panel-next-decade-btn');
  337. const tdDom = tableDom[0].querySelectorAll('td');
  338. // 当前面板的第一个和最后一个年份类似年份翻页按钮因此和年份翻页按钮做相同处理,否则会有错误
  339. const prevBtnTd = tdDom[0];
  340. const nextBtnTd = tdDom[tdDom.length - 1];
  341. //定义所需对比值
  342. const nowDate = moment().format('YYYY');
  343. if (tableDom.length > 0) {
  344. switch (typeR) {
  345. //<=当前年
  346. case 'lteNow':
  347. (() => {
  348. tdDom.forEach((item) => {
  349. if (item.innerText > nowDate) {
  350. item.setAttribute('class', 'datepicker-year-disabled');
  351. } else {
  352. item.classList.remove('datepicker-year-disabled');
  353. }
  354. });
  355. // 年份翻页按钮
  356. const ev = dateYearDisabledRule.bind(this, 'lteNow');
  357. prevBtn.removeEventListener('click', ev);
  358. nextBtn.removeEventListener('click', ev);
  359. prevBtn.addEventListener('click', ev);
  360. nextBtn.addEventListener('click', ev);
  361. prevBtnTd.removeEventListener('click', ev);
  362. nextBtnTd.removeEventListener('click', ev);
  363. prevBtnTd.addEventListener('click', ev);
  364. nextBtnTd.addEventListener('click', ev);
  365. })();
  366. break;
  367. //<=当前年、<=结束日期
  368. case 'rangeNowStart':
  369. (() => {
  370. tdDom.forEach((item) => {
  371. if (item.innerText > nowDate || (valueR && item.innerText > valueR)) {
  372. item.setAttribute('class', 'datepicker-year-disabled');
  373. } else {
  374. item.classList.remove('datepicker-year-disabled');
  375. }
  376. });
  377. // 年份翻页按钮
  378. const ev = dateYearDisabledRule.bind(this, 'rangeNowStart', value);
  379. prevBtn.removeEventListener('click', ev);
  380. nextBtn.removeEventListener('click', ev);
  381. prevBtn.addEventListener('click', ev);
  382. nextBtn.addEventListener('click', ev);
  383. prevBtnTd.removeEventListener('click', ev);
  384. nextBtnTd.removeEventListener('click', ev);
  385. prevBtnTd.addEventListener('click', ev);
  386. nextBtnTd.addEventListener('click', ev);
  387. })();
  388. break;
  389. //<=当前年、>=开始日期
  390. case 'rangeNowEnd':
  391. (() => {
  392. tdDom.forEach((item) => {
  393. if (item.innerText > nowDate || (valueR && item.innerText < valueR)) {
  394. item.setAttribute('class', 'datepicker-year-disabled');
  395. } else {
  396. item.classList.remove('datepicker-year-disabled');
  397. }
  398. });
  399. // 年份翻页按钮
  400. const ev = dateYearDisabledRule.bind(this, 'rangeNowEnd', value);
  401. prevBtn.removeEventListener('click', ev);
  402. nextBtn.removeEventListener('click', ev);
  403. prevBtn.addEventListener('click', ev);
  404. nextBtn.addEventListener('click', ev);
  405. prevBtnTd.removeEventListener('click', ev);
  406. nextBtnTd.removeEventListener('click', ev);
  407. prevBtnTd.addEventListener('click', ev);
  408. nextBtnTd.addEventListener('click', ev);
  409. })();
  410. break;
  411. }
  412. }
  413. }
  414. onMounted(() => {
  415. setEcharts();
  416. queryData();
  417. // if (data.interval) return;
  418. // data.interval = setInterval(() => {
  419. // queryData();
  420. // }, 3000);
  421. });
  422. onUnmounted(() => {
  423. if (data.interval) clearInterval(data.interval);
  424. });
  425. return {
  426. domRef,
  427. mychart,
  428. ...toRefs(data),
  429. queryData,
  430. setEcharts,
  431. getOption,
  432. selectType,
  433. disabledDate,
  434. disabledYear,
  435. openChange,
  436. panelChange,
  437. dateYearDisabledRule,
  438. dataChange,
  439. };
  440. },
  441. });
  442. </script>
  443. <style lang="less" scoped>
  444. .spatial-analysis-statistic {
  445. height: 100%;
  446. width: 100%;
  447. padding: 1rem;
  448. .title {
  449. height: 1.2rem;
  450. font-family: Source Han Sans CN;
  451. font-size: 1.012rem;
  452. font-weight: bold;
  453. line-height: normal;
  454. letter-spacing: 0em;
  455. color: #3d3d3d;
  456. margin-bottom: 1.2rem;
  457. .statistic {
  458. display: flex;
  459. width: 330px;
  460. height: 22px;
  461. float: right;
  462. .label {
  463. margin-right: 10px;
  464. font-weight: 400;
  465. }
  466. .value {
  467. width: 60px;
  468. color: #0671dd;
  469. font-family: 思源黑体;
  470. font-size: 18px;
  471. font-weight: 500;
  472. line-height: normal;
  473. letter-spacing: 0em;
  474. margin-right: 10px;
  475. }
  476. .btn {
  477. width: 48px;
  478. height: 24px;
  479. font-weight: 400;
  480. border-radius: 180px;
  481. margin: 0 2px;
  482. text-align: center;
  483. cursor: pointer;
  484. }
  485. .active {
  486. background: #0671dd;
  487. color: #fff;
  488. }
  489. }
  490. }
  491. .echart-container {
  492. height: calc(100% - 2.4rem);
  493. width: 100%;
  494. }
  495. }
  496. </style>