index.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. <template>
  2. <div class="container">
  3. <visitorStatistics />
  4. <div class="card">
  5. <cord-top title="访客趋势分析" @returnWhere="getVisitorTrend" />
  6. <div ref="visitorTrend" style="margin-top: 20px"></div>
  7. </div>
  8. <div class="card">
  9. <cord-top title="访问量趋势分析" @returnWhere="getPageViewTrend" />
  10. <div ref="pageViewTrend" style="margin-top: 20px"></div>
  11. </div>
  12. <div class="card">
  13. <cord-top title="用户类型分析" @returnWhere="getUserTypeAnalysis" />
  14. <div ref="userTypeAnalysis" style="margin-top: 20px"></div>
  15. </div>
  16. <div class="card">
  17. <cord-top
  18. title="各模块点击量分析"
  19. @returnWhere="getModuleClicksAnalysis"
  20. />
  21. <div class="module-clicks">
  22. <div
  23. class="pie-chart"
  24. ref="moduleClicksAnalysis"
  25. style="margin-top: 20px"
  26. ></div>
  27. <el-table :data="moduleClicksAnalysisTable" border style="width: 100%">
  28. <el-table-column prop="module" :label="$t('模块名称')">
  29. </el-table-column>
  30. <el-table-column prop="clickcount" :label="$t('当前时段模块点击量')">
  31. </el-table-column>
  32. <el-table-column prop="sumclickcount" :label="$t('模块总点击量')">
  33. </el-table-column>
  34. </el-table>
  35. </div>
  36. </div>
  37. <div class="card">
  38. <rankingList />
  39. </div>
  40. <div class="card">
  41. <cord-top title="留言分析" @returnWhere="getMessageAnalysis" />
  42. <div ref="messageAnalysis" style="margin-top: 20px"></div>
  43. </div>
  44. <statisticalAnalysisOfMessage />
  45. <div class="card">
  46. <cord-top title="服务申请分析" @returnWhere="getServiceRequestAnalysis" />
  47. <div ref="serviceRequestAnalysis" style="margin-top: 20px"></div>
  48. </div>
  49. </div>
  50. </template>
  51. <script>
  52. import cordTop from "./modules/header.vue";
  53. import visitorStatistics from "./modules/visitorStatistics";
  54. import rankingList from "./modules/rankingList";
  55. import statisticalAnalysisOfMessage from "./modules/statisticalAnalysisOfMessage";
  56. import { Line, Column, Pie } from "@antv/g2plot";
  57. export default {
  58. components: {
  59. visitorStatistics,
  60. cordTop,
  61. rankingList,
  62. statisticalAnalysisOfMessage,
  63. },
  64. data() {
  65. return {
  66. visitorTrend: null, //访客趋势
  67. pageViewTrend: null, //访问量趋势
  68. userTypeAnalysis: null, //用户类型分析
  69. moduleClicksAnalysis: null, //各模块点击量分析
  70. moduleClicksAnalysisTable: null, //各模块点击量分析表格
  71. messageAnalysis: null, //留言分析
  72. serviceRequestAnalysis: null, //服务申请分析
  73. siteid: "", //站点id
  74. };
  75. },
  76. created() {
  77. this.siteid = JSON.parse(sessionStorage.getItem("active_account")).siteid;
  78. // 获取访客趋势
  79. this.getVisitorTrend();
  80. // 获取访问量趋势
  81. this.getPageViewTrend();
  82. // 获取用户类型分析
  83. this.getUserTypeAnalysis();
  84. // 获取各模块点击量分析
  85. this.getModuleClicksAnalysis();
  86. // 获取留言分析
  87. this.getMessageAnalysis();
  88. // 获取服务申请分析
  89. this.getServiceRequestAnalysis();
  90. },
  91. methods: {
  92. // 获取访客趋势
  93. getVisitorTrend(detail) {
  94. let content = {
  95. nocache: true,
  96. siteid: this.siteid,
  97. type: "近七日",
  98. datatype: "访客",
  99. };
  100. if (detail) {
  101. if (detail.type) {
  102. content.type = detail.type;
  103. } else {
  104. content.type = "";
  105. content.where = detail;
  106. }
  107. }
  108. this.$api
  109. .requested({
  110. id: 2025010214275903,
  111. content,
  112. })
  113. .then((res) => {
  114. if (res.code != 1) return;
  115. let type = this.$t("访客数量");
  116. let list = res.data.map((v) => {
  117. v.type = type;
  118. return v;
  119. });
  120. if (detail) {
  121. this.visitorTrend.update({
  122. scrollbar: list.length > 14 ? { type: "horizontal" } : null,
  123. });
  124. this.visitorTrend.changeData(list);
  125. } else {
  126. this.visitorTrend = new Line(this.$refs.visitorTrend, {
  127. height: 300,
  128. data: list,
  129. xField: "date",
  130. seriesField: "type",
  131. yField: "count",
  132. color: "#5588F7",
  133. tooltip: {
  134. formatter: (datum) => {
  135. return {
  136. name: type,
  137. value: datum.count,
  138. };
  139. },
  140. },
  141. point: {
  142. shape: "breath-point",
  143. },
  144. });
  145. this.visitorTrend.render();
  146. }
  147. });
  148. },
  149. // 获取访问量趋势
  150. getPageViewTrend(detail) {
  151. let content = {
  152. nocache: true,
  153. siteid: this.siteid,
  154. type: "近七日",
  155. datatype: "访问量",
  156. };
  157. if (detail) {
  158. if (detail.type) {
  159. content.type = detail.type;
  160. } else {
  161. content.type = "";
  162. content.where = detail;
  163. }
  164. }
  165. this.$api
  166. .requested({
  167. id: 2025010214275903,
  168. content,
  169. })
  170. .then((res) => {
  171. if (res.code != 1) return;
  172. let type = this.$t("访问量");
  173. let list = res.data.map((v) => {
  174. v.type = type;
  175. return v;
  176. });
  177. if (detail) {
  178. this.pageViewTrend.update({
  179. scrollbar: list.length > 14 ? { type: "horizontal" } : null,
  180. });
  181. this.pageViewTrend.changeData(list);
  182. } else {
  183. this.pageViewTrend = new Line(this.$refs.pageViewTrend, {
  184. height: 300,
  185. data: list,
  186. xField: "date",
  187. yField: "count",
  188. color: "#F29C37",
  189. seriesField: "type",
  190. tooltip: {
  191. formatter: (datum) => {
  192. return { name: type, value: datum.count };
  193. },
  194. },
  195. point: {
  196. shape: "breath-point",
  197. },
  198. });
  199. this.pageViewTrend.render();
  200. }
  201. });
  202. },
  203. // 获取各模块点击量分析
  204. getModuleClicksAnalysis(detail) {
  205. let content = {
  206. siteid: this.siteid,
  207. nocache: true,
  208. type: "近七日",
  209. };
  210. if (detail) {
  211. if (detail.type) {
  212. content.type = detail.type;
  213. } else {
  214. content.type = "";
  215. content.where = detail;
  216. }
  217. }
  218. this.$api
  219. .requested({
  220. id: 2025010309594403,
  221. content,
  222. })
  223. .then((res) => {
  224. if (res.code != 1) return;
  225. let list = res.data.map((v) => {
  226. v.module = this.$t(v.module);
  227. return v;
  228. });
  229. this.moduleClicksAnalysisTable = list;
  230. if (detail) {
  231. this.moduleClicksAnalysis.changeData(list);
  232. } else {
  233. this.moduleClicksAnalysis = new Pie(
  234. this.$refs.moduleClicksAnalysis,
  235. {
  236. height: 400,
  237. appendPadding: 10,
  238. angleField: "clickcount",
  239. colorField: "module",
  240. radius: 1,
  241. innerRadius: 0.64,
  242. data: list,
  243. label: {
  244. type: "inner",
  245. offset: "-50%",
  246. autoRotate: false,
  247. style: { textAlign: "center" },
  248. formatter: ({ percent }) => `${(percent * 100).toFixed(0)}%`,
  249. },
  250. statistic: {
  251. title: {
  252. offsetY: -8,
  253. customHtml: (container, view, datum) => {
  254. const text = datum ? datum.module : this.$t("点击量总数");
  255. return text;
  256. },
  257. },
  258. content: {
  259. offsetY: -4,
  260. },
  261. },
  262. legend: {
  263. layout: "horizontal",
  264. position: "bottom",
  265. flipPage: false,
  266. },
  267. // 添加 中心统计文本 交互
  268. interactions: [
  269. { type: "element-selected" },
  270. { type: "element-active" },
  271. {
  272. type: "pie-statistic-active",
  273. cfg: {
  274. start: [
  275. {
  276. trigger: "element:mouseenter",
  277. action: "pie-statistic:change",
  278. },
  279. {
  280. trigger: "legend-item:mouseenter",
  281. action: "pie-statistic:change",
  282. },
  283. ],
  284. end: [
  285. {
  286. trigger: "element:mouseleave",
  287. action: "pie-statistic:reset",
  288. },
  289. {
  290. trigger: "legend-item:mouseleave",
  291. action: "pie-statistic:reset",
  292. },
  293. ],
  294. },
  295. },
  296. ],
  297. }
  298. );
  299. this.moduleClicksAnalysis.render();
  300. }
  301. });
  302. },
  303. // 获取用户类型分析
  304. getUserTypeAnalysis(detail) {
  305. let content = {
  306. nocache: true,
  307. siteid: this.siteid,
  308. type: "近七日",
  309. };
  310. if (detail) {
  311. if (detail.type) {
  312. content.type = detail.type;
  313. } else {
  314. content.type = "";
  315. content.where = detail;
  316. }
  317. }
  318. this.$api
  319. .requested({
  320. id: 2025010309354603,
  321. content,
  322. })
  323. .then((res) => {
  324. if (res.code != 1) return;
  325. let type = [this.$t("登录用户"), this.$t("游客")];
  326. let list = [];
  327. res.data.filter((v) => {
  328. list.push({
  329. date: v.date,
  330. count: v.logincount,
  331. type: type[0],
  332. });
  333. list.push({
  334. date: v.date,
  335. count: v.visitorcount,
  336. type: type[1],
  337. });
  338. });
  339. if (detail) {
  340. this.userTypeAnalysis.update({
  341. scrollbar: list.length > 28 ? { type: "horizontal" } : null,
  342. });
  343. this.userTypeAnalysis.changeData(list);
  344. } else {
  345. this.userTypeAnalysis = new Column(this.$refs.userTypeAnalysis, {
  346. height: 300,
  347. data: list,
  348. isGroup: true,
  349. xField: "date",
  350. yField: "count",
  351. color: ["#3874F6", "#F29C37"],
  352. seriesField: "type",
  353. label: {
  354. // 可手动配置 label 数据标签位置
  355. position: "top", // 'top', 'middle', 'bottom'
  356. // 可配置附加的布局方法
  357. layout: [
  358. // 柱形图数据标签位置自动调整
  359. { type: "interval-adjust-position" },
  360. // 数据标签防遮挡
  361. { type: "interval-hide-overlap" },
  362. // 数据标签文颜色自动调整
  363. { type: "adjust-color" },
  364. ],
  365. },
  366. });
  367. this.userTypeAnalysis.render();
  368. }
  369. });
  370. },
  371. // 获取留言分析
  372. getMessageAnalysis(detail) {
  373. let content = {
  374. nocache: true,
  375. siteid: this.siteid,
  376. type: "近七日",
  377. };
  378. if (detail) {
  379. if (detail.type) {
  380. content.type = detail.type;
  381. } else {
  382. content.type = "";
  383. content.where = detail;
  384. }
  385. }
  386. this.$api
  387. .requested({
  388. id: 2025010310381303,
  389. content,
  390. })
  391. .then((res) => {
  392. if (res.code != 1) return;
  393. let type = this.$t("留言量");
  394. let list = res.data.map((v) => {
  395. v.type = type;
  396. return v;
  397. });
  398. if (detail) {
  399. this.messageAnalysis.update({
  400. scrollbar: list.length > 14 ? { type: "horizontal" } : null,
  401. });
  402. this.messageAnalysis.changeData(list);
  403. } else {
  404. this.messageAnalysis = new Line(this.$refs.messageAnalysis, {
  405. height: 300,
  406. data: list,
  407. xField: "date",
  408. seriesField: "type",
  409. yField: "count",
  410. color: "#5588F7",
  411. tooltip: {
  412. formatter: (datum) => {
  413. return {
  414. name: type,
  415. value: datum.count,
  416. };
  417. },
  418. },
  419. point: {
  420. shape: "breath-point",
  421. },
  422. });
  423. this.messageAnalysis.render();
  424. }
  425. });
  426. },
  427. // 获取服务申请分析
  428. getServiceRequestAnalysis(detail) {
  429. let content = {
  430. nocache: true,
  431. siteid: this.siteid,
  432. type: "近七日",
  433. };
  434. if (detail) {
  435. if (detail.type) {
  436. content.type = detail.type;
  437. } else {
  438. content.type = "";
  439. content.where = detail;
  440. }
  441. }
  442. this.$api
  443. .requested({
  444. id: 2025010310402603,
  445. content,
  446. })
  447. .then((res) => {
  448. if (res.code != 1) return;
  449. let type = this.$t("申请量");
  450. let list = res.data.map((v) => {
  451. v.type = type;
  452. return v;
  453. });
  454. if (detail) {
  455. this.serviceRequestAnalysis.update({
  456. scrollbar: list.length > 14 ? { type: "horizontal" } : null,
  457. });
  458. this.serviceRequestAnalysis.changeData(list);
  459. } else {
  460. this.serviceRequestAnalysis = new Line(
  461. this.$refs.serviceRequestAnalysis,
  462. {
  463. height: 300,
  464. data: list,
  465. xField: "date",
  466. seriesField: "type",
  467. yField: "count",
  468. color: "#F29C37",
  469. tooltip: {
  470. formatter: (datum) => {
  471. return {
  472. name: type,
  473. value: datum.count,
  474. };
  475. },
  476. },
  477. point: {
  478. shape: "breath-point",
  479. },
  480. }
  481. );
  482. this.serviceRequestAnalysis.render();
  483. }
  484. });
  485. },
  486. },
  487. };
  488. </script>
  489. <style scoped>
  490. .container {
  491. padding: 20px;
  492. box-sizing: border-box;
  493. }
  494. .card {
  495. width: 100%;
  496. padding: 20px;
  497. background: #ffffff;
  498. box-shadow: 0px 1px 6px 1px rgba(0, 0, 0, 0.16);
  499. border-radius: 10px;
  500. box-sizing: border-box;
  501. margin-top: 20px;
  502. }
  503. .module-clicks {
  504. display: flex;
  505. align-items: center;
  506. }
  507. .pie-chart {
  508. width: 450px;
  509. }
  510. </style>