manageOrgan.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. <template>
  2. <div>
  3. <div
  4. class="wall"
  5. style="height: 68px"
  6. v-if="JSON.stringify(items) == '{}'"
  7. ></div>
  8. <!-- 按月/按天 -->
  9. <div class="wrap">
  10. <!-- v-if="timer == 'day'" :settings="chartSettings" DD-->
  11. <ve-histogram
  12. :data="chartData"
  13. height="524px"
  14. :data-empty="dataEmpty"
  15. :extend="chartExtend"
  16. :legend="legend"
  17. :data-zoom="dataZoom"
  18. />
  19. <!-- <ve-line
  20. v-else
  21. :data-zoom="dataZoom"
  22. :settings="{
  23. area: true,
  24. }"
  25. :data="chartDataForMoth"
  26. height="350px"
  27. :data-empty="dataEmpty"
  28. :data-zoom="dataZoom"
  29. :extend="chartExtend"
  30. :legend="legend"
  31. /> -->
  32. </div>
  33. </div>
  34. </template>
  35. <script>
  36. import "echarts/lib/component/dataZoom";
  37. import countTo from "vue-count-to";
  38. // import veLine from "v-charts/lib/line.common";
  39. import histogram from "v-charts/lib/histogram.common";
  40. import searchHeader from "./searchHeader";
  41. import { getIndex } from "../../api";
  42. import { getTimes } from "@/utils";
  43. import { descs, chioseNum } from "../../constant";
  44. import { orderType } from "@/constant";
  45. export default {
  46. props: ["data", "search"],
  47. components: {
  48. // "ve-line": veLine,
  49. "count-to": countTo,
  50. "ve-histogram": histogram,
  51. searchHeader,
  52. },
  53. computed: {
  54. legend() {
  55. return {
  56. left: "10px",
  57. };
  58. },
  59. items() {
  60. let obj = {};
  61. let arr = [
  62. "TOTAL_AMOUNT",
  63. // "FINANCE_AMOUNT",
  64. // "FINANCE_BALANCE_AMOUNT",
  65. // "FINANCE_PAY",
  66. ];
  67. arr.forEach((str) => {
  68. if (this.data[str]) {
  69. obj[str] = this.data[str];
  70. }
  71. });
  72. // console.log(obj);
  73. return obj;
  74. },
  75. items2() {
  76. let obj = {};
  77. let arr = [
  78. "APPLY_AMOUNT",
  79. "RENEW_AMOUNT",
  80. "VIP_AMOUNT",
  81. "PRACTICE_AMOUNT",
  82. "OTHER_AMOUNT",
  83. ];
  84. arr.forEach((str) => {
  85. if (this.data[str]) {
  86. obj[str] = this.data[str];
  87. }
  88. });
  89. return obj;
  90. },
  91. chartExtend() {
  92. return {
  93. series: {
  94. smooth: false,
  95. barwidth: 80,
  96. label: {
  97. show: true,
  98. position: "top",
  99. color: "#000",
  100. formatter: function (value) {
  101. var val = value.data;
  102. return val + "%";
  103. },
  104. },
  105. },
  106. markerPoint: {
  107. data: { name: "百分比" },
  108. },
  109. yAxis: {
  110. //纵轴标尺固定
  111. minInterval: 1,
  112. type: "value",
  113. scale: true,
  114. min: 0,
  115. axisLabel: {
  116. formatter: "{value}%",
  117. },
  118. },
  119. xAxis: {
  120. interval: 0,
  121. axisLabel: {
  122. show: true, // 是否显示刻度标签,默认显示
  123. interval: 0, // 坐标轴刻度标签的显示间隔,在类目轴中有效;默认会采用标签不重叠的策略间隔显示标签;可以设置成0强制显示所有标签;如果设置为1,表示『隔一个标签显示一个标签』,如果值为2,表示隔两个标签显示一个标签,以此类推。
  124. inside: false, // 刻度标签是否朝内,默认朝外
  125. margin: 6, // 刻度标签与轴线之间的距离
  126. formatter: function (value) {
  127. return value.split("").join("\n");
  128. },
  129. },
  130. },
  131. tooltip: {
  132. axisPointer: {
  133. type: "shadow",
  134. shadowStyle: {
  135. color: "rgba(150,150,150,0.2)",
  136. },
  137. },
  138. formatter: (item) => {
  139. // console.log(item);
  140. // console.log(this.values, item[0].axisValue, "organ");
  141. let arr = [
  142. { name: "总收入", dot: "元" },
  143. { name: "总收入占比", dot: "%" },
  144. { name: "报名缴费收入", dot: "元" },
  145. { name: "乐团续费收入", dot: "元" },
  146. { name: "VIP课收入", dot: "元" },
  147. { name: "网管课收入", dot: "元" },
  148. { name: "其他收入", dot: "元" },
  149. ];
  150. return [
  151. item[0].axisValueLabel,
  152. ...arr.map(
  153. (d) =>
  154. `<br/>${d.name}:${this.values[item[0].axisValue][d.name]}${
  155. d.dot
  156. }`
  157. ),
  158. ].join("");
  159. },
  160. },
  161. };
  162. },
  163. dataZoom() {
  164. return [
  165. {
  166. show: true,
  167. type: "slider",
  168. start: 0,
  169. end: 20,
  170. filterMode: "empty",
  171. },
  172. ];
  173. },
  174. chartData() {
  175. //
  176. const values = Object.values({ ...this.items, ...this.items2 });
  177. const organ = {};
  178. const organNameList = [];
  179. // 计算总的百分比
  180. for (const row of values[0].organIndexMonthData || []) {
  181. const key = row.organName;
  182. organ[key] = {
  183. 分部: row.organName,
  184. };
  185. for (const item of values) {
  186. if (item.title == row.title) {
  187. organ[key][item.title] = row.percent;
  188. }
  189. if (item.title == "总收入" && row.title == "总收入") {
  190. organ[key]["总收入占比"] = (
  191. (row.percent / item.percent) *
  192. 100
  193. ).toFixed(2);
  194. }
  195. }
  196. }
  197. for (const item of values) {
  198. for (const row of item.organIndexMonthData || []) {
  199. if (item.title == row.title) {
  200. organ[row.organName][row.title] = row.percent;
  201. }
  202. }
  203. }
  204. // const months = {};
  205. // for (const item of values) {
  206. // for (const row of item.indexMonthData || []) {
  207. // const key = this.$helpers.dayjs(row.month).format("YYYY-MM-DD");
  208. // if (!months[key]) {
  209. // months[key] = {
  210. // 日期: key,
  211. // };
  212. // }
  213. // months[key][item.title] = row.percent;
  214. // }
  215. // }
  216. console.log(organ);
  217. this.values = organ;
  218. // console.log(values);
  219. // return;
  220. return {
  221. columns: ["分部", "总收入占比"],
  222. rows: Object.values(organ),
  223. loading: true,
  224. };
  225. },
  226. chartDataForMoth() {
  227. const values = Object.values({ ...this.items, ...this.items2 });
  228. const months = {};
  229. for (const item of values) {
  230. for (const row of item.indexMonthData || []) {
  231. const key = this.$helpers.dayjs(row.month).format("YYYY-MM");
  232. if (!months[key]) {
  233. months[key] = {
  234. 月份: key,
  235. };
  236. months[key][item.title] = row.percent;
  237. } else {
  238. if (months[key][item.title]) {
  239. months[key][item.title] = (
  240. parseFloat(months[key][item.title]) + parseFloat(row.percent)
  241. ).toFixed(2);
  242. } else {
  243. months[key][item.title] = parseFloat(row.percent).toFixed(2);
  244. }
  245. }
  246. }
  247. }
  248. return {
  249. columns: [
  250. "月份",
  251. "总收入",
  252. "现金收入",
  253. "余额收入",
  254. "财务支出",
  255. "报名缴费收入",
  256. "网管课收入",
  257. "其他收入",
  258. "乐团续费收入",
  259. "VIP课收入",
  260. ],
  261. rows: Object.values(months),
  262. loading: true,
  263. };
  264. },
  265. dataEmpty() {
  266. return !this.chartData.rows.length;
  267. },
  268. },
  269. data() {
  270. // this.chartSettings = {
  271. // stack: { 总收入: [`现金收入`, `余额收入`] },
  272. // };
  273. return {
  274. orderType,
  275. active: "SHOULD_INCOME_MONEY",
  276. mdate: [],
  277. loading: false,
  278. endDate: "",
  279. show: true,
  280. activeName: "first",
  281. timer: "day",
  282. values: "",
  283. };
  284. },
  285. mounted() {
  286. this.init();
  287. },
  288. methods: {
  289. init() {
  290. // this.$refs.searchHeader.initStatue("month");
  291. this.mdate = this.getInitDate();
  292. this.endDate = this.$helpers.dayjs(new Date()).format("YYYY-MM-DD");
  293. this.isDayOrMoth(this.mdate);
  294. // // this.$refs.searchHeader.initStatue()
  295. // this.changeValue(this.mdate);
  296. },
  297. // changeValue(date) {
  298. // // 请求更改数据
  299. // this.mdate = date;
  300. // this.isDayOrMoth(date);
  301. // this.FetchDetail();
  302. // },
  303. // async FetchDetail() {
  304. // this.loading = true;
  305. // let data = [];
  306. // try {
  307. // const { dates, ...rest } = this.search;
  308. // const res = await getIndex({
  309. // ...rest,
  310. // ...getTimes(this.mdate, ["startDate", "endDate"]),
  311. // //
  312. // dataTypes:
  313. // "FINANCE_AMOUNT,FINANCE_BALANCE_AMOUNT,FINANCE_PAY,TOTAL_AMOUNT",
  314. // });
  315. // for (const item of res.data) {
  316. // // 再循环一遍
  317. // for (const key in { ...this.items, ...this.items2 }) {
  318. // // console.log(key);
  319. // if (item.dataType == key) {
  320. // data[item.dataType] = {
  321. // ...item,
  322. // desc: descs[item.dataType],
  323. // };
  324. // }
  325. // }
  326. // }
  327. // } catch (error) {
  328. // console.log(error);
  329. // }
  330. // this.loading = false;
  331. // this.$emit("resetDate", data);
  332. // },
  333. isDayOrMoth(arr) {
  334. if (!arr || arr.length < 1) {
  335. this.timer = "day";
  336. } else {
  337. const count = this.$helpers
  338. .dayjs(arr[0])
  339. .diff(this.$helpers.dayjs(arr[1]), "day");
  340. Math.abs(count) > chioseNum
  341. ? (this.timer = "month")
  342. : (this.timer = "day");
  343. }
  344. },
  345. getInitDate() {
  346. const end = this.$helpers.dayjs(new Date()).format("YYYY-MM-DD");
  347. const start = this.$helpers
  348. .dayjs(new Date())
  349. .set("date", 1)
  350. .format("YYYY-MM-DD");
  351. return [start, end];
  352. },
  353. },
  354. };
  355. </script>
  356. <style lang="less" scoped>
  357. /deep/.description-title {
  358. margin-bottom: 0;
  359. }
  360. #management .statistic .statistic-content > span {
  361. &:first-child {
  362. font-size: 14px !important;
  363. }
  364. font-size: 18px !important;
  365. }
  366. .chioseBox {
  367. position: absolute;
  368. right: 20px;
  369. z-index: 1000;
  370. }
  371. .wrap {
  372. position: relative;
  373. }
  374. .blod {
  375. font-weight: bold;
  376. color: var(--color-primary);
  377. font-size: 22px !important;
  378. }
  379. // .chioseBox {
  380. // position: absolute;
  381. // right: 20px;
  382. // z-index: 1000;
  383. // }
  384. // .wrap {
  385. // position: relative;
  386. // }
  387. .statisticWrap {
  388. // box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
  389. border-radius: 4px;
  390. border: 1px solid #ebeef5;
  391. padding-top: 10px;
  392. margin-bottom: 10px;
  393. position: relative;
  394. &:after {
  395. top: -16px;
  396. margin-left: calc(10% - 14px);
  397. border-top-width: 0;
  398. border-color: transparent;
  399. border-bottom-color: #fff;
  400. content: " ";
  401. border-width: 8px;
  402. position: absolute;
  403. display: block;
  404. width: 0;
  405. height: 0;
  406. border-style: solid;
  407. z-index: 101;
  408. }
  409. &:before {
  410. top: -20px;
  411. margin-left: calc(10% - 16px);
  412. border-top-width: 0;
  413. border-color: transparent;
  414. border-bottom-color: #ebeef5;
  415. content: " ";
  416. border-width: 10px;
  417. position: absolute;
  418. display: block;
  419. width: 0;
  420. height: 0;
  421. border-style: solid;
  422. z-index: 100;
  423. }
  424. }
  425. </style>