detailDep.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. <template>
  2. <section>
  3. <!--工具条-->
  4. <el-col :span="24" class="toolbar" style="padding-bottom: 0px;">
  5. <el-form :inline="true">
  6. <el-form-item>
  7. <el-button type="text" @click="backToList" icon="el-icon-back" class="back">返回</el-button>
  8. </el-form-item>
  9. <el-form-item class="divLine"></el-form-item>
  10. <el-form-item style="width: 500px">
  11. <!-- <div class="dipali"> -->
  12. <!-- <span class="workName">{{detailName}}</span> -->
  13. <el-cascader v-if="user.userNameNeedTranslate != '1'" v-model="departmentId" placeholder="请选择部门" style="width: 180px;margin-left:10px;" @change="getList"
  14. :options="option" :props="{ checkStrictly: true }" :show-all-levels="false"></el-cascader>
  15. <vueCascader v-if="user.userNameNeedTranslate == '1'" :size="'medium'" :widthStr="'180'" :clearable="true" :subject="option" :radios="true" :distinction="'1'" @vueCasader="vueCasader" :selectNameChuan="$t('qing-xuan-ze-bu-men')"></vueCascader>
  16. <!-- </div> -->
  17. </el-form-item>
  18. <el-form-item >
  19. <span style="color:#666;">时间段:{{startDate}}<span style="padding-left:5px;padding-right:5px;">至</span>{{endDate}}</span>
  20. </el-form-item>
  21. <el-form-item style="float:right;">
  22. <span style="font-size:18px;">部门成本:<span style="color:#20a0ff;">{{cost.toFixed(2)}}元</span></span>
  23. </el-form-item>
  24. </el-form>
  25. </el-col>
  26. <div id="clearfix" :style="'overflow-x: auto;width:100%;padding-bottom: 100px; position: relative; height:'+containerHeight+'px;'">
  27. <div id="container" :style="'height:' + tableHeight + 'px'"></div>
  28. </div>
  29. </section>
  30. </template>
  31. <script>
  32. import util from "../../common/js/util";
  33. // 引入自定义级联组件
  34. import vueCascader from "@/components/cascader.vue"
  35. export default {
  36. components: {
  37. vueCascader
  38. },
  39. data() {
  40. return {
  41. yAxisValue: localStorage.yAxisValue,
  42. startDate:null,
  43. endDate: null,
  44. detailId: this.$route.params.id,
  45. detailName: this.$route.params.name,
  46. user: JSON.parse(sessionStorage.getItem("user")),
  47. cost: 0,
  48. tableHeight: 0,
  49. echart: null,
  50. option: [],
  51. departmentId: [].concat(parseInt(this.$route.params.id)),
  52. };
  53. },
  54. methods: {
  55. //返回
  56. backToList() {
  57. if (this.startDate != null) {
  58. this.$router.push("/cost?startDate="+this.startDate+"&endDate="+this.endDate);
  59. } else {
  60. this.$router.push("/cost");
  61. }
  62. },
  63. // 获取部门列表
  64. getDepartment() {
  65. this.http.post( this.port.manage.depList, {},
  66. res => {
  67. if (res.code == "ok") {
  68. var list = res.data , array = [];
  69. // for(var i in list) {
  70. // if(list[i].id == this.detailId) {
  71. // array.push(list[i])
  72. // }
  73. // }
  74. this.option = this.changeArr(list);
  75. } else {
  76. this.$message({
  77. message: res.msg,
  78. type: "error"
  79. });
  80. }
  81. },
  82. error => {
  83. this.$message({
  84. message: error,
  85. type: "error"
  86. });
  87. });
  88. },
  89. // 修改数组
  90. changeArr(arr) {
  91. for (var i = 0; i < arr.length; i++) {
  92. if(arr[i].id != -1 && arr[i].id != 0) {
  93. if (arr[i].children != null && arr[i].children.length>0) {
  94. arr[i].children = this.changeArr(arr[i].children);
  95. }
  96. arr[i].id && (arr[i].value = arr[i].id);
  97. delete arr[i].id;
  98. }
  99. }
  100. for(var i in arr) {
  101. if(arr[i].id == -1 || arr[i].id == 0) {
  102. arr.splice(i,1)
  103. }
  104. }
  105. return arr;
  106. },
  107. //获取部门人员工时统计
  108. getList() {
  109. this.listLoading = true;
  110. this.http.post(this.port.project.userCost, {
  111. departmentId: this.departmentId[this.departmentId.length-1],
  112. startDate: this.startDate,
  113. endDate: this.endDate,
  114. },
  115. res => {
  116. this.listLoading = false;
  117. var _this = this;
  118. if (res.code == "ok") {
  119. //
  120. for(var i in res.data.list) {
  121. if(i>20) {
  122. this.widthHtval = +this.widthHtval + 40
  123. } else {
  124. this.widthHtval = document.body.clientWidth - 230
  125. }
  126. }
  127. if(this.user.userNameNeedTranslate == '1') {
  128. let dealWithList = []
  129. let list = res.data.list
  130. for(var i in list) {
  131. let obj = {}
  132. obj.type = 'userName'
  133. obj.id = list[i].name
  134. dealWithList.push(obj)
  135. }
  136. this.dealWithTranslationPlone(dealWithList, res)
  137. } else {
  138. this.renderingDiagram(res)
  139. }
  140. //
  141. } else {
  142. this.$message({
  143. message: res.msg,
  144. type: "error"
  145. });
  146. }
  147. },
  148. error => {
  149. this.listLoading = false;
  150. this.$message({
  151. message: error,
  152. type: "error"
  153. });
  154. });
  155. },
  156. dealWithTranslationPlone(items, obj) {
  157. if (WWOpenData.initCanvas) {
  158. WWOpenData.initCanvas()
  159. }
  160. const myFunOne = async () => {
  161. const result = await new Promise((resolve, reject) => {
  162. if(WWOpenData.prefetch) {
  163. WWOpenData.prefetch({ items }, (err, data) => {
  164. if (err) { return reject(err) }
  165. resolve(data)
  166. })
  167. }
  168. })
  169. for(var i in obj.data.list) {
  170. if(result.items[i]) {
  171. obj.data.list[i].name = result.items[i].data
  172. }
  173. }
  174. this.renderingDiagram(obj)
  175. }
  176. myFunOne()
  177. },
  178. // 渲染图表
  179. renderingDiagram (res) {
  180. var _this = this;
  181. var xList = [] , yList = [] , list = res.data.list, array = [] , series = [];
  182. if (list.length > 0) {
  183. this.cost = res.data.totalCostMoney;
  184. for(var i in list) {
  185. xList.push(list[i].name);
  186. var pro = list[i].project;
  187. for(var j in pro) {
  188. if(array.indexOf(pro[j].project) == -1) {
  189. array.push(pro[j].project)
  190. }
  191. }
  192. }
  193. for(var i in array) {
  194. yList.push(array[i]);
  195. var dataList = [];
  196. for(var j in list) {
  197. var curUser = list[j];
  198. var project = list[j].project;
  199. if(project.length != 0) {
  200. //找到当前用户对应的项目
  201. var findProject = project.filter(p=>p.project == array[i]);
  202. if (findProject.length > 0) {
  203. dataList.push({
  204. "value": this.yAxisValue==0?findProject[0].money:findProject[0].time,
  205. "cost": findProject[0].time,
  206. "money": findProject[0].money
  207. })
  208. } else {
  209. dataList.push({
  210. "value": 0,
  211. "cost": 0,
  212. "money": 0,
  213. })
  214. }
  215. } else {
  216. dataList.push({
  217. "value": 0,
  218. "cost": 0,
  219. "money": 0
  220. })
  221. }
  222. }
  223. series.push({
  224. name: array[i],
  225. type: 'bar',
  226. stack:'1',
  227. barMaxWidth: 30,
  228. data: dataList,
  229. })
  230. }
  231. var myChart = echarts.init(document.getElementById("container"));
  232. // 设置宽度
  233. myChart.resize({
  234. width: this.widthHtval
  235. })
  236. _this.myChart = myChart;
  237. var option = {
  238. // 工具箱
  239. legend: {
  240. x: 80,
  241. y: 10,
  242. data: yList
  243. },
  244. grid : {
  245. top : 80, //距离容器上边界40像素
  246. bottom: 35, //距离容器下边界30像素
  247. left: 150,
  248. right: 150
  249. },
  250. toolbox: {
  251. show: true,
  252. feature:{
  253. saveAsImage:{
  254. show:true
  255. },
  256. restore:{
  257. show:true
  258. },
  259. dataView:{
  260. show:true
  261. },
  262. dataZoom:{
  263. show:true
  264. },
  265. magicType:{
  266. type:['line','bar']
  267. }
  268. }
  269. },
  270. tooltip:{
  271. trigger:'axis',
  272. formatter: function (params,ticket,callback) {
  273. var totalTime = 0.0;
  274. for(var i in params) {
  275. totalTime += parseFloat(params[i].data.cost)
  276. }
  277. var res
  278. if(_this.user.userNameNeedTranslate != 1) {
  279. res = params[0].name + " 工时 : " + totalTime.toFixed(1)+"小时<br/>";
  280. } else {
  281. res = " 工时 : " + totalTime.toFixed(1)+"小时<br/>";
  282. }
  283. for(var i in params) {
  284. if (params[i].data.value > 0) {
  285. res += "<div style='margin-top:3px;font-size:12px;'><font color='#ddd'>项目名称:" + params[i].seriesName
  286. + "</font><br/>工作成本 : " + params[i].data.money
  287. + "元 <br/>工作时长"+" : " + params[i].data.cost + "小时</br></div>";
  288. }
  289. }
  290. return res;
  291. }
  292. },
  293. xAxis: {
  294. data: xList,
  295. axisLabel: {
  296. interval:0,rotate:20
  297. }
  298. },
  299. yAxis: [{
  300. type : 'value',
  301. axisLabel: {
  302. formatter:this.yAxisValue==0?'{value} (元)':'{value}(小时)'
  303. }
  304. }],
  305. series: series,
  306. };
  307. myChart.setOption(option, {notMerge: true});
  308. } else {
  309. this.$message({
  310. message: "暂无数据",
  311. type: "error"
  312. });
  313. }
  314. },
  315. // 左右滚动
  316. scrollFunction () {
  317. this.domObj = document.getElementById('clearfix') // 通过id获取要设置的div
  318. if (this.domObj.attachEvent) { // IE
  319. this.domObj.attachEvent('onmousewheel', this.mouseScroll)
  320. } else if (this.domObj.addEventListener) {
  321. this.domObj.addEventListener('DOMMouseScroll', this.mouseScroll, false)
  322. }
  323. this.domObj.onmousewheel = this.domObj.onmousewheel = this.mouseScroll
  324. },
  325. mouseScroll(event) { // google 浏览器下
  326. let detail = event.wheelDelta || event.detail
  327. let moveForwardStep = -1
  328. let moveBackStep = 1
  329. let step = 0
  330. step = detail > 0 ? moveForwardStep * 100 : moveBackStep * 100
  331. event.preventDefault() // 阻止浏览器默认事件
  332. this.domObj.scrollLeft = this.domObj.scrollLeft + step
  333. },
  334. // 自定义事件
  335. vueCasader(obj) {
  336. if(obj.distinction == 1) {
  337. let arr = []
  338. arr.push(obj.id)
  339. this.departmentId = arr
  340. this.getList()
  341. }
  342. }
  343. },
  344. created() {
  345. let height = window.innerHeight;
  346. this.tableHeight = height - 145;
  347. const that = this;
  348. window.onresize = function temp() {
  349. that.tableHeight = window.innerHeight - 145;
  350. };
  351. },
  352. mounted() {
  353. this.startDate = this.$route.query.startDate;
  354. this.endDate = this.$route.query.endDate;
  355. this.getDepartment();
  356. this.getList();
  357. var _this = this;
  358. window.addEventListener("resize", function() {
  359. _this.myChart.resize();
  360. });
  361. this.scrollFunction()
  362. }
  363. };
  364. </script>
  365. <style lang="scss" scoped>
  366. .toolbar {
  367. .el-form-item {
  368. font-size: 14px;
  369. vertical-align: middle;
  370. }
  371. .back {
  372. font-size: 16px;
  373. cursor: pointer;
  374. }
  375. .divLine {
  376. width: 2px;
  377. background: #c3c3c3;
  378. height: 100%;
  379. }
  380. .workName {
  381. color: #333;
  382. font-size: 18px;
  383. }
  384. .workHours {
  385. color: #20a0ff;
  386. font-size: 18px;
  387. }
  388. }
  389. #container {
  390. float: left;
  391. width: 100%;
  392. }
  393. .dipali {
  394. display: flex;
  395. width: 100%;
  396. }
  397. </style>
  398. <style lang="scss">
  399. </style>