earning.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. <template>
  2. <div :style="'padding:10px;background:#f7f7f7;min-height:'+tableHeight+'px;'">
  3. <div style="margin: 0 auto;width:1120px;">
  4. <el-row :gutter="10">
  5. <el-col :span="24">
  6. <div class="box" style="height:650px;">
  7. <div >
  8. <div class="lableTxt">项目利润快照</div>
  9. <el-divider></el-divider>
  10. <!--利润率列表-->
  11. <el-table :data="list" highlight-current-row v-loading="listLoading" max-height="300" style="width: 100%;">
  12. <el-table-column prop="indate" label="校准日期" ></el-table-column>
  13. <el-table-column prop="profitA" >
  14. <template slot="header">
  15. <span>利润率A</span>
  16. <el-popover placement="top" width="250" trigger="hover" content="利润率A = (项目金额 - 总成本)/项目金额">
  17. <i class="el-icon-question" slot="reference" />
  18. </el-popover>
  19. </template>
  20. <template slot-scope="scope">
  21. {{scope.row.profitA}}%
  22. </template>
  23. </el-table-column>
  24. <el-table-column prop="profitB" label="利润率B" >
  25. <template slot="header">
  26. <span>利润率B</span>
  27. <el-popover placement="top" width="350" trigger="hover" content="利润率B = (项目金额 - 总成本 - 预留金额1)/项目金额">
  28. <i class="el-icon-question" slot="reference" />
  29. </el-popover>
  30. </template>
  31. <template slot-scope="scope">
  32. {{scope.row.profitB}}%
  33. </template>
  34. </el-table-column>
  35. <el-table-column prop="profitC" label="利润率C" >
  36. <template slot="header">
  37. <span>利润率C</span>
  38. <el-popover placement="top" width="430" trigger="hover" content="利润率C = (项目金额 - 总成本 - 预留金额1 - 预留金额2)/项目金额">
  39. <i class="el-icon-question" slot="reference" />
  40. </el-popover>
  41. </template>
  42. <template slot-scope="scope">
  43. {{scope.row.profitC}}%
  44. </template>
  45. </el-table-column>
  46. <el-table-column prop="contractAmount" label="项目金额" ></el-table-column>
  47. <el-table-column label="基线成本" >
  48. <el-table-column prop="baseMan" label="人员成本">
  49. <template slot-scope="scope">
  50. ¥{{scope.row.baseMan | numberToCurrency}}
  51. </template>
  52. </el-table-column>
  53. <el-table-column prop="baseFee" label="费用">
  54. <template slot-scope="scope">
  55. ¥{{scope.row.baseFee | numberToCurrency}}
  56. </template>
  57. </el-table-column>
  58. <el-table-column prop="baseOutsourcing" label="外包费用">
  59. <template slot-scope="scope">
  60. ¥{{scope.row.baseOutsourcing | numberToCurrency}}
  61. </template>
  62. </el-table-column>
  63. <el-table-column prop="baseRisk1" label="风险预留金额1" width="150">
  64. <template slot-scope="scope">
  65. ¥{{scope.row.baseRisk1 | numberToCurrency}}
  66. </template>
  67. </el-table-column>
  68. <el-table-column prop="baseRisk2" label="风险预留金额2" width="150">
  69. <template slot-scope="scope">
  70. ¥{{scope.row.baseRisk2 | numberToCurrency}}
  71. </template>
  72. </el-table-column>
  73. </el-table-column>
  74. </el-table>
  75. <el-divider ></el-divider>
  76. <!--图形显示 -->
  77. <div id="chartPanel" style="height: 300px;width: 1100px;"></div>
  78. </div>
  79. </div>
  80. </el-col>
  81. </el-row>
  82. </div>
  83. </div>
  84. </template>
  85. <style scoped>
  86. #executorPanel {
  87. display: inline-block;
  88. width: 100%;
  89. }
  90. .el-divider--horizontal {
  91. margin: 10px 0;
  92. height: 0.5px;
  93. }
  94. .box {
  95. background:#fff;border: 1px solid #eeeeee;border-radius:5px;padding:10px;
  96. height:303.7px;margin-top:10px;
  97. }
  98. .info span {
  99. color:#303133;
  100. }
  101. .gray_label {
  102. color:#999 !important;
  103. }
  104. .el-row {
  105. margin-top:10px;
  106. }
  107. .lableTxt {
  108. color:#666;
  109. }
  110. </style>
  111. <script>
  112. import util from "../../common/js/util";
  113. export default {
  114. data() {
  115. return {
  116. yList3:[],
  117. yList2:[],
  118. yList1:[],
  119. xList:[],
  120. list:[],
  121. costChart:null,
  122. stagesChart: null,
  123. executorChart: null,
  124. pVisible:false,
  125. taskSum:{},
  126. users:[],
  127. importanceList:[{id:1,label:'一般'},{id:2,label:'紧急'},{id:3,label:'重要'},{id:4,label:'重要且紧急'}],
  128. //1-一般,2-紧急,3-重要,4-重要且紧急
  129. levelTxt:["全部","一般","紧急","重要","重要且紧急"],
  130. //1-进行中,2-已完成,3-已撤销
  131. statusTxt: ["全部","进行中","已完成","已撤销"],
  132. addFolderDialog: false,
  133. upLoading:false,
  134. user: JSON.parse(sessionStorage.getItem("user")),
  135. addLoading: false,
  136. curProjectId:null,
  137. title: "",
  138. };
  139. },
  140. filters: {
  141. numberToCurrency(value) {
  142. if (!value) return '0.00'
  143. value = value.toFixed(2)
  144. const intPart = Math.trunc(value)
  145. const intPartFormat = intPart.toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,')
  146. let floatPart = '.00'
  147. const valueArray = value.toString().split('.')
  148. if (valueArray.length === 2) { // 有小数部分
  149. floatPart = valueArray[1].toString() // 取得小数部分
  150. return intPartFormat + '.' + floatPart
  151. }
  152. return intPartFormat + floatPart
  153. }
  154. },
  155. methods: {
  156. getProfitSnapshot() {
  157. let _this = this;
  158. this.http.post('/earning-snapshot/list', {projectId: this.curProjectId},
  159. res => {
  160. if (res.code == "ok") {
  161. var list = JSON.parse(JSON.stringify(res.data)).reverse();
  162. _this.list = res.data;
  163. for (var m=0;m<list.length; m++) {
  164. this.xList.push(list[m].indate);
  165. this.yList1.push(list[m].profitA);
  166. this.yList2.push(list[m].profitB);
  167. this.yList3.push(list[m].profitC);
  168. }
  169. //图表展示
  170. var myChart = echarts.init(document.getElementById("chartPanel"));
  171. myChart.setOption({
  172. title: {
  173. textStyle: {
  174. color: "#666666",
  175.   fontSize: 18,
  176. fontWeight: 'normal',
  177.  },
  178.   text: list.length == 0?"暂无数据":"利润率趋势图",
  179.   left: list.length == 0?"center":"left",
  180.   top: list.length == 0?"center":"left"
  181. },
  182. toolbox: {
  183. show: true,
  184. feature:{
  185. saveAsImage:{
  186. show:true
  187. },
  188. }
  189. },
  190. tooltip:{
  191. trigger: 'axis'
  192. },
  193. legend: {
  194. data: ['利润率A', '利润率B', '利润率C']
  195. },
  196. grid: {
  197. left: '3%',
  198. right: '4%',
  199. bottom: '3%',
  200. containLabel: true
  201. },
  202. xAxis: {
  203. type: 'category',
  204. boundaryGap: false,
  205. data: this.xList
  206. },
  207. yAxis: {
  208. type: 'value'
  209. },
  210. series : [
  211. {
  212. name: '利润率A',
  213. type: 'line',
  214. stack: '百分比',
  215. data: this.yList1
  216. },
  217. {
  218. name: '利润率B',
  219. type: 'line',
  220. stack: '百分比',
  221. data: this.yList2
  222. },
  223. {
  224. name: '利润率C',
  225. type: 'line',
  226. stack: '百分比',
  227. data: this.yList3
  228. },
  229. ]
  230. })
  231. } else {
  232. this.$message({
  233. message: res.msg,
  234. type: "error"
  235. });
  236. }
  237. },
  238. error => {
  239. this.$message({
  240. message: error,
  241. type: "error"
  242. });
  243. });
  244. },
  245. getStagesPanel(){
  246. let _this = this;
  247. this.http.post('/task/getStagesPanel', {projectId: this.curProjectId},
  248. res => {
  249. if (res.code == "ok") {
  250. var list = res.data;
  251. var myChart = echarts.init(document.getElementById("stagesPanel"));
  252. _this.stagesChart = myChart;
  253. myChart.setOption({
  254. title: {
  255. show:list.length == 0,
  256. textStyle: {
  257. color: "#666666",
  258.   fontSize: 18,
  259. fontWeight: 'normal',
  260.  },
  261.   text: list.length == 0?"暂无数据":"任务列表统计",
  262.   left: "center",
  263.   top: "center"
  264. },
  265. toolbox: {
  266. show: true,
  267. feature:{
  268. saveAsImage:{
  269. show:true
  270. },
  271. }
  272. },
  273. tooltip:{
  274. trigger:'item',
  275. formatter: "{b}<br/>任务数:{c} ({d}%)",
  276. },
  277. series : [
  278. {
  279. name: '任务列表',
  280. type: 'pie',
  281. radius: '55%',
  282. data:list
  283. }
  284. ]
  285. })
  286. } else {
  287. this.$message({
  288. message: res.msg,
  289. type: "error"
  290. });
  291. }
  292. },
  293. error => {
  294. this.$message({
  295. message: error,
  296. type: "error"
  297. });
  298. });
  299. },
  300. getExecutorPanel(){
  301. let _this = this;
  302. this.http.post('/task/getExecutorPanel', {projectId: this.curProjectId},
  303. res => {
  304. if (res.code == "ok") {
  305. var xList = [], yList = [], list = res.data;
  306. for(var i in list) {
  307. xList.push(list[i].executorName);
  308. yList.push({
  309. "value": list[i].taskCount,
  310. "id": list[i].executorId
  311. });
  312. }
  313. var myChart = echarts.init(document.getElementById("executorPanel"));
  314. _this.executorChart = myChart;
  315. var option = {
  316. title: {
  317. show:list.length == 0,
  318. textStyle: {
  319. color: "#666666",
  320.   fontSize: 18,
  321. fontWeight: 'normal',
  322.  },
  323.   text: list.length == 0?"暂无数据":"执行人分配图",
  324.   left: "center",
  325.   top: "center"
  326. },
  327. toolbox: {
  328. show: true,
  329. feature:{
  330. saveAsImage:{
  331. show:true
  332. },
  333. restore:{
  334. show:true
  335. },
  336. magicType:{
  337. type:['line','bar']
  338. },
  339. }
  340. },
  341. tooltip:{
  342. trigger:'axis',
  343. formatter: function (params,ticket,callback) {
  344. var res = params[0].name + ""+" : " + params[0].data.value
  345. + "个";
  346. _this.params = params;
  347. return res;
  348. }
  349. },
  350. xAxis: {
  351. data: xList,
  352. axisLabel: {
  353. interval:0,rotate:20
  354. }
  355. },
  356. yAxis: [{
  357. type : 'value',
  358. axisLabel: {
  359. formatter:'{value} '
  360. }
  361. }],
  362. series: [{
  363. name: '任务数量(个)',
  364. type: 'bar',
  365. barMaxWidth: 30,
  366. data: yList,
  367. }]
  368. };
  369. myChart.setOption(option);
  370. console.log('===这是完成');
  371. } else {
  372. this.$message({
  373. message: res.msg,
  374. type: "error"
  375. });
  376. }
  377. },
  378. error => {
  379. this.$message({
  380. message: error,
  381. type: "error"
  382. });
  383. });
  384. },
  385. getProjectTaskSum() {
  386. this.http.post('/project/taskSum', {
  387. id: this.curProjectId
  388. },
  389. res => {
  390. if (res.code == "ok") {
  391. this.taskSum = res.data;
  392. } else {
  393. this.$message({
  394. message: res.msg,
  395. type: "error"
  396. });
  397. }
  398. },
  399. error => {
  400. this.$message({
  401. message: error,
  402. type: "error"
  403. });
  404. });
  405. },
  406. refreshPage() {
  407. this.curProjectId = parseInt(this.$route.params.id);
  408. this.getProfitSnapshot();
  409. }
  410. },
  411. created() {
  412. console.log('created===');
  413. let height = window.innerHeight;
  414. this.tableHeight = height - 160;
  415. const that = this;
  416. window.onresize = function temp() {
  417. that.tableHeight = window.innerHeight - 160;
  418. };
  419. },
  420. mounted() {
  421. console.log('=========图表mounted===');
  422. this.curProjectId = parseInt(this.$route.params.id);
  423. var _this = this;
  424. window.addEventListener("resize", function() {
  425. _this.executorChart.resize();
  426. _this.stagesChart.resize();
  427. _this.costChart.resize();
  428. });
  429. this.getProfitSnapshot(); // 调用图表方法
  430. }
  431. };
  432. </script>
  433. <style scoped>
  434. </style>