details.vue 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669
  1. <template>
  2. <div class="ele-body el-form-box">
  3. <el-card class="card_2_box">
  4. <div class="card_2_box_content">
  5. <ele-split-layout
  6. :left-style="{
  7. overflow: 'hidden',
  8. width: '100%',
  9. paddingLeft: '10px',
  10. }"
  11. :max-size="300"
  12. :min-size="0"
  13. :resizable="true"
  14. :responsive="true"
  15. :right-style="{ overflow: 'hidden' }"
  16. allow-collapse
  17. width="210px"
  18. >
  19. <div class="el_tree_box">
  20. <!-- <el-tabs-->
  21. <!-- v-model="treeActiveName"-->
  22. <!-- class="tab-box_1"-->
  23. <!-- type="border-card">-->
  24. <!-- </el-tabs>-->
  25. <el-input
  26. v-model="filterText"
  27. placeholder="在结构中查找"
  28. size="small"
  29. clearable
  30. style="margin-bottom: 3px"
  31. >
  32. </el-input>
  33. <el-tree
  34. class="project_tree"
  35. ref="treeRef"
  36. :data="treeList"
  37. :default-expanded-keys="currentNodeData && currentNodeData.id ? [currentNodeData.id] : []"
  38. :expand-on-click-node="false"
  39. :highlight-current="true"
  40. :indent='0'
  41. :props="defaultProps"
  42. node-key="id"
  43. style="height: 100%"
  44. :filter-node-method="filterNode"
  45. @node-click="handleNodeClick"
  46. >
  47. <div style="width: 100%;height: 100%;display: flex;" slot-scope="{ node, data }"
  48. @contextmenu.stop="(e)=>showRightMenu(e,node,data)">
  49. <span class="custom-tree-node">
  50. <span :style="fontSize(node,data)" class="label_img" :class="getIconClass(node,data)"></span>
  51. <span :style="fontSize(node,data)" class="label">{{ node.label }}</span>
  52. </span>
  53. <vue-context-menu :transferIndex="0" :class="'vue-contextmenuName-'+data.id+'_'+data.name+'_rightMenu'"
  54. v-if="data.id+'_'+data.name+'_rightMenu'== contextMenuData.menuName"
  55. :contextMenuData="contextMenuData"
  56. @updateProject="()=> handleUpdateProject(node,data,'edit')"
  57. @removeBom="()=> bomRemove(node,data)"
  58. @stageRemove="()=> stageRemove(node,data)"
  59. @addBOM="()=> addOrEditBOM('add',node,data)"
  60. @editBOM="()=> addOrEditBOM('edit',node,data)"
  61. @addPlan="()=> handleAddPlan('add',node,data)"
  62. @editPlan="()=> handleAddPlan('edit',node,data,'plan')"
  63. @addTask="()=> handleAddTask('add',node,data)"
  64. @handleTermination="()=> handleStatus(projectsTerminationAPI,'确定终止该项目吗?',node,data)"
  65. @handlePause="()=> handleStatus(projectsPauseAPI,'确定暂停该项目吗',node,data)"
  66. @handleStartup="()=> handleStatus(projectsStartupAPI,'确定启动该项目吗',node,data)"
  67. @handleFinish="()=> handleStatus(projectsFinishAPI,'确定完成该项目吗',node,data)"
  68. @handleBomTermination="()=> handleStatus(projectsBomTerminationAPI,'确定终止该BOM吗?',node,data)"
  69. @handleBomPause="()=> handleStatus(projectsBomPauseAPI,'确定暂停该BOM吗',node,data)"
  70. @handleBomStartup="()=> handleStatus(projectsBomStartupAPI,'确定启动该BOM吗',node,data)"
  71. @handleBomFinish="()=> handleStatus(projectsBomFinishAPI,'确定完成该BOM吗',node,data)"
  72. @handleStageTermination="()=> handleStatus(projectsStageTerminationAPI,'确定终止该项目阶段吗?',node,data)"
  73. @handleStagePause="()=> handleStatus(projectsStagePauseAPI,'确定暂停该项目阶段吗',node,data)"
  74. @handleStageStartup="()=> handleStatus(projectsStageStartupAPI,'确定启动该项目阶段吗',node,data)"
  75. @handleStageFinish="()=> handleStatus(projectsStageFinishAPI,'确定完成该项目阶段吗',node,data)"
  76. ></vue-context-menu>
  77. <!-- <span :class="getIconClass(node,data)">{{ node.label }}</span>-->
  78. </div>
  79. </el-tree>
  80. </div>
  81. <template v-slot:content>
  82. <ele-split-layout
  83. :left-style="{
  84. overflow: 'hidden',
  85. width: '100%' }"
  86. :vertical="true"
  87. :max-size="500"
  88. :min-size="1"
  89. :resizable="true"
  90. :responsive="true"
  91. width="440px"
  92. :right-style="{ overflow: 'hidden' }"
  93. allow-collapse
  94. >
  95. <div class="card_2_layout_content">
  96. <!-- <div class="card_2_1_box">-->
  97. <!-- -->
  98. <!-- </div>-->
  99. <dv-border-box-12 class="card_2_1_box" :color="['rgb(255,255,255)', 'rgb(255,255,255)']"
  100. :backgroundColor="'rgb(255,255,255)'">
  101. <div class="card_2_1_box_div_1">
  102. <el-steps :active="active" finish-status="success" simple>
  103. <el-step v-for="(item,index) in planStepList" :key="index" :title="item"></el-step>
  104. </el-steps>
  105. </div>
  106. <div class="card_2_1_box_div_2">
  107. <dv-percent-pond
  108. :title="(dialogForm.speedPercent||0)+'%'"
  109. :config="{value:dialogForm.speedPercent||0, localGradient: true,textColor:'rgb(0,185,253)',formatter:''}"
  110. style="width:98%;height:55%;"/>
  111. <!-- <el-progress :stroke-width="30" text-color="#606266" :text-inside="false"-->
  112. <!-- :percentage="dialogForm.speedPercent||0"-->
  113. <!-- :color="customColorMethod"></el-progress>-->
  114. </div>
  115. </dv-border-box-12>
  116. <el-tabs
  117. v-model="activeName"
  118. class="tab-box_1"
  119. @tab-click="handleTabs1"
  120. type="border-card"
  121. >
  122. <el-tab-pane label="基本信息" name="基本信息">
  123. <plan-form ref="planForm" dialog-type="view"
  124. :dialogForm="dialogForm" :deptList="deptList"
  125. :deptTreeList="deptTreeList"></plan-form>
  126. </el-tab-pane>
  127. <el-tab-pane label="子计划以及节点" name="子计划以及节点" class="el-tab-pane-tree">
  128. <ele-pro-table
  129. class="el-table"
  130. ref="table"
  131. row-key="id"
  132. :columns="columns"
  133. :datasource="planAndTaskTree"
  134. height="100%"
  135. @row-click="handleTableNodeClick"
  136. @row-contextmenu="showTableRightMenu"
  137. :toolkit="[]"
  138. :default-expand-all="true"
  139. cache-key="project-initiationTable"
  140. :tree-props="{children: 'children'}"
  141. :need-page="false"
  142. :indent="0">
  143. <template v-slot:name="{ row }">
  144. <span v-if="!row.children.length&&row.level==2"
  145. style="margin-left: 25px;display: inline-block"></span>
  146. <span class="dot" v-if="row.milepost=='1'"></span>
  147. <span class="name"> {{ row.name }}</span>
  148. </template>
  149. <template v-slot:type="{ row }">
  150. <el-tag v-if="row.type==0" type="info">计划</el-tag>
  151. <el-tag v-else-if="row.type==1" type="info">计划节点</el-tag>
  152. <el-tag v-else-if="row.type==2" type="info">任务</el-tag>
  153. </template>
  154. <template v-slot:speedPercent="{ row }">
  155. <el-progress style="padding: 0 5px" :stroke-width="20" text-color="#606266" :text-inside="true"
  156. :percentage="row.speedPercent||0"
  157. :color="customColorMethod"></el-progress>
  158. <!-- planFinishAPI,
  159. planPauseAPI,
  160. planStartupAPI,
  161. planTerminationAPI,
  162. planStageFinishAPI,
  163. planStagePauseAPI,
  164. planStageStartupAPI,
  165. planStageTerminationAPI,-->
  166. <vue-context-menu :transferIndex="0"
  167. :class="'vue-contextmenuName-'+row.name "
  168. v-if="row.name== contextTableMenuData.menuName"
  169. :contextMenuData="contextTableMenuData"
  170. @addPlan="()=> handleAddPlan('add','',row,'plan')"
  171. @editPlan="()=> handleAddPlan('edit','',row,'plan')"
  172. @removePlan="()=> handleRemovePlan([row.id])"
  173. @terminationPlan="()=> handleStatus(planTerminationAPI,'确定终止该计划吗?','',row)"
  174. @pausePlan="()=> handleStatus(planPauseAPI,'确定暂停该计划吗','',row)"
  175. @startupPlan="()=> handleStatus(planStartupAPI,'确定启动该计划吗','',row)"
  176. @finishPlan="()=> handleStatus(planFinishAPI,'确定完成该计划吗','',row)"
  177. @terminationPlanStage="()=> handleStatus(planStageTerminationAPI,'确定终止该计划节点吗?','',row)"
  178. @pausePlanStage="()=> handleStatus(planStagePauseAPI,'确定暂停该计划节点吗','',row)"
  179. @startupPlanStage="()=> handleStatus(planStageStartupAPI,'确定启动该计划节点吗','',row)"
  180. @finishPlanStage="()=> handleStatus(planStageFinishAPI,'确定完成该计划节点吗','',row)"
  181. @addTask="()=> handleAddTask('add','',row,'plan')"
  182. @updateTask="()=> handleAddTask('edit','',{...row,type:2},'plan')"
  183. @removeTask="()=> handleRemoveTask([row.id])"
  184. @startTask="()=> handleStartTask(row,1,'是否确定执行该任务?')"
  185. @finishTask="()=> handleStartTask(row,3,'是否确定报工该任务?')"
  186. @pauseTask="()=> handleStartTask(row,2,'是否确定暂停该任务?')"
  187. @terminationTask="()=> handleStartTask(row,4,'是否确定终止该任务?')"
  188. @handleTransfer="()=> handleTransfer(row)"
  189. @handleSubmitDeliverables="()=> handleSubmitDeliverables(row)"
  190. ></vue-context-menu>
  191. </template>
  192. </ele-pro-table>
  193. </el-tab-pane>
  194. <el-tab-pane label="任务" name="任务" class="el-tab-pane-tree">
  195. <ele-pro-table
  196. class="el-table"
  197. ref="table"
  198. row-key="id"
  199. :columns="columns"
  200. :datasource="taskTree"
  201. height="100%"
  202. :max-height="500"
  203. @row-click="(row)=>handleTableNodeClick({...row,type:2})"
  204. @row-contextmenu="(row, column, event)=>showTableRightMenu({...row,type:2}, column, event,'任务')"
  205. :toolkit="[]"
  206. :default-expand-all="true"
  207. cache-key="project-initiationTable"
  208. :tree-props="{children: 'children'}"
  209. :need-page="false"
  210. :indent="0">
  211. <template v-slot:name="{ row }">
  212. <span v-if="!row.children.length&&row.level==1"
  213. style="margin-left: 25px;display: inline-block"></span>
  214. <span class="dot" v-if="row.milepost=='1'"></span>
  215. <span class="name"> {{ row.name }}</span>
  216. </template>
  217. <template v-slot:type="{ row }">
  218. <el-tag type="info">任务</el-tag>
  219. </template>
  220. <template v-slot:speedPercent="{ row }">
  221. <el-progress style="padding: 0 5px" :stroke-width="20" text-color="#606266" :text-inside="true"
  222. :percentage="row.speedPercent||0"
  223. :color="customColorMethod"></el-progress>
  224. <vue-context-menu :transferIndex="0"
  225. :class="'vue-contextmenuName-任务'+row.name "
  226. v-if="'任务'+row.name== contextTableMenuData.menuName"
  227. :contextMenuData="contextTableMenuData"
  228. @addTask="()=> handleAddTask('add','',{...row,type:2},'plan')"
  229. @updateTask="()=> handleAddTask('edit','',{...row,type:2},'plan')"
  230. @removeTask="()=> handleRemoveTask([row.id])"
  231. @startTask="()=> handleStartTask(row,1,'是否确定执行该任务?')"
  232. @finishTask="()=> handleStartTask(row,3,'是否确定报工该任务?')"
  233. @pauseTask="()=> handleStartTask(row,2,'是否确定暂停该任务?')"
  234. @terminationTask="()=> handleStartTask(row,4,'是否确定终止该任务?')"
  235. @handleTransfer="()=> handleTransfer(row)"
  236. @handleSubmitDeliverables="()=> handleSubmitDeliverables(row)"
  237. ></vue-context-menu>
  238. </template>
  239. </ele-pro-table>
  240. </el-tab-pane>
  241. <!-- <el-tab-pane label="项目团队" name="项目团队" class="el-tab-pane-tree">-->
  242. <!-- <team-info-table ref="deliverablesInfoTable" dialog-type="view"-->
  243. <!-- :dialogForm="teamForm"></team-info-table>-->
  244. <!-- </el-tab-pane>-->
  245. <!-- <el-tab-pane label="项目看板" name="项目看板" class="el-tab-pane-tree">-->
  246. <!-- </el-tab-pane>-->
  247. </el-tabs>
  248. </div>
  249. <template v-slot:content>
  250. <el-tabs
  251. v-if="isShow"
  252. v-model="attrActiveName"
  253. class="tab-box_2"
  254. type="border-card"
  255. >
  256. <el-tab-pane label="属性" name="属性">
  257. <!--currentTableNodeData-->
  258. <plan-form ref="planForm" v-if="[0, 1].includes(currentTableNodeData.type)" dialog-type="view"
  259. :dialogForm="rightForm" :deptList="deptList"
  260. :deptTreeList="deptTreeList"></plan-form>
  261. <base-form ref="baseForm" v-if="[2].includes(currentTableNodeData.type)" dialog-type="view"
  262. :dialogForm="rightForm" :deptList="deptList"
  263. :deptTreeList="deptTreeList"></base-form>
  264. </el-tab-pane>
  265. <el-tab-pane v-if="[0, 1].includes(currentTableNodeData.type)" label="计划节点" name="计划节点">
  266. <plan-info-table ref="planInfoTable" dialog-type="view" :dialogForm="rightForm" :deptList="deptList"
  267. :deptTreeList="deptTreeList"></plan-info-table>
  268. </el-tab-pane>
  269. <el-tab-pane v-if="[2].includes(currentTableNodeData.type)" label="交付物" name="交付物"
  270. class="el-tab-pane-tree">
  271. <submit-deliverables-info-table ref="deliverablesInfoTable" :dictList="dictList" dialog-type="view"
  272. :dialogForm="rightForm"></submit-deliverables-info-table>
  273. </el-tab-pane>
  274. </el-tabs>
  275. </template>
  276. </ele-split-layout>
  277. </template>
  278. </ele-split-layout>
  279. </div>
  280. </el-card>
  281. <add-BOM-dialog v-if="addBOMDialogFlag" ref="addBOMDialogRef"
  282. :addBOMDialogFlag.sync="addBOMDialogFlag"
  283. :treeList="treeList"
  284. @reload="reload"></add-BOM-dialog>
  285. <!-- 新增计划 -->
  286. <add-plan-dialog v-if="addPlanDialogFLag" @reload="reload" :addOrEditDialogFlag.sync="addPlanDialogFLag"
  287. ref="addPlanDialogRef"></add-plan-dialog>
  288. <plan-detail-dialog v-if="planDetailDialogFlag" :detailDialogFlag.sync="planDetailDialogFlag"
  289. ref="planDetailDialogRef"></plan-detail-dialog>
  290. <!-- 编辑弹窗 -->
  291. <add-task-dialog v-if="addTaskDialogFlag" @reload="reload" :addOrEditDialogFlag.sync="addTaskDialogFlag"
  292. ref="addTaskDialogRef"></add-task-dialog>
  293. <task-detail-dialog v-if="taskDetailDialogFlag" :detailDialogFlag.sync="taskDetailDialogFlag"
  294. ref="taskDetailDialogRef"></task-detail-dialog>
  295. <transfer-dialog ref="transferDialogRef" v-if="transferDialogFlag" @reload="reload"
  296. :transferDialogFlag.sync="transferDialogFlag"></transfer-dialog>
  297. <submit-deliverables-dialog ref="submitDeliverablesDialogRef" v-if="submitDeliverablesDialogFlag"
  298. :submitDeliverablesDialogFlag.sync="submitDeliverablesDialogFlag" @reload="reload"></submit-deliverables-dialog>
  299. <!-- 编辑弹窗 -->
  300. <addOrEditProjectDialog v-if="addOrEditProjectDialogFlag" @reload="reload"
  301. :addOrEditDialogFlag.sync="addOrEditProjectDialogFlag"
  302. ref="addOrEditProjectDialogRef"></addOrEditProjectDialog>
  303. </div>
  304. </template>
  305. <script>
  306. import {
  307. projectsBomDeleteAPI,
  308. projectsBomFinishAPI,
  309. projectsBomPauseAPI,
  310. projectsBomStartupAPI,
  311. projectsBomTerminationAPI
  312. } from '@/api/project-manage/BOM.js';
  313. import Attribute from "@/views/BOMmanage/components/attribute.vue";
  314. import BOMBaseForm from "@/views/BOMmanage/components/BOMBaseForm.vue";
  315. import addBOMDialog from "@/views/BOMmanage/components/addBOMDialog.vue";
  316. import {
  317. getPlanAndTaskTreeById,
  318. getTaskTreeById,
  319. projectsFinishAPI,
  320. projectsPauseAPI,
  321. projectsStageDeleteAPI,
  322. projectsStageFinishAPI,
  323. projectsStagePauseAPI,
  324. projectsStageStartupAPI,
  325. projectsStageTerminationAPI,
  326. projectsStartupAPI,
  327. projectsTerminationAPI
  328. } from "@/api/project-manage";
  329. import projectForm from "@/views/project-manage/project-initiation/components/project-form.vue";
  330. import {listOrganizations} from "@/api/system/organization";
  331. import {projectsTeamGetByIdAPI, projectsTeamPageAPI} from "@/api/project-manage/team";
  332. import PlanCard from "@/views/BOMmanage/components/planCard.vue";
  333. import addPlanDialog from "@/views/project-manage/planManage/components/addOrEditDialog.vue";
  334. import planDetailDialog from "@/views/project-manage/planManage/components/detailDialog.vue";
  335. import taskDetailDialog from "@/views/project-manage/task-manage/components/detailDialog.vue";
  336. import planForm from "@/views/project-manage/planManage/components/plan-form.vue";
  337. import {
  338. getTargetPlanTreeAPI,
  339. planFinishAPI,
  340. planPauseAPI,
  341. planStageFinishAPI,
  342. planStagePauseAPI,
  343. planStageStartupAPI,
  344. planStageTerminationAPI,
  345. planStartupAPI,
  346. planTerminationAPI,
  347. projectsPlanDeleteAPI,
  348. projectsPlanGetByIdAPI
  349. } from "@/api/project-manage/plan";
  350. import {deepClone} from "@/utils";
  351. import planInfoTable from "@/views/project-manage/planManage/components/planInfoTable.vue";
  352. import BaseForm from "@/views/project-manage/task-manage/components/base-form.vue";
  353. import {projectsTaskDeleteAPI, projectsTaskGetByIdAPI, projectsTaskOpRation} from "@/api/project-manage/task";
  354. import submitDeliverablesInfoTable from "@/views/project-manage/task-manage/components/submitDeliverablesInfoTable.vue";
  355. import {getByCode} from "@/api/system/dictionary-data";
  356. import teamInfoTable from "@/views/project-manage/team-manage/components/team-Info-table.vue";
  357. import addTaskDialog from "@/views/project-manage/task-manage/components/addOrEditDialog.vue";
  358. import {proStatusEnum, reviewStatusEnum} from "@/enum/dict";
  359. import transferDialog from "@/views/project-manage/task-manage/components/transferDialog.vue";
  360. import submitDeliverablesDialog from "@/views/project-manage/task-manage/components/submitDeliverablesDialog.vue";
  361. import addOrEditProjectDialog from "@/views/project-manage/project-initiation/components/addOrEditDialog.vue";
  362. export default {
  363. name: 'BOMDetails',
  364. components: {
  365. addOrEditProjectDialog,
  366. submitDeliverablesDialog,
  367. transferDialog,
  368. addTaskDialog,
  369. teamInfoTable,
  370. submitDeliverablesInfoTable,
  371. BaseForm,
  372. planInfoTable,
  373. planForm,
  374. taskDetailDialog,
  375. planDetailDialog,
  376. addPlanDialog,
  377. PlanCard,
  378. projectForm,
  379. BOMBaseForm,
  380. Attribute,
  381. addBOMDialog,
  382. },
  383. data() {
  384. return {
  385. projectsFinishAPI,
  386. projectsPauseAPI,
  387. projectsStartupAPI,
  388. projectsTerminationAPI,
  389. projectsBomFinishAPI,
  390. projectsBomPauseAPI,
  391. projectsBomStartupAPI,
  392. projectsBomTerminationAPI,
  393. projectsStageFinishAPI,
  394. projectsStagePauseAPI,
  395. projectsStageStartupAPI,
  396. projectsStageTerminationAPI,
  397. planFinishAPI,
  398. planPauseAPI,
  399. planStartupAPI,
  400. planTerminationAPI,
  401. planStageFinishAPI,
  402. planStagePauseAPI,
  403. planStageStartupAPI,
  404. planStageTerminationAPI,
  405. activeName: '基本信息',
  406. attrActiveName: '属性',
  407. active: 0,
  408. contextMenuData: {
  409. menuName: '',
  410. axis: {
  411. x: null,
  412. y: null
  413. }, // 鼠标位置
  414. menulists: [],
  415. },
  416. contextTableMenuData: {
  417. menuName: '',
  418. axis: {
  419. x: null,
  420. y: null
  421. }, // 鼠标位置
  422. menulists: [],
  423. },
  424. currentNodeData: {},
  425. planAndTaskTree: [],
  426. taskTree: [],
  427. deptList: [],
  428. deptTreeList: [],
  429. planStepList: ['待审核', '审核中', '执行中', '已完成'],
  430. teamList: [],
  431. current: {},
  432. dialogForm: {},
  433. rightForm: {},
  434. teamForm: {},
  435. dictList: {},
  436. currentTableNodeData: {},
  437. treeList: [],
  438. isShow: false,
  439. treeLoading: false,
  440. addBOMDialogFlag: false,
  441. addPlanDialogFLag: false,
  442. addTaskDialogFlag: false,
  443. planDetailDialogFlag: false,
  444. taskDetailDialogFlag: false,
  445. transferDialogFlag: false,
  446. submitDeliverablesDialogFlag: false,
  447. addOrEditProjectDialogFlag: false,
  448. defaultProps: {
  449. children: 'children',
  450. label: 'name'
  451. },
  452. loading: false,
  453. filterText: null,
  454. categoryId: 1,
  455. loadingInstance: null,
  456. treeId: null,
  457. dialogType: null,
  458. mainPlanRow: {},
  459. };
  460. },
  461. watch: {
  462. filterText(val) {
  463. this.$refs.treeRef.filter(val);
  464. }
  465. },
  466. computed: {
  467. columns() {
  468. return [
  469. {
  470. columnKey: 'index',
  471. label: '序号',
  472. type: 'index',
  473. width: 55,
  474. align: 'center',
  475. showOverflowTooltip: true,
  476. },
  477. {
  478. label: '名称',
  479. prop: 'name',
  480. showOverflowTooltip: true,
  481. minWidth: 180,
  482. slot: 'name',
  483. },
  484. {
  485. label: '类型名称',
  486. prop: 'type',
  487. showOverflowTooltip: true,
  488. minWidth: 80,
  489. align: 'center',
  490. slot: 'type',
  491. },
  492. {
  493. label: '预计开始时间',
  494. prop: 'planStartDate',
  495. formatter: (val) => {
  496. return val.planStartDate?.split(' ')[0]
  497. },
  498. showOverflowTooltip: true,
  499. minWidth: 120,
  500. align: 'center',
  501. },
  502. {
  503. label: '预计结束时间',
  504. prop: 'planEndDate',
  505. formatter: (val) => {
  506. return val.planEndDate?.split(' ')[0]
  507. },
  508. showOverflowTooltip: true,
  509. minWidth: 120,
  510. align: 'center',
  511. },
  512. {
  513. label: '预计工期(天)',
  514. prop: 'planDay',
  515. showOverflowTooltip: true,
  516. minWidth: 120,
  517. align: 'center',
  518. },
  519. {
  520. label: '实际开始时间',
  521. prop: 'realStartTime',
  522. // formatter: (val) => {
  523. // return val.realStartTime?.split(' ')[0]
  524. // },
  525. showOverflowTooltip: true,
  526. minWidth: 150,
  527. align: 'center',
  528. },
  529. {
  530. label: '实际结束时间',
  531. prop: 'realEndTime',
  532. // formatter: (val) => {
  533. // return val.realEndTime?.split(' ')[0]
  534. // },
  535. showOverflowTooltip: true,
  536. minWidth: 150,
  537. align: 'center',
  538. },
  539. {
  540. label: '实际工期(天)',
  541. prop: 'realDay',
  542. showOverflowTooltip: true,
  543. minWidth: 120,
  544. align: 'center',
  545. },
  546. {
  547. label: '负责人',
  548. prop: 'responsibleUserName',
  549. showOverflowTooltip: true,
  550. minWidth: 100,
  551. align: 'center',
  552. },
  553. {
  554. prop: 'processStatus',
  555. label: '审核状态',
  556. align: 'center',
  557. showOverflowTooltip: true,
  558. minWidth: 100,
  559. formatter: (_row, _column, cellValue) => {
  560. return reviewStatusEnum[_row.processStatus]?.label;
  561. }
  562. },
  563. {
  564. prop: 'status',
  565. label: '状态',
  566. align: 'center',
  567. showOverflowTooltip: true,
  568. minWidth: 100,
  569. formatter: (_row, _column, cellValue) => {
  570. return proStatusEnum[_row.status]?.label;
  571. }
  572. },
  573. {
  574. label: '进度',
  575. prop: 'speedPercent',
  576. showOverflowTooltip: false,
  577. minWidth: 120,
  578. align: 'center',
  579. slot: 'speedPercent'
  580. },
  581. ]
  582. }
  583. },
  584. mounted() {
  585. this.activeName = '基本信息'
  586. this.attrActiveName = '属性'
  587. this.isShow = false
  588. if (this.$route.query.row) {
  589. this.mainPlanRow = JSON.parse(this.$route.query.row);
  590. this.initData();
  591. }
  592. this.getDeptList();
  593. this.getTeamList();
  594. this.getDictList('pro_files_approve_type')
  595. this.getDictList('deliverables_type')
  596. },
  597. activated() {
  598. if (this.$route.query.row) {
  599. this.mainPlanRow = JSON.parse(this.$route.query.row);
  600. this.initData();
  601. }
  602. },
  603. methods: {
  604. handleTabs1(val) {
  605. this.activeName = val.label
  606. this.attrActiveName = '属性'
  607. this.isShow = false
  608. },
  609. filterNode(value, data) {
  610. if (!value) return true;
  611. return data.name.indexOf(value) !== -1;
  612. },
  613. async getDictList(code) {
  614. let {data: res} = await getByCode(code)
  615. this.dictList[code] = res.map(item => {
  616. let values = Object.keys(item)
  617. return {
  618. value: values[0],
  619. label: item[values[0]]
  620. }
  621. })
  622. },
  623. initData() {
  624. this.getTreeData();
  625. },
  626. // 获取部门数据
  627. getDeptList() {
  628. listOrganizations().then((list) => {
  629. this.deptList = list;
  630. this.deptTreeList = this.$util.toTreeData({
  631. data: list,
  632. idField: 'id',
  633. parentIdField: 'parentId'
  634. });
  635. console.log(this.deptTreeList);
  636. });
  637. },
  638. getTeamList() {
  639. projectsTeamPageAPI(
  640. {
  641. pageNum: 1,
  642. size: 999
  643. }
  644. ).then((list) => {
  645. this.teamList = list;
  646. });
  647. },
  648. handleUpdateProject(node, data, type) {
  649. this.addOrEditProjectDialogFlag = true;
  650. this.$nextTick(() => {
  651. this.$refs.addOrEditProjectDialogRef.init(data, type)
  652. })
  653. },
  654. bomRemove(node, data) {
  655. let message = data.children.length ? '当前节点包含子节点,是否确认删除?' : '是否确认删除?'
  656. this.$confirm(message, '提示', {
  657. confirmButtonText: '确定',
  658. cancelButtonText: '取消',
  659. type: 'warning'
  660. })
  661. .then(async () => {
  662. const loading = this.$loading({lock: true});
  663. await projectsBomDeleteAPI([data.id])
  664. loading.close();
  665. this.$message.success('删除成功');
  666. await this.getTreeData();
  667. })
  668. .catch(() => {
  669. this.$message({
  670. type: 'info',
  671. message: '已取消删除'
  672. });
  673. });
  674. },
  675. stageRemove(node, data) {
  676. let message = data.children.length ? '当前节点包含子节点,是否确认删除?' : '是否确认删除?'
  677. this.$confirm(message, '提示', {
  678. confirmButtonText: '确定',
  679. cancelButtonText: '取消',
  680. type: 'warning'
  681. })
  682. .then(async () => {
  683. const loading = this.$loading({lock: true});
  684. await projectsStageDeleteAPI([data.id])
  685. loading.close();
  686. this.$message.success('删除成功');
  687. await this.getTreeData();
  688. })
  689. .catch(() => {
  690. this.$message({
  691. type: 'info',
  692. message: '已取消删除'
  693. });
  694. });
  695. },
  696. back() {
  697. this.$router.go(-1);
  698. },
  699. async validateForm() {
  700. return Promise.all([new Promise((resolve, reject) => {
  701. this.$refs.BOMBaseFormRef.getValidaValue((valid) => {
  702. if (!valid) {
  703. reject(false);
  704. } else {
  705. resolve(true);
  706. }
  707. })
  708. })]).catch(() => {
  709. this.$message.warning('请先填写完整信息');
  710. return Promise.reject(false);
  711. });
  712. },
  713. addOrEditBOM(type, node, data) {
  714. this.addBOMDialogFlag = true;
  715. this.$nextTick(() => {
  716. this.$refs.addBOMDialogRef.init(data, type);
  717. })
  718. },
  719. handleAddPlan(type, node, data, sourceName = 'project') {
  720. this.addPlanDialogFLag = true;
  721. let params = {
  722. projectId: data.projectId,
  723. projectStageId: data.projectStageId,
  724. projectBomId: data.projectBomId,
  725. parentPlanId: data.id,
  726. id: data.id
  727. }
  728. this.$nextTick(() => {
  729. this.$refs.addPlanDialogRef.init(params, type)
  730. })
  731. },
  732. async handleStatus(API, msg, node, row) {
  733. this.$confirm(msg, '提示', {
  734. type: 'warning'
  735. }).then(async () => {
  736. await API(row.id)
  737. this.$message.success('操作成功');
  738. this.reload();
  739. }).catch(() => {
  740. });
  741. },
  742. //报工/执行
  743. async handleStartTask(row, afterStatus, msg) {
  744. this.$confirm(msg, '提示', {
  745. confirmButtonText: '确定',
  746. cancelButtonText: '取消',
  747. type: 'warning'
  748. }).then(async () => {
  749. let params = {
  750. id: row.id,
  751. afterStatus: afterStatus,
  752. status: row.status
  753. }
  754. await projectsTaskOpRation(params)
  755. this.$message.success('操作成功');
  756. this.reload();
  757. }).catch(() => {
  758. });
  759. },
  760. handleRemovePlan(ids) {
  761. this.$confirm('此操作将永久删除该计划, 是否继续?', '提示', {
  762. confirmButtonText: '确定',
  763. cancelButtonText: '取消',
  764. type: 'warning'
  765. }).then(async () => {
  766. const loading = this.$loading({lock: true});
  767. projectsPlanDeleteAPI(ids)
  768. .then((res) => {
  769. loading.close();
  770. this.$message.success('删除成功');
  771. this.reload();
  772. })
  773. .catch((e) => {
  774. loading.close();
  775. // this.$message.error(e.message);
  776. });
  777. })
  778. },
  779. /* 删除 */
  780. handleRemoveTask(ids) {
  781. this.$confirm('此操作将永久删除该任务, 是否继续?', '提示', {
  782. confirmButtonText: '确定',
  783. cancelButtonText: '取消',
  784. type: 'warning'
  785. }).then(async () => {
  786. const loading = this.$loading({lock: true});
  787. projectsTaskDeleteAPI(ids)
  788. .then((res) => {
  789. loading.close();
  790. this.$message.success('删除成功');
  791. this.reload();
  792. })
  793. .catch((e) => {
  794. loading.close();
  795. // this.$message.error(e.message);
  796. });
  797. }).catch(() => {
  798. });
  799. },
  800. /* */
  801. handleAddTask(type, node, data, sourceName = 'project') {
  802. this.addTaskDialogFlag = true;
  803. let params = {}
  804. switch (data.type) {
  805. case 0:
  806. params = {
  807. targetPlanId: data.id,
  808. projectId: data.projectId,
  809. projectStageId: data.projectStageId,
  810. projectBomId: data.projectBomId,
  811. }
  812. break;
  813. case 1:
  814. params = {
  815. targetPlanId: data.parentId,
  816. projectId: data.projectId,
  817. projectStageId: data.projectStageId,
  818. projectBomId: data.projectBomId,
  819. planStageId: data.id,
  820. }
  821. break;
  822. case 2:
  823. params = {
  824. targetPlanId: data.targetPlanId,
  825. projectId: data.projectId,
  826. projectStageId: data.projectStageId,
  827. projectBomId: data.projectBomId,
  828. planStageId: data.planStageId,
  829. taskId: data.id,
  830. id: type !== 'add' ? data.id : '',
  831. }
  832. break;
  833. default:
  834. params = {
  835. targetPlanId: data.id,
  836. projectId: data.projectId,
  837. projectStageId: data.projectStageId,
  838. projectBomId: data.projectBomId,
  839. }
  840. break;
  841. }
  842. this.$nextTick(() => {
  843. this.$refs.addTaskDialogRef.init(params, type)
  844. })
  845. },
  846. async getTreeData() {
  847. try {
  848. this.treeLoading = true;
  849. let API = getTargetPlanTreeAPI
  850. let params = {
  851. id: this.mainPlanRow.id,
  852. projectBomId: this.mainPlanRow.projectBomId,
  853. projectId: this.mainPlanRow.projectId,
  854. projectStageId: this.mainPlanRow.projectStageId,
  855. rootParentId: this.mainPlanRow.parentId,
  856. }
  857. this.treeList = await API(params);
  858. this.$nextTick(() => {
  859. if (this.treeList.length) {
  860. // 默认高亮第一个
  861. this.$refs.treeRef.setCurrentKey(this.treeList[0]?.id);
  862. this.handleNodeClick(this.treeList[0]);
  863. }
  864. });
  865. } catch (error) {
  866. }
  867. this.treeLoading = false;
  868. },
  869. getIconClass(node, data) {
  870. switch (data.type) {
  871. case 2:
  872. return node.expanded ? 'el-icon-document' : 'el-icon-tickets';
  873. case 1:
  874. return node.expanded ? 'el-icon-document' : 'el-icon-tickets';
  875. case 0:
  876. return node.expanded ? 'el-icon-folder-opened' : 'el-icon-folder';
  877. default :
  878. return ''
  879. }
  880. },
  881. showRightMenu(event, node, data) {
  882. this.contextMenuData.menuName = data.id+'_'+data.name+'_rightMenu'
  883. this.$nextTick(() => {
  884. let menuList = [...document.querySelectorAll('.vue-contextmenu-listWrapper')]
  885. menuList.forEach(item => {
  886. item.style.display = 'none'
  887. })
  888. event.preventDefault();
  889. const x = event.clientX;
  890. const y = event.clientY;
  891. this.contextMenuData.axis = {x, y}
  892. this.contextMenuData.menulists = [
  893. {
  894. fnHandler: 'addPlan',
  895. icoName: 'fa el-icon-plus',
  896. btnName: '新建子计划',
  897. disabled: this.disableToAddPlan(data)
  898. },
  899. {
  900. fnHandler: 'addTask',
  901. icoName: 'fa el-icon-plus',
  902. btnName: '新建任务',
  903. disabled: this.disableToAddTask(data)
  904. },
  905. {
  906. fnHandler: 'editPlan',
  907. icoName: 'fa el-icon-edit',
  908. btnName: '修改',
  909. disabled: [1, 2].includes(data.processStatus)
  910. },
  911. {
  912. fnHandler: 'onRemove',
  913. icoName: 'fa el-icon-delete',
  914. btnName: '删除',
  915. disabled: [1, 2].includes(data.processStatus)
  916. },
  917. {
  918. fnHandler: 'handleFinish',
  919. icoName: 'fa el-icon-success',
  920. btnName: '完成',
  921. disabled: this.disableToFinish(data)
  922. },
  923. {
  924. fnHandler: 'handlePause',
  925. icoName: 'fa el-icon-video-pause',
  926. btnName: '暂停',
  927. disabled: this.disableToPause(data)
  928. },
  929. {
  930. fnHandler: 'handleStartup',
  931. icoName: 'fa el-icon-video-play',
  932. btnName: '启动',
  933. disabled: this.disableToStartup(data)
  934. },
  935. {
  936. fnHandler: 'handleTermination',
  937. icoName: 'fa el-icon-error',
  938. btnName: '终止',
  939. disabled: this.disableToTermination(data)
  940. },
  941. ]
  942. })
  943. },
  944. disableToAddBOM(row) {
  945. return ![2].includes(row.processStatus) || ![0, 1].includes(row.status)
  946. },
  947. disableToAddPlan(row) {
  948. return ![0,1,2,3].includes(row.processStatus) || ![0, 1].includes(row.status)
  949. },
  950. disableToAddTask(row) {
  951. return ![0,1,2,3].includes(row.processStatus) || ![0, 1].includes(row.status)
  952. },
  953. disableToFinish(row) {
  954. return ![2].includes(row.processStatus) || [4, 2, 3].includes(row.status)
  955. },
  956. disableToPause(row) {
  957. return ![2].includes(row.processStatus) || [4, 2, 3].includes(row.status)
  958. },
  959. disableToStartup(row) {
  960. return ![2].includes(row.processStatus) || [4, 1, 0, 3].includes(row.status)
  961. },
  962. disableToTermination(row) {
  963. return ![2].includes(row.processStatus) || [4, 3].includes(row.status)
  964. },
  965. handleNodeClick(data) {
  966. this.treeId = data.id;
  967. this.currentNodeData = data
  968. this.$nextTick(async () => {
  969. this.dialogForm = await projectsPlanGetByIdAPI(data.id)
  970. this.dialogForm.responsibleUserIds = this.dialogForm.responsibleUserList?.map(i => i.userName) || []
  971. this.dialogForm.planStageList?.forEach((item, index) => {
  972. let userNames = item.responsibleUserList.map(i => i.userName) || []
  973. this.$set(item, 'responsibleUserNames', userNames.join(','))
  974. })
  975. this.getPlanAndTaskTree(data)
  976. this.getTaskTree(data)
  977. this.planStepList = ['待审核', '审核中', '执行中', '已完成']
  978. if (data.processStatus == 0) {
  979. this.active = 0
  980. return
  981. }
  982. if ([1, 3].includes(data.processStatus)) {
  983. let stepName = data.processStatus == 3 ? '审核未通过' : '审核中'
  984. this.planStepList.splice(1, 1, stepName)
  985. this.active = 1
  986. return
  987. }
  988. if ([0, 1, 2].includes(data.status)) {
  989. let stepName = data.status == 1 ? '执行中' : data.status == 2 ? '暂停中' : '未开始'
  990. this.planStepList.splice(2, 1, stepName)
  991. this.active = 2
  992. return
  993. }
  994. if ([3, 4].includes(data.status)) {
  995. let stepName = data.status == 3 ? '已完成' : '已终止'
  996. this.planStepList.splice(3, 1, stepName)
  997. this.active = 4
  998. return
  999. }
  1000. // await this.getTeamInfo(this.dialogForm.teamId)
  1001. })
  1002. },
  1003. async getPlanAndTaskTree(data) {
  1004. let params = {
  1005. id: data.id,
  1006. }
  1007. let res = await getPlanAndTaskTreeById(params)
  1008. this.planAndTaskTree = res[0]?.children || []
  1009. },
  1010. async getTaskTree(data) {
  1011. let params = {
  1012. planId: data.id,
  1013. }
  1014. this.taskTree = await getTaskTreeById(params)
  1015. },
  1016. reload(where) {
  1017. this.getTreeData();
  1018. },
  1019. setTableCell({row}) {
  1020. console.log(row.level);
  1021. if (row.level === 1) return '' //
  1022. return {marginLeft: (row.level + 3) + 'px'} //
  1023. },
  1024. handleTableNodeClick(row) {
  1025. this.isShow = true;
  1026. this.attrActiveName = '属性'
  1027. this.currentTableNodeData = row;
  1028. switch (row.type) {
  1029. case 0:
  1030. this.getProjectPlanInfo(row.id)
  1031. break;
  1032. case 1:
  1033. this.getProjectPlanInfo(row.targetPlanId)
  1034. break;
  1035. case 2:
  1036. this.getProjectTaskInfo(row.id)
  1037. break;
  1038. }
  1039. },
  1040. showTableRightMenu(row, column, event,name='') {
  1041. this.contextTableMenuData.menuName = name+row.name
  1042. this.$nextTick(() => {
  1043. let menuList = [...document.querySelectorAll('.vue-contextmenu-listWrapper')]
  1044. menuList.forEach(item => {
  1045. item.style.display = 'none'
  1046. })
  1047. event.preventDefault();
  1048. const x = event.clientX;
  1049. const y = event.clientY;
  1050. this.contextTableMenuData.axis = {x, y}
  1051. switch (row.type) {
  1052. case 0:
  1053. this.contextTableMenuData.menulists = [
  1054. {
  1055. fnHandler: 'addPlan',
  1056. icoName: 'fa el-icon-plus',
  1057. btnName: '新建子计划',
  1058. disabled: this.disableToAddPlan(row)
  1059. },
  1060. {
  1061. fnHandler: 'addTask',
  1062. icoName: 'fa el-icon-plus',
  1063. btnName: '新建任务',
  1064. disabled: this.disableToAddTask(row)
  1065. },
  1066. {
  1067. fnHandler: 'editPlan',
  1068. icoName: 'fa el-icon-edit',
  1069. btnName: '修改',
  1070. disabled: [1, 2].includes(row.processStatus) || ![0].includes(row.status)
  1071. },
  1072. {
  1073. fnHandler: 'removePlan',
  1074. icoName: 'fa el-icon-delete',
  1075. btnName: '删除',
  1076. disabled: [1, 2].includes(row.processStatus) || ![0].includes(row.status)
  1077. },
  1078. {
  1079. fnHandler: 'finishPlan',
  1080. icoName: 'fa el-icon-success',
  1081. btnName: '完成',
  1082. disabled: this.disableToFinish(row)
  1083. },
  1084. {
  1085. fnHandler: 'pausePlan',
  1086. icoName: 'fa el-icon-video-pause',
  1087. btnName: '暂停',
  1088. disabled: this.disableToPause(row)
  1089. },
  1090. {
  1091. fnHandler: 'startupPlan',
  1092. icoName: 'fa el-icon-video-play',
  1093. btnName: '启动',
  1094. disabled: this.disableToStartup(row)
  1095. },
  1096. {
  1097. fnHandler: 'terminationPlan',
  1098. icoName: 'fa el-icon-error',
  1099. btnName: '终止',
  1100. disabled: this.disableToTermination(row)
  1101. },
  1102. ]
  1103. break
  1104. case 1:
  1105. this.contextTableMenuData.menulists = [
  1106. {
  1107. fnHandler: 'addTask', icoName: 'fa el-icon-plus', btnName: '新建任务',
  1108. disabled: this.disableToAddTask(row)
  1109. },
  1110. // {fnHandler: 'editBOM', icoName: 'fa el-icon-edit', btnName: '修改'},
  1111. // {fnHandler: 'removeBom', icoName: 'fa el-icon-delete', btnName: '删除'},
  1112. {
  1113. fnHandler: 'finishPlanStage', icoName: 'fa el-icon-success', btnName: '完成',
  1114. disabled: this.disableToFinish(row)
  1115. },
  1116. {
  1117. fnHandler: 'pausePlanStage', icoName: 'fa el-icon-video-pause', btnName: '暂停',
  1118. disabled: this.disableToPause(row)
  1119. },
  1120. {
  1121. fnHandler: 'startupPlanStage', icoName: 'fa el-icon-video-play', btnName: '启动',
  1122. disabled: this.disableToStartup(row)
  1123. },
  1124. {
  1125. fnHandler: 'terminationPlanStage', icoName: 'fa el-icon-error', btnName: '终止',
  1126. disabled: this.disableToTermination(row)
  1127. },
  1128. ]
  1129. break
  1130. case 2:
  1131. this.contextTableMenuData.menulists = [
  1132. {
  1133. fnHandler: 'addTask', icoName: 'fa el-icon-plus', btnName: '新建任务',
  1134. disabled: [4, 2, 3].includes(row.status)
  1135. },
  1136. {
  1137. fnHandler: 'updateTask', icoName: 'fa el-icon-edit', btnName: '修改',
  1138. disabled: [4, 2, 3, 1].includes(row.status)
  1139. },
  1140. {
  1141. fnHandler: 'removeTask', icoName: 'fa el-icon-delete', btnName: '删除',
  1142. disabled: [4, 2, 3, 1].includes(row.status)
  1143. },
  1144. {
  1145. fnHandler: 'startTask',
  1146. icoName: 'fa el-icon-video-play',
  1147. btnName: '执行',
  1148. disabled: [4, 3, 1].includes(row.status)
  1149. },
  1150. {
  1151. fnHandler: 'handleSubmitDeliverables',
  1152. icoName: 'fa el-icon-folder-add',
  1153. btnName: '交付物提交',
  1154. disabled: [4, 3, 0, 2].includes(row.status)
  1155. },
  1156. {
  1157. fnHandler: 'finishTask',
  1158. icoName: 'fa el-icon-success',
  1159. btnName: '报工',
  1160. disabled: !([1].includes(row.status) && row.ifFilesAllFinish == 1)
  1161. },
  1162. {
  1163. fnHandler: 'pauseTask', icoName: 'fa el-icon-video-pause', btnName: '暂停',
  1164. disabled: this.disableToPause(row)
  1165. },
  1166. {
  1167. fnHandler: 'terminationTask', icoName: 'fa el-icon-error', btnName: '终止',
  1168. disabled: this.disableToTermination(row)
  1169. },
  1170. {
  1171. fnHandler: 'handleTransfer', icoName: 'fa el-icon-position', btnName: '转派',
  1172. disabled: !([1].includes(row.status))
  1173. },
  1174. ]
  1175. break
  1176. }
  1177. console.log(this.contextTableMenuData.menulists);
  1178. })
  1179. },
  1180. //转派
  1181. handleTransfer(row) {
  1182. this.transferDialogFlag = true;
  1183. this.$nextTick(() => {
  1184. this.$refs.transferDialogRef.init(row)
  1185. })
  1186. },
  1187. /* 交付物提交 */
  1188. handleSubmitDeliverables(row = {}, type) {
  1189. this.submitDeliverablesDialogFlag = true;
  1190. this.$nextTick(() => {
  1191. this.$refs.submitDeliverablesDialogRef.init(row, type)
  1192. })
  1193. },
  1194. async getProjectTaskInfo(id = '') {
  1195. this.rightForm = await projectsTaskGetByIdAPI(id)
  1196. this.rightForm.type = this.rightForm.type + ''
  1197. this.rightForm.responsibleUserIds = this.rightForm.responsibleUserList?.map(i => i.userName) || []
  1198. },
  1199. async getProjectPlanInfo(id = '') {
  1200. let res = await projectsPlanGetByIdAPI(id)
  1201. this.rightForm = deepClone(res)
  1202. this.rightForm.responsibleUserIds = this.rightForm.responsibleUserList?.map(i => i.userName) || []
  1203. this.rightForm.planStageList?.forEach((item, index) => {
  1204. let userNames = item.responsibleUserList.map(i => i.userName) || []
  1205. this.$set(item, 'responsibleUserNames', userNames.join(','))
  1206. })
  1207. // await this.changeProject(this.dialogForm.projectId)
  1208. },
  1209. async getTeamInfo(teamId='') {
  1210. if(teamId){
  1211. this.teamForm = await projectsTeamGetByIdAPI(teamId)
  1212. }
  1213. },
  1214. // 每一级字体变小
  1215. fontSize(node, data) {
  1216. if (node.level === 1 || node.level === 2) return 'font-size:14px' // 一二级字体
  1217. return 'font-size:' + (13) + 'px' // 三级以下字号减小
  1218. },
  1219. uploadFile() {
  1220. this.$refs.importDialogRef.open();
  1221. },
  1222. customColorMethod(percentage) {
  1223. if (percentage < 30) {
  1224. return '#b6b6b6';
  1225. } else if (percentage < 70) {
  1226. return '#b3e496';
  1227. } else {
  1228. return '#67c23a';
  1229. }
  1230. },
  1231. }
  1232. };
  1233. </script>
  1234. <style lang="scss" scoped>
  1235. .ele-body {
  1236. display: flex;
  1237. flex-direction: column;
  1238. height: 100%;
  1239. .card_2_box {
  1240. flex: 1;
  1241. ::v-deep .el-card__body {
  1242. height: 100%;
  1243. .card_2_box_content {
  1244. height: 100%;
  1245. .ele-split-panel {
  1246. height: 100%;
  1247. .el_tree_box {
  1248. padding: 0 4px 0 0;
  1249. height: 100%;
  1250. border: none;
  1251. border-right: 1px solid #e8eaec;
  1252. //border-radius: 3px;
  1253. .el-tree-node {
  1254. .el-tree-node__children {
  1255. height: 100%;
  1256. overflow: auto
  1257. }
  1258. }
  1259. }
  1260. }
  1261. }
  1262. }
  1263. }
  1264. }
  1265. .card_2_layout_content {
  1266. display: flex;
  1267. flex-direction: column;
  1268. height: 100%;
  1269. ::v-deep .card_2_1_box {
  1270. height: 50px;
  1271. width: 100%;
  1272. margin-bottom: 10px;
  1273. .border-box-content {
  1274. height: 100%;
  1275. width: 100%;
  1276. background: rgba(203, 203, 203, 0.12);
  1277. border-radius: 3px;
  1278. display: flex;
  1279. flex-direction: row;
  1280. justify-content: space-between;
  1281. align-items: center;
  1282. .card_2_1_box_div_1 {
  1283. flex: 1;
  1284. height: 50px;
  1285. display: flex;
  1286. align-items: center;
  1287. .el-steps--simple {
  1288. border-radius: 0 !important;
  1289. background: none;
  1290. width: 100%;
  1291. }
  1292. .is-success {
  1293. color: rgb(103, 103, 103) !important;
  1294. .el-step__icon {
  1295. border-color: rgb(103, 103, 103) !important
  1296. }
  1297. .el-icon-check:before {
  1298. font-size: 14px;
  1299. line-height: 14px;
  1300. font-weight: bold;
  1301. color: rgb(103, 103, 103) !important;
  1302. }
  1303. }
  1304. .el-step__main {
  1305. .is-process:before {
  1306. content: '';
  1307. background: rgba(182, 182, 182, 0.26);
  1308. height: 30px;
  1309. width: 160px;
  1310. display: block;
  1311. position: absolute;
  1312. border-radius: 15px;
  1313. transform: translate(-40%, -18%);
  1314. }
  1315. }
  1316. .is-process {
  1317. border-color: #f8f8f8 !important;
  1318. font-weight: bold;
  1319. }
  1320. .is-success + .el-step__arrow:before {
  1321. background: rgb(202, 205, 212) !important;
  1322. }
  1323. .is-success + .el-step__arrow:after {
  1324. background: rgb(202, 205, 212) !important;
  1325. }
  1326. }
  1327. .card_2_1_box_div_2 {
  1328. width: 150px;
  1329. margin-right: 10px;
  1330. height: 100%;
  1331. display: flex;
  1332. align-items: center;
  1333. .dv-percent-pond text {
  1334. font-size: 20px !important;
  1335. transform: translate(0%, 8%)
  1336. }
  1337. }
  1338. }
  1339. }
  1340. ::v-deep .tab-box_1 {
  1341. flex: 1;
  1342. .el-tabs__content {
  1343. //padding: 10px;
  1344. height: calc(100% - 45px);
  1345. //overflow: auto;
  1346. padding: 0;
  1347. padding-top: 10px;
  1348. .el-tab-pane {
  1349. height: 100%;
  1350. }
  1351. }
  1352. }
  1353. }
  1354. ::v-deep .project_tree {
  1355. .custom-tree-node {
  1356. display: flex;
  1357. align-items: center;
  1358. .label_img {
  1359. width: 20px;
  1360. height: 20px;
  1361. margin-left: 5px;
  1362. }
  1363. .label {
  1364. }
  1365. }
  1366. .el-tree-node {
  1367. position: relative;
  1368. padding-left: 0px;
  1369. }
  1370. .el-tree-node__children {
  1371. padding-left: 22px;
  1372. }
  1373. // 自定义图标中隐藏自带箭头
  1374. //.el-tree-node__content > .el-tree-node__expand-icon {
  1375. // position: absolute;
  1376. // opacity: 0;
  1377. //}
  1378. .el-tree-node__content > .el-tree-node__expand-icon {
  1379. padding: 0;
  1380. }
  1381. // 禁止旋转
  1382. .el-tree .el-tree-node__expand-icon.expanded {
  1383. -webkit-transform: rotate(0deg);
  1384. transform: rotate(0deg);
  1385. }
  1386. // 节点高度与边距
  1387. .el-tree-node__content {
  1388. height: 30px;
  1389. }
  1390. .el-tree-node {
  1391. margin: 1px 0;
  1392. overflow: hidden;
  1393. text-overflow: ellipsis;
  1394. white-space: nowrap;
  1395. }
  1396. //高亮字体颜色
  1397. .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {
  1398. color: #ee7355 !important;
  1399. background-color: red !important; // 设置选中背景颜色
  1400. }
  1401. // 设置竖线
  1402. .el-tree-node .is-focusable:before {
  1403. content: "";
  1404. display: inline-block;
  1405. position: absolute;
  1406. left: -15px;
  1407. border-left: 1px solid #f8f8f8;
  1408. height: calc(100%);
  1409. }
  1410. .list-left {
  1411. width: 214px;
  1412. height: auto;
  1413. margin: 10px 0 20px 20px;
  1414. background-color: #fff;
  1415. border-radius: 10px;
  1416. padding: 20px;
  1417. }
  1418. // 鼠标移入高亮
  1419. .custom-tree-node:hover {
  1420. //color: #070a0c !important;
  1421. }
  1422. .el-icon-folder-opened, .el-icon-folder, .el-icon-document, .el-icon-tickets {
  1423. display: flex;
  1424. align-items: center;
  1425. }
  1426. .el-icon-document, .el-icon-folder-opened {
  1427. //color: #0e85fa;
  1428. }
  1429. //高亮字体颜色
  1430. .el-tree--highlight-current, .el-tree-node.is-current > .el-tree-node__content {
  1431. color: #f8f8f8 !important;
  1432. background-color: #72b9ff !important; // 设置选中背景颜色
  1433. border-radius: 3px;
  1434. }
  1435. .el-tree-node__content:hover {
  1436. color: #f8f8f8 !important;
  1437. background-color: #b7d6f8 !important; // 设置选中背景颜色
  1438. border-radius: 3px;
  1439. }
  1440. }
  1441. ::v-deep .ele-table-tool-default {
  1442. display: none;
  1443. }
  1444. ::v-deep .ele-split-panel-body {
  1445. .ele-split-panel-side {
  1446. border-bottom: 1px solid #e8e8e8;
  1447. }
  1448. }
  1449. ::v-deep .ele-split-panel-side {
  1450. // border-bottom: 2px solid #e6e8ea;
  1451. height: 100%;
  1452. .tab-box_1 {
  1453. height: 100%;
  1454. .el-tabs__item {
  1455. background: rgba(246, 246, 247, 0.8);
  1456. border-bottom: 1px solid #e6e8ea;
  1457. }
  1458. .is-active.el-tabs__item {
  1459. background: #FFFFFF;
  1460. border-bottom: none;
  1461. }
  1462. .el-table {
  1463. height: calc(100% - 1px);
  1464. }
  1465. }
  1466. }
  1467. ::v-deep .tab-box_2 {
  1468. height: 100%;
  1469. overflow: auto;
  1470. display: flex;
  1471. flex-direction: column;
  1472. .el-tabs__content {
  1473. flex: 1;
  1474. .el-tab-pane {
  1475. height: 100%;
  1476. }
  1477. }
  1478. }
  1479. .current_button {
  1480. background: #096cd7;
  1481. border-color: #096cd7;
  1482. color: #FFFFFF;
  1483. }
  1484. ::v-deep .vue-contextmenu-listWrapper {
  1485. display: block;
  1486. background: #fff !important;
  1487. padding: 4px 0 !important;
  1488. border: 1px solid #dadada;
  1489. border-radius: 7px !important;
  1490. color: #606266;
  1491. .context-menu-list:hover {
  1492. background: rgba(156, 156, 156, 0.2) !important;
  1493. //color: #FFFFFF !important;
  1494. }
  1495. .context-menu-list {
  1496. background: #fff !important;
  1497. width: 100%;
  1498. height: 25px;
  1499. div {
  1500. display: flex;
  1501. flex-direction: row;
  1502. align-items: center;
  1503. justify-content: flex-start;
  1504. min-width: 120px;
  1505. width: 100%;
  1506. height: 100%;
  1507. i {
  1508. margin-left: 15px;
  1509. }
  1510. span {
  1511. margin: 0 !important;
  1512. margin-left: 25px !important;
  1513. }
  1514. }
  1515. }
  1516. }
  1517. ::v-deep tr[class^="el-table__row--level"] > td:nth-child(2) > .cell {
  1518. margin-left: 24px;
  1519. }
  1520. ::v-deep .el-table__header-wrapper .el-table__cell {
  1521. .cell {
  1522. text-align: center;
  1523. }
  1524. }
  1525. @for $i from 1 to 10 {
  1526. ::v-deep .el-table__row--level-#{$i} > td:nth-child(2) > .cell {
  1527. margin-left: #{ $i * 4 +10}px;
  1528. display: flex;
  1529. flex-direction: row;
  1530. align-items: center;
  1531. }
  1532. }
  1533. .dot {
  1534. border-radius: 50%;
  1535. -webkit-background-clip: text;
  1536. color: #0e85fa;
  1537. display: inline-block;
  1538. width: 5px;
  1539. height: 5px;
  1540. margin-right: 2px;
  1541. text-align: center;
  1542. background: #0e85fa;
  1543. }
  1544. </style>