project_gantt.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. {{ src/App.vue }}
  2. <template>
  3. <div class="container">
  4. <div class="gantt_head">
  5. <div class="head_RorX">
  6. <el-radio-group v-model="radio1" @change="selChange()" size="small" style="margin-right:9px">
  7. <el-radio-button label="按人员查看" value="renyuan"></el-radio-button>
  8. <el-radio-button label="按项目查看" value="xiangmu"></el-radio-button>
  9. <el-radio-button label="资源需求" value="demand"></el-radio-button>
  10. </el-radio-group>
  11. </div>
  12. <!-- 时间段筛选 -->
  13. <div class="head_date" v-if="isDataLoaded">
  14. <span>时间段</span>
  15. <el-date-picker
  16. style="margin-left:9px;width:18vw"
  17. size="small"
  18. v-model="valueDate"
  19. type="daterange"
  20. range-separator="至"
  21. start-placeholder="开始日期"
  22. end-placeholder="结束日期"
  23. value-format="yyyy-MM-dd"
  24. @change="dateupdata()">
  25. </el-date-picker>
  26. </div>
  27. <!-- 任务分组筛选 -->
  28. <div v-if="reqpar1" class="head_taskgroup">
  29. <span>任务分组</span>
  30. <el-select clearable filterable v-model="valuex2" placeholder="请选择" size="small" style="margin-left:9px;width:10vw" @change="taskgroupSel()">
  31. <el-option
  32. v-for="item in taskgroupList"
  33. :key="item.name"
  34. :label="item.name"
  35. :value="item.name"
  36. >
  37. </el-option>
  38. </el-select>
  39. </div>
  40. <!-- 人员/项目筛选 -->
  41. <div class="head_select">
  42. <span>{{(this.radio1 == "按人员查看" ? "人员" : "项目")}}</span>
  43. <el-select clearable filterable v-model="valuex" placeholder="请选择" size="small" style="margin-left:9px;width:10vw" @change="optupdata()">
  44. <el-option
  45. v-for="item in screenList"
  46. :key="item.id"
  47. :label="reqpar1 ? item.projectName : item.name"
  48. :value="item.id"
  49. >
  50. <span style="float: left;color: #8492a6;">{{ item.projectCode }}</span>
  51. <span style="float: right;font-size: 13px;margin-left: 20px">{{ item.projectName }}</span>
  52. </el-option>
  53. </el-select>
  54. </div>
  55. <!-- 资源需求导入/导出 -->
  56. <div class="head_files" v-if="!isDataLoaded">
  57. <el-link type="primary" style="margin-left:10px;float:left;" :underline="false" href="./upload/资源需求导入模板.xlsx" download="资源需求导入模板.xlsx">模板下载</el-link>
  58. <el-upload ref="upload" style="margin-left:10px;float:left;" action="#" :limit="1" :http-request="importProject" :show-file-list="false">
  59. <el-link type="primary" :underline="false" >导入需求</el-link>
  60. </el-upload>
  61. <el-link type="primary" style="margin-left:10px;float:left;" :underline="false" @click="exportProjectData" download="资源需求导出.xlsx">导出需求</el-link>
  62. </div>
  63. </div>
  64. <gantt v-if="isDataLoaded" ref="ganttTable1" class="left-container" :tasks="tasks"
  65. :stafforpro="radio1"
  66. :valueDate="valueDate"
  67. :key="updatakey1"></gantt>
  68. <div class="demand-container" v-if="!isDataLoaded">
  69. <el-table height="90%" :loading="demandListLoading" :data="demandList">
  70. <el-table-column label="项目编号" prop="projectCode" width="160"></el-table-column>
  71. <el-table-column label="项目名称" prop="projectName" min-width="240"></el-table-column>
  72. <el-table-column label="近七日活跃人员" prop="activeUsers" min-width="240"></el-table-column>
  73. <el-table-column label="人员需求" prop="membReq" min-width="280"></el-table-column>
  74. <el-table-column label="任务需求" prop="taskReq" min-width="280"></el-table-column>
  75. <el-table-column label="操作" width="120" align="center">
  76. <template slot-scope="scope">
  77. <el-button @click="demandEdit(scope.row)" size="small">修改</el-button>
  78. </template>
  79. </el-table-column>
  80. </el-table>
  81. <div class="poss">
  82. <el-pagination
  83. @size-change="handleSizeChange"
  84. @current-change="handleCurrentChange"
  85. :current-page="pageIndex"
  86. :page-sizes="[20, 50, 100, 200]"
  87. :page-size="20"
  88. layout="total, sizes, prev, pager, next"
  89. :total="total">
  90. </el-pagination>
  91. </div>
  92. <!-- 资源需求修改 -->
  93. <el-dialog v-if="demandEditDialog" width="500px" append-to-body :visible.sync="demandEditDialog" :title="'修改 - ' + editParameter.projectName">
  94. <el-form label-width="150">
  95. <el-form-item label="人员需求">
  96. <el-input style="width:350px" v-model="editParameter.membReq" clearable></el-input>
  97. </el-form-item>
  98. <el-form-item label="任务需求">
  99. <el-input style="width:350px" v-model="editParameter.taskReq" clearable></el-input>
  100. </el-form-item>
  101. </el-form>
  102. <div slot="footer" class="dialog-footer">
  103. <el-button type="default" @click="demandEditDialog = false">取消</el-button>
  104. <el-button type="primary" @click="demandEditSure" >确定</el-button>
  105. </div>
  106. </el-dialog>
  107. </div>
  108. </div>
  109. </template>
  110. <script>
  111. import { error } from 'dingtalk-jsapi';
  112. import Gantt from './gantt.vue';
  113. export default {
  114. name: 'project_gantt',
  115. components: {Gantt},
  116. data () {
  117. return {
  118. isDataLoaded:false,
  119. tasks: {
  120. data : [],
  121. links: []
  122. },
  123. tasks1: {links:[]},
  124. updatakey1: 1,
  125. updatakey2: -1,
  126. radio1:"按人员查看",
  127. valueDate:[],
  128. options:[{value:"选项1",label:"全部"},{value:"选项2",label:"人员1"}],
  129. valuex:'',
  130. screenList:[],
  131. // 请求参数
  132. reqpar1:0,
  133. reqpar2:[],
  134. demandListLoading: false,
  135. demandList: [],
  136. pageIndex: 1,
  137. pageSize: 20,
  138. demandEditDialog: false,
  139. editParameter: {},
  140. taskgroupList: [],
  141. valuex2: ''
  142. }
  143. },
  144. methods: {
  145. setGroup() {
  146. this.$refs.ganttTable1.setGroup();
  147. // this.$refs.ganttTable2.setGroup();
  148. },
  149. // 资源需求导出
  150. exportProjectData() {
  151. this.http.post('/project-requirement/exportData',{},
  152. res => {
  153. if (res.code == "ok") {
  154. let filePath = res.data;
  155. const a = document.createElement('a'); // 创建a标签
  156. a.setAttribute('download', '资源需求导出.xls');// download属性
  157. a.setAttribute('href', filePath);// href链接
  158. a.click(); //自执行点击事件
  159. a.remove();
  160. }
  161. },
  162. error => {
  163. this.$message({
  164. message: error,
  165. type: "error"
  166. });
  167. }
  168. );
  169. },
  170. // 资源需求导入
  171. importProject(item) {
  172. //首先判断文件类型
  173. let str = item.file.name.split(".");
  174. let format = str[str.length - 1];
  175. if (format != "xls" && format != "xlsx") {
  176. this.$message({
  177. message: "请选择.xls或.xlsx文件",
  178. type: "error"
  179. });
  180. } else {
  181. let formData = new FormData();
  182. formData.append("multipartFile", item.file);
  183. this.http.uploadFile('/project-requirement/importData', formData,
  184. res => {
  185. this.$refs.upload.clearFiles();
  186. if (res.code == "ok") {
  187. this.$message({
  188. message: "导入成功",
  189. type: "success"
  190. });
  191. this.getDemandList();
  192. } else {
  193. this.$message({
  194. message: res.msg,
  195. type: "error"
  196. });
  197. }
  198. },
  199. error => {
  200. this.$refs.upload.clearFiles();
  201. this.$message({
  202. message: error,
  203. type: "error"
  204. });
  205. });
  206. }
  207. },
  208. // 人员/项目切换
  209. selChange(){
  210. this.valuex = null
  211. // console.log("切换按钮",this.radio1);
  212. if (this.radio1 == "按人员查看") {
  213. this.isDataLoaded = true
  214. this.reqpar1 = 0
  215. this.getList()
  216. this.getScreen()
  217. }else if(this.radio1 == "按项目查看"){
  218. this.isDataLoaded = true
  219. this.reqpar1 = 1
  220. this.getList()
  221. this.getXmScreen()
  222. this.getTaskgroupList()
  223. }else {
  224. this.reqpar1 = 1
  225. this.isDataLoaded = false
  226. this.pageIndex = 1
  227. this.pageSize = 20
  228. this.valuex = ''
  229. this.valuex2 = ''
  230. this.getDemandList()
  231. this.getXmScreen()
  232. this.getTaskgroupList()
  233. }
  234. },
  235. // 时间段改变
  236. dateupdata(){
  237. this.reqpar2 = this.valueDate
  238. this.getList()
  239. },
  240. // 人员/项目筛选改变
  241. optupdata(){
  242. // console.log(this.valuex);
  243. if(this.isDataLoaded){
  244. this.getList()
  245. }else{
  246. this.getDemandList()
  247. }
  248. },
  249. // 任务分组筛选改变
  250. taskgroupSel(){
  251. // console.log(this.valuex2);
  252. if(this.isDataLoaded){
  253. this.getList()
  254. }else{
  255. this.getDemandList()
  256. }
  257. },
  258. handleSizeChange(val){
  259. this.pageSize = val
  260. this.getDemandList()
  261. },
  262. handleCurrentChange(val){
  263. this.pageIndex = val
  264. this.getDemandList()
  265. },
  266. // 资源需求修改
  267. demandEdit(row){
  268. this.demandEditDialog = true
  269. this.editParameter = JSON.parse(JSON.stringify(row))
  270. // console.log('edit',this.demandEditDialog);
  271. },
  272. demandEditSure(){
  273. this.http.post('/project-requirement/addOrMod',this.editParameter,
  274. res => {
  275. if(res.code == 'ok'){
  276. this.$message({
  277. message: '修改成功',
  278. type: 'success'
  279. })
  280. this.demandEditDialog = false
  281. this.getDemandList()
  282. }else {
  283. this.$message({
  284. message: res.msg,
  285. type: 'error'
  286. })
  287. }
  288. },err => {
  289. this.$message({
  290. message: err,
  291. type: 'error'
  292. })
  293. })
  294. },
  295. // 获取人员项目筛选列表
  296. getScreen(){
  297. this.http.get('/project/getMyUsers',
  298. res => {
  299. if (res.code == "ok") {
  300. this.screenList = res.data
  301. }else{
  302. this.$message({
  303. message: res.msg,
  304. type: "error"
  305. });
  306. }
  307. },
  308. error => {
  309. this.$message({
  310. message : error,
  311. type : "error"
  312. })
  313. }
  314. )
  315. },
  316. getXmScreen(){
  317. this.http.get('/project/getProjectList',
  318. res => {
  319. if (res.code == "ok") {
  320. this.screenList = res.data
  321. // console.log("screen",this.screenList);
  322. }else{
  323. this.$message({
  324. message: res.msg,
  325. type: "error"
  326. });
  327. }
  328. },
  329. error => {
  330. this.$message({
  331. message : error,
  332. type : "error"
  333. })
  334. }
  335. )
  336. },
  337. // 获取任务分组筛选列表
  338. getTaskgroupList(){
  339. this.http.post('/task-group/getGroupNames',{},
  340. res => {
  341. if(res.code == 'ok'){
  342. this.taskgroupList = res.data
  343. }else {
  344. this.$message({
  345. message: res.msg,
  346. type: 'error'
  347. })
  348. }
  349. },err => {
  350. this.$message({
  351. message: err,
  352. type: 'error'
  353. })
  354. })
  355. },
  356. // 获取甘特图数据
  357. getList() {
  358. let getlistcs = {type : this.reqpar1 , startDate : this.reqpar2[0] , endDate : this.reqpar2[1]}
  359. if(this.reqpar1) {
  360. if(this.valuex != ''){
  361. getlistcs.projectId = this.valuex
  362. }
  363. if(this.valuex2 != ''){
  364. getlistcs.groupName = this.valuex2
  365. }
  366. }else {
  367. if(this.valuex != ''){
  368. getlistcs.userId = this.valuex
  369. }
  370. }
  371. this.http.post('/project/getGanttData', getlistcs ,
  372. res => {
  373. if (res.code == "ok") {
  374. for(var i in res.data) {
  375. if(res.data[i].id.indexOf('出差') != '-1') {
  376. res.data[i].color = '#E6A23C'
  377. }
  378. if(res.data[i].id.indexOf('请假') != '-1') {
  379. res.data[i].color = '#F56C6C'
  380. }
  381. }
  382. this.tasks = {data:res.data};
  383. for(let i in this.tasks.data){
  384. if(this.tasks.data[i].time == 0){
  385. delete this.tasks.data[i].start_date
  386. delete this.tasks.data[i].end_date
  387. this.tasks.data[i].type = 'milestone'
  388. }
  389. }
  390. this.$nextTick(()=>{
  391. this.updatakey1 += 1
  392. })
  393. } else {
  394. this.$message({
  395. message: res.msg,
  396. type: "error"
  397. });
  398. }
  399. },
  400. error => {
  401. this.$message({
  402. message: error,
  403. type: "error"
  404. });
  405. }
  406. );
  407. },
  408. // 获取资源需求列表
  409. getDemandList(){
  410. let parameter = {
  411. pageIndex: this.pageIndex,
  412. pageSize: this.pageSize,
  413. }
  414. if(this.valuex != ''){
  415. parameter.projectId = this.valuex
  416. }
  417. if(this.valuex2 != ''){
  418. parameter.groupName = this.valuex2
  419. }
  420. this.demandListLoading = true
  421. this.http.post('/project-requirement/listByPage',parameter,
  422. res => {
  423. if(res.code == 'ok'){
  424. this.demandListLoading = false
  425. this.total = res.data.total
  426. this.demandList = res.data.records
  427. }else {
  428. this.demandListLoading = false
  429. this.$message({
  430. message: res.msg,
  431. type: 'error'
  432. })
  433. }
  434. },err => {
  435. this.demandListLoading = false
  436. this.$message({
  437. message: err,
  438. type: 'error'
  439. })
  440. })
  441. },
  442. // tasksEdit(){
  443. // let etasks = JSON.parse(JSON.stringify(this.tasks.data))
  444. // for(let i=0;i<etasks.length;i++){
  445. // if(etasks[i].parent != null){
  446. // let edate = new Date(etasks[i].end_date)
  447. // edate = new Date(edate.setDate(edate.getDate() + 1))
  448. // let edatemonth = edate.getMonth() + 1
  449. // let edateday = edate.getDate()
  450. // edate = edate.getFullYear() + '-' + (edatemonth < 10 ? '0' + edatemonth : edatemonth) + '-' + (edateday < 10 ? '0' + edateday : edateday)
  451. // etasks[i].end_date = edate
  452. // }
  453. // }
  454. // this.tasks = {data:etasks}
  455. // }
  456. },
  457. mounted: function () {
  458. let nowdate = new Date()
  459. let nowmonth = nowdate.getMonth() + 1
  460. let startdate = nowdate.getFullYear() + "-" + (nowmonth < 10 ? "0" + nowmonth : nowmonth) + "-" + (nowdate.getDate() < 10 ? "0" + nowdate.getDate() : nowdate.getDate())
  461. let udate = new Date(nowdate.getFullYear(),nowdate.getMonth(),nowdate.getDate() + 31)
  462. let endmonth = udate.getMonth() + 1
  463. let enddate = udate.getFullYear() + "-" + (endmonth < 10 ? "0" + endmonth : endmonth) + "-" + (udate.getDate() < 10 ? "0" + udate.getDate() : udate.getDate())
  464. this.valueDate = [startdate,enddate]
  465. this.reqpar2 = this.valueDate
  466. // console.log("date",this.valueDate);
  467. this.getList();
  468. this.getScreen()
  469. // this.tasks1 = this.tasks
  470. this.isDataLoaded = true
  471. }
  472. }
  473. </script>
  474. <style>
  475. /* html, body {
  476. height: 100%;
  477. margin: 0;
  478. padding: 0;
  479. } */
  480. .container {
  481. height: 100%;
  482. width: 100%;
  483. }
  484. .left-container {
  485. overflow: hidden;
  486. position: relative;
  487. height: 90%;
  488. }
  489. .demand-container{
  490. overflow: hidden;
  491. position: relative;
  492. height: 92%;
  493. }
  494. .gantt_head{
  495. width: 100%;
  496. height: 80px;
  497. display: flex;
  498. justify-content: space-between;
  499. align-items: center;
  500. }
  501. .gantt_head .head_RorX{
  502. width: 22vw;
  503. }
  504. .gantt_head .head_date{
  505. width: 24vw;
  506. }
  507. .gantt_head .head_taskgroup{
  508. width: 16vw;
  509. }
  510. .gantt_head .head_select{
  511. width: 15vw;
  512. }
  513. .gantt_head .head_files{
  514. width: 17vw;
  515. }
  516. .poss {
  517. height: 8%;
  518. float: right;
  519. padding-top: 15px;
  520. }
  521. </style>