index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. <template>
  2. <div class="home-contain">
  3. <div style="position: relative; padding: 16px 0; background-color: #fff;">
  4. <div style="position: absolute; top: 20px; right: 20px; z-index: 99;">
  5. <year-month-select v-model="currYear" :showMonth="false" style="margin: 0;" />
  6. </div>
  7. <el-row gutter="20">
  8. <el-col :span="9">
  9. <basic-card title="研发项目情况">
  10. <avue-data-display :option="projectTotalOpt"></avue-data-display>
  11. <div style="position: relative;">
  12. <basic-chart
  13. style="width: 100%; height: 300px"
  14. :options="projectStatusOpt"
  15. />
  16. </div>
  17. </basic-card>
  18. </el-col>
  19. <el-col :span="9">
  20. <basic-card title="研发费用情况">
  21. <avue-data-display :option="RD_costOpt"></avue-data-display>
  22. <div style="position: relative;">
  23. <basic-chart
  24. style="width: 100%; height: 300px"
  25. :options="yffyPieOptions"
  26. />
  27. </div>
  28. </basic-card>
  29. </el-col>
  30. </el-row>
  31. <el-divider></el-divider>
  32. <el-row gutter="20">
  33. <el-col :span="9">
  34. <basic-card title="研发人员情况">
  35. <avue-data-display :option="RD_person_zb_opt"></avue-data-display>
  36. <div style="position: relative;">
  37. <basic-chart
  38. style="width: 100%; height: 300px"
  39. :options="RD_personOpt"
  40. />
  41. </div>
  42. </basic-card>
  43. </el-col>
  44. <el-col :span="9">
  45. <basic-card title="知识产权情况">
  46. <avue-data-display :option="zscqTotalOpt"></avue-data-display>
  47. <div style="position: relative;">
  48. <basic-chart
  49. style="width: 100%; height: 300px"
  50. :options="zscqOpt"
  51. />
  52. </div>
  53. </basic-card>
  54. </el-col>
  55. </el-row>
  56. <el-divider></el-divider>
  57. <basic-card title="本年度月研发归集趋势图">
  58. <el-row style="margin-top: 45px">
  59. <el-col :span="24">
  60. <basic-chart
  61. style="width: 100%; height: 300px"
  62. :options="monthAggregationBarOpt"
  63. />
  64. </el-col>
  65. </el-row>
  66. </basic-card>
  67. <el-divider></el-divider>
  68. <basic-card title="项目预算与归集趋势图">
  69. <el-row :gutter="24">
  70. <el-col :span="12">
  71. <basic-chart
  72. style="width: 100%; height: 300px"
  73. :options="currYearBudgetOpt"
  74. />
  75. </el-col>
  76. <el-col :span="12">
  77. <basic-chart
  78. style="width: 100%; height: 300px"
  79. :options="fullCycleBudgetOpt"
  80. />
  81. </el-col>
  82. </el-row>
  83. </basic-card>
  84. </div>
  85. </div>
  86. </template>
  87. <script>
  88. import basicCard from "@/components/basic-card";
  89. import basicChart from "@/components/basic-chart";
  90. import numStatistics from "./components/num-statistics.vue";
  91. import YearMonthSelect from "@/components/year-month-select";
  92. import { getProjectListByYear } from "@/api/projectManage/projectList";
  93. import { getList as getCostSummaryList } from "@/api/yfCostManage/yfCostStatistics/yfCostSummaryList";
  94. import { getList as getZlList } from "@/api/achievement/patentAchievement";
  95. import { getList as getCyPersonList } from "@/api/techPerson/cyPersonRoster";
  96. import Decimal from "decimal.js";
  97. export default {
  98. name: "home",
  99. components: {
  100. basicCard,
  101. basicChart,
  102. numStatistics,
  103. YearMonthSelect
  104. },
  105. data() {
  106. let monthArr = [];
  107. for(let i=0; i<12; i++) {
  108. monthArr.push((i+1)+"月");
  109. }
  110. return {
  111. currYear: "",
  112. projectTotal: 0,
  113. costAmount: 0,
  114. yfPersonZb: 0, // 研发人员占比
  115. zscqTotal: 0,
  116. // 项目情况
  117. projectStatusOpt: {},
  118. // 研发费用情况
  119. yffyPieOptions: {},
  120. // 研发人员情况
  121. RD_personOpt: {},
  122. // 知识产权情况
  123. zscqOpt: {},
  124. // 本年度月研发归集趋势图
  125. monthAggregationBarOpt: {
  126. grid: {
  127. top: "3%",
  128. left: "3%",
  129. right: "3%",
  130. bottom: "10%",
  131. },
  132. tooltip: {
  133. trigger: "axis",
  134. axisPointer: {
  135. type: "shadow",
  136. },
  137. },
  138. xAxis: {
  139. type: 'category',
  140. data: monthArr
  141. },
  142. yAxis: {
  143. type: 'value',
  144. axisLabel: {
  145. formatter: value => {
  146. return value+" 元";
  147. }
  148. }
  149. },
  150. series: [
  151. {
  152. data: [6200, 4000, 300, 200, 1000, 6000, 3000, 2000, 1500, 5000, 1600, 9000],
  153. type: 'bar',
  154. barWidth: "25%",
  155. label: {
  156. show: true,
  157. position: "top"
  158. }
  159. }
  160. ]
  161. },
  162. // 本年度项目预算与归集表
  163. currYearBudgetOpt: {
  164. title: {
  165. text: "本年度",
  166. left: "13%",
  167. },
  168. tooltip: {
  169. trigger: "axis",
  170. axisPointer: {
  171. type: "shadow",
  172. },
  173. },
  174. legend: {
  175. left: "center",
  176. bottom: 0,
  177. },
  178. grid: {
  179. top: "16%",
  180. left: "8%",
  181. right: "2%",
  182. bottom: "13%",
  183. containLabel: true,
  184. },
  185. xAxis: {
  186. type: "value",
  187. boundaryGap: [0, 0.01],
  188. },
  189. yAxis: {
  190. type: "category",
  191. data: ["项目一", "项目二", "项目三", "项目四", "项目五", "项目六"],
  192. },
  193. series: [
  194. {
  195. name: "预算",
  196. type: "bar",
  197. data: [18203, 23489, 29034, 104970, 131744, 630230],
  198. },
  199. {
  200. name: "归集",
  201. type: "bar",
  202. data: [19325, 23438, 31000, 121594, 134141, 681807],
  203. },
  204. ],
  205. },
  206. // 全周期项目预算与归集表
  207. fullCycleBudgetOpt: {
  208. title: {
  209. text: "全周期",
  210. left: "13%",
  211. },
  212. tooltip: {
  213. trigger: "axis",
  214. axisPointer: {
  215. type: "shadow",
  216. },
  217. },
  218. legend: {
  219. left: "center",
  220. bottom: 0,
  221. },
  222. grid: {
  223. top: "16%",
  224. left: "8%",
  225. right: "2%",
  226. bottom: "13%",
  227. containLabel: true,
  228. },
  229. xAxis: {
  230. type: "value",
  231. boundaryGap: [0, 0.01],
  232. },
  233. yAxis: {
  234. type: "category",
  235. data: ["项目一", "项目二", "项目三", "项目四", "项目五", "项目六"],
  236. },
  237. series: [
  238. {
  239. name: "预算",
  240. type: "bar",
  241. data: [18203, 23489, 29034, 104970, 131744, 630230],
  242. },
  243. {
  244. name: "归集",
  245. type: "bar",
  246. data: [19325, 23438, 31000, 121594, 134141, 681807],
  247. },
  248. ],
  249. }
  250. };
  251. },
  252. computed: {
  253. projectTotalOpt() {
  254. return {
  255. span: 24,
  256. data: [
  257. {
  258. icon: 'el-icon-view',
  259. color: 'rgb(56, 161, 242)',
  260. count: this.projectTotal,
  261. decimals: 0,
  262. title: "项目总数",
  263. },
  264. ],
  265. }
  266. },
  267. RD_costOpt() {
  268. return {
  269. span: 24,
  270. data: [
  271. {
  272. icon: 'el-icon-view',
  273. color: 'rgb(56, 161, 242)',
  274. count: this.costAmount,
  275. decimals: 2,
  276. title: "研发费用(元)",
  277. },
  278. ],
  279. }
  280. },
  281. RD_person_zb_opt() {
  282. return {
  283. span: 24,
  284. data: [
  285. {
  286. icon: 'el-icon-view',
  287. color: 'rgb(56, 161, 242)',
  288. count: this.yfPersonZb,
  289. decimals: 2,
  290. title: "研发人员占比(%)",
  291. },
  292. ],
  293. }
  294. },
  295. zscqTotalOpt() {
  296. return {
  297. span: 24,
  298. data: [
  299. {
  300. icon: 'el-icon-view',
  301. color: 'rgb(56, 161, 242)',
  302. count: this.zscqTotal,
  303. decimals: 0,
  304. title: "知识产权总数",
  305. },
  306. ],
  307. }
  308. }
  309. },
  310. watch: {
  311. currYear() {
  312. this.getProjectListByYearFunc();
  313. this.getCostSummaryListFunc();
  314. this.getZlListFunc();
  315. this.getCyPersonListFunc();
  316. }
  317. },
  318. mounted() {
  319. // this.initProjectStatusOptions();
  320. // this.initRdPersonOptions();
  321. // this.initZscqOptions();
  322. // this.initYfffChartOptions();
  323. },
  324. methods: {
  325. getProjectListByYearFunc() {
  326. getProjectListByYear({ year: this.currYear }).then(({ data }) => {
  327. let _projectList = data.data;
  328. this.projectTotal = _projectList.length;
  329. this.projectStatusOpt = this.getPieOptions("研发项目情况", [
  330. { value: _projectList.filter(item => item.status == 1).length, name: "开展中" },
  331. { value: _projectList.filter(item => item.status == 2).length, name: "已结题" },
  332. { value: _projectList.filter(item => item.status == 3).length, name: "项目暂停" },
  333. { value: _projectList.filter(item => item.status == 4).length, name: "项目终止" },
  334. ]);
  335. });
  336. },
  337. // 获取费用统计数据
  338. getCostSummaryListFunc() {
  339. getCostSummaryList({ yearAndMonth: `${this.currYear}12` }).then(({ data }) => {
  340. let ryrgfyTotal = new Decimal(0); // 人员人工费用
  341. let zjtrfyTotal = new Decimal(0); // 直接投入费用
  342. let zjfyycqdtfyTotal = new Decimal(0); // 折旧费用和长期待摊费用
  343. let sjfyTotal = new Decimal(0); // 设计费用
  344. let wxzctxfyTotal = new Decimal(0); // 无形资产摊销费用
  345. let zbtsfyysyfyTotal = new Decimal(0); // 装备调试费用与试验费用
  346. let qtfyTotal = new Decimal(0); // 其他费用
  347. let wwfyTotal = new Decimal(0); // 委外费用
  348. data.data.forEach(item => {
  349. ryrgfyTotal = ryrgfyTotal.add(new Decimal(item.ryrgfy));
  350. zjtrfyTotal = zjtrfyTotal.add(new Decimal(item.zjtrfy));
  351. zjfyycqdtfyTotal = zjfyycqdtfyTotal.add(new Decimal(item.zjfyycqdtfy));
  352. sjfyTotal = sjfyTotal.add(new Decimal(item.sjfy));
  353. wxzctxfyTotal = wxzctxfyTotal.add(new Decimal(item.wxzctxfy));
  354. zbtsfyysyfyTotal = zbtsfyysyfyTotal.add(new Decimal(item.zbtsfyysyfy));
  355. qtfyTotal = qtfyTotal.add(new Decimal(item.qtfy));
  356. wwfyTotal = wwfyTotal.add(new Decimal(item.wwfy));
  357. });
  358. // 研发费用总额
  359. let costAmount = ryrgfyTotal
  360. .add(zjtrfyTotal)
  361. .add(zjfyycqdtfyTotal)
  362. .add(sjfyTotal)
  363. .add(wxzctxfyTotal)
  364. .add(zbtsfyysyfyTotal)
  365. .add(qtfyTotal)
  366. .add(wwfyTotal)
  367. this.costAmount = costAmount.toFixed(2);
  368. this.yffyPieOptions = this.getPieOptions("研发费用情况", [
  369. { value: Number(ryrgfyTotal), name: "人员人工费用" },
  370. { value: Number(zjtrfyTotal), name: "直接投入费用" },
  371. { value: Number(zjfyycqdtfyTotal), name: "折旧费用与长期待摊费用" },
  372. { value: Number(wxzctxfyTotal), name: "无形资产摊销费用" },
  373. { value: Number(sjfyTotal), name: "设计费用" },
  374. { value: Number(zbtsfyysyfyTotal), name: "装备调试费用与试验费用" },
  375. { value: Number(wwfyTotal), name: "委托外部研究开发费用" },
  376. { value: Number(qtfyTotal), name: "其他费用" },
  377. ]);
  378. })
  379. },
  380. // 获取专利数据
  381. getZlListFunc() {
  382. getZlList(1, 99999).then(({ data }) => {
  383. let _zscqList = data.data.records;
  384. this.zscqTotal = _zscqList.length;
  385. // 授权数
  386. let sqListTotal = _zscqList.filter(item => item.flzt == '授权有效').length;
  387. this.zscqOpt = this.getPieOptions("", [
  388. { value: _zscqList.length - sqListTotal, name: "申请数" },
  389. { value: sqListTotal, name: "授权数" },
  390. ]);
  391. });
  392. },
  393. // 获取年度参研人员
  394. getCyPersonListFunc() {
  395. getCyPersonList(1, 99999, { yearAndMonth: this.currYear }).then(({ data }) => {
  396. let _personList = data.data.records;
  397. let yfPersonList = _personList.filter(item => item.personnelType == '研发人员');
  398. this.yfPersonZb = ((yfPersonList.length / _personList.length) * 100).toFixed(2);
  399. console.log(yfPersonList.length, _personList.length, yfPersonList.length / _personList.length)
  400. this.RD_personOpt = this.getPieOptions("", [
  401. { value: _personList.filter(item => item.situation == '全职').length, name: "全职" },
  402. { value: _personList.filter(item => item.situation == '非全职').length, name: "非全职" },
  403. ]);
  404. });
  405. },
  406. getPieOptions(title, seriesData) {
  407. let options = {
  408. title: {
  409. text: title,
  410. left: "center",
  411. show: false
  412. },
  413. tooltip: {
  414. trigger: "item",
  415. },
  416. legend: {
  417. orient: "vertical",
  418. top: "center",
  419. right: 0,
  420. textStyle: {
  421. rich: {
  422. a: {
  423. verticalAlign: "right",
  424. align: "left",
  425. width: 160,
  426. fontSize: 14,
  427. },
  428. num: {
  429. align: "right",
  430. fontSize: 14,
  431. color: "rgb(64, 158, 255)",
  432. },
  433. },
  434. },
  435. formatter: function (name) {
  436. let currItem = seriesData.find((item) => item.name === name);
  437. let str = "{a|" + name + "}{num|" + currItem.value + "}";
  438. return str;
  439. },
  440. },
  441. series: [
  442. {
  443. name: title,
  444. type: "pie",
  445. radius: "50%",
  446. radius: ["45%", "70%"],
  447. center: ["25%", "50%"],
  448. avoidLabelOverlap: false,
  449. label: {
  450. show: false,
  451. position: "center",
  452. },
  453. labelLine: {
  454. show: false,
  455. },
  456. data: seriesData,
  457. },
  458. ],
  459. };
  460. return options;
  461. },
  462. },
  463. };
  464. </script>
  465. <style lang="scss" scoped>
  466. .home-contain {
  467. min-height: calc(100vh - 50px);
  468. background-color: #eee;
  469. padding: 16px 18px;
  470. box-sizing: border-box;
  471. }
  472. .count {
  473. font-size: 20px;
  474. font-weight: 600;
  475. color: rgb(64, 158, 255);
  476. margin: 0 3px;
  477. }
  478. </style>