form.vue 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  1. <template>
  2. <HcCard actionUi="text-center" :title="detailData?.projectName">
  3. <template #extra>
  4. <HcNewSwitch :datas="tabTab" :keys="tabKey" @change="tabChange" :round="false"/>
  5. </template>
  6. <template #search>
  7. <div class="hc-program-project-form-radio-group">
  8. <el-radio-group v-model="radioType" size="large">
  9. <el-radio-button label="1">市场部</el-radio-button>
  10. <el-radio-button label="2">研发部</el-radio-button>
  11. <el-radio-button label="3">实施部</el-radio-button>
  12. <el-radio-button label="4">维护部</el-radio-button>
  13. <el-radio-button label="5">管理支出</el-radio-button>
  14. <el-radio-button label="6">外包劳务</el-radio-button>
  15. </el-radio-group>
  16. </div>
  17. </template>
  18. <HcTable :isIndex="false" :column="tableColumn" :datas="tableData" :row-style="tableRowStyle" hasChildren="hasChildren1" children="childrenList">
  19. <template #projectProcessValue="{row,index}">
  20. <template v-if="row.taskFinishedStatus === 1">
  21. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  22. <template #reference>
  23. <span class="text-hover">{{row.projectProcessValue}}</span>
  24. </template>
  25. </el-popover>
  26. </template>
  27. <span v-else>{{row.projectProcessValue}}</span>
  28. </template>
  29. <template #budgetTypeValue="{row,index}">
  30. <template v-if="row.taskFinishedStatus === 1">
  31. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  32. <template #reference>
  33. <span class="text-hover">{{row.budgetTypeValue}}</span>
  34. </template>
  35. </el-popover>
  36. </template>
  37. <span v-else>{{row.projectProcessValue}}</span>
  38. </template>
  39. <template #taskDetailValue="{row,index}">
  40. <template v-if="row.taskFinishedStatus === 1">
  41. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  42. <template #reference>
  43. <span class="text-hover">{{row.taskDetailValue}}</span>
  44. </template>
  45. </el-popover>
  46. </template>
  47. <span v-else>{{row.projectProcessValue}}</span>
  48. </template>
  49. <template #planTaskType="{row,index}">
  50. <template v-if="row.taskFinishedStatus === 1">
  51. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  52. <template #reference>
  53. <el-select v-model="row.planTaskType" v-if="row.isEdit" clearable>
  54. <el-option v-for="item in taskTypeList" :label="item.dictName" :value="item.id" />
  55. </el-select>
  56. <span v-else>{{row?.planTaskTypeValue}}</span>
  57. </template>
  58. </el-popover>
  59. </template>
  60. <span v-else>
  61. <el-select v-model="row.planTaskType" v-if="row.isEdit" clearable>
  62. <el-option v-for="item in taskTypeList" :label="item.dictName" :value="item.id" />
  63. </el-select>
  64. <span v-else>{{row?.planTaskTypeValue}}</span>
  65. </span>
  66. </template>
  67. <template #planTaskDesc="{row,index}">
  68. <template v-if="row.taskFinishedStatus === 1">
  69. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  70. <template #reference>
  71. <el-input v-model="row.planTaskDesc" v-if="row.isEdit" clearable/>
  72. <span v-else>{{row.planTaskDesc}}</span>
  73. </template>
  74. </el-popover>
  75. </template>
  76. <span v-else>
  77. <el-input v-model="row.planTaskDesc" v-if="row.isEdit" clearable/>
  78. <span v-else>{{row.planTaskDesc}}</span>
  79. </span>
  80. </template>
  81. <template #planTarget="{row,index}">
  82. <template v-if="row.taskFinishedStatus === 1">
  83. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  84. <template #reference>
  85. <el-input v-model="row.planTarget" v-if="row.isEdit" clearable/>
  86. <span v-else>{{row.planTarget}}</span>
  87. </template>
  88. </el-popover>
  89. </template>
  90. <span v-else>
  91. <el-input v-model="row.planTarget" v-if="row.isEdit" clearable/>
  92. <span v-else>{{row.planTarget}}</span>
  93. </span>
  94. </template>
  95. <template #key7="{row,index}">
  96. <template v-if="row.taskFinishedStatus === 1">
  97. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  98. <template #reference>
  99. <HcDatePicker :dates="[row.planStartTime,row.planEndTime]" @change="betweenTimeUpdate($event,row)" v-if="row.isEdit" clearable/>
  100. <span v-else>
  101. <span >{{row.planStartTime?row.planStartTime:''}}</span>
  102. <span v-if="row.planEndTime">~</span>
  103. <span >{{row.planEndTime?row.planEndTime:''}}</span>
  104. </span>
  105. </template>
  106. </el-popover>
  107. </template>
  108. <span v-else>
  109. <HcDatePicker :dates="[row.planStartTime,row.planEndTime]" @change="betweenTimeUpdate($event,row)" v-if="row.isEdit" clearable/>
  110. <span v-else>
  111. <span >{{row.planStartTime?row.planStartTime:''}}</span>
  112. <span v-if="row.planEndTime">~</span>
  113. <span >{{row.planEndTime?row.planEndTime:''}}</span>
  114. </span>
  115. </span>
  116. </template>
  117. <!-- <template #planDays="{row,index}">
  118. <el-input v-model="row.planDays" v-if="row.isEdit" />
  119. <span v-else>{{row.planDays}}</span>
  120. </template> -->
  121. <template #planDays="{row,index}" >
  122. <template v-if="row.taskFinishedStatus === 1">
  123. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  124. <template #reference>
  125. <el-input v-model="row.planDays" v-if="row.isEdit" disabled clearable/>
  126. <span v-else>{{row.planDays}}</span>
  127. </template>
  128. </el-popover>
  129. </template>
  130. <span v-else>
  131. <el-input v-model="row.planDays" v-if="row.isEdit" disabled clearable/>
  132. <span v-else>{{row.planDays}}</span>
  133. </span>
  134. </template>
  135. <template #postTypeValue="{row,index}">
  136. <template v-if="row.taskFinishedStatus === 1">
  137. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  138. <template #reference>
  139. <span class="text-hover">{{row.postTypeValue}}</span>
  140. </template>
  141. </el-popover>
  142. </template>
  143. <span v-else>{{row.postTypeValue}}</span>
  144. </template>
  145. <template #staffCount="{row,index}">
  146. <template v-if="row.taskFinishedStatus === 1">
  147. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  148. <template #reference>
  149. <span class="text-hover">{{row.staffCount}}</span>
  150. </template>
  151. </el-popover>
  152. </template>
  153. <span v-else>{{row.staffCount}}</span>
  154. </template>
  155. <template #budgetStaffCost="{row,index}">
  156. <template v-if="row.taskFinishedStatus === 1">
  157. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  158. <template #reference>
  159. <span class="text-hover">{{row.budgetStaffCost}}</span>
  160. </template>
  161. </el-popover>
  162. </template>
  163. <span v-else>{{row.staffCount}}</span>
  164. </template>
  165. <template #budgetTravelExpense="{row,index}">
  166. <template v-if="row.taskFinishedStatus === 1">
  167. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  168. <template #reference>
  169. <span class="text-hover">{{row.budgetTravelExpense}}</span>
  170. </template>
  171. </el-popover>
  172. </template>
  173. <span v-else>{{row.staffCount}}</span>
  174. </template>
  175. <template #outsourceUnitPrice="{row,index}">
  176. <template v-if="row.taskFinishedStatus === 1">
  177. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  178. <template #reference>
  179. <span class="text-hover">{{row.outsourceUnitPrice}}</span>
  180. </template>
  181. </el-popover>
  182. </template>
  183. <span v-else>{{row.staffCount}}</span>
  184. </template>
  185. <template #outsourcePeopleCount="{row,index}">
  186. <template v-if="row.taskFinishedStatus === 1">
  187. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  188. <template #reference>
  189. <span class="text-hover">{{row.outsourcePeopleCount}}</span>
  190. </template>
  191. </el-popover>
  192. </template>
  193. <span v-else>{{row.staffCount}}</span>
  194. </template>
  195. <template #outsourceCountMoney="{row,index}">
  196. <template v-if="row.taskFinishedStatus === 1">
  197. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  198. <template #reference>
  199. <span class="text-hover">{{row.outsourceCountMoney}}</span>
  200. </template>
  201. </el-popover>
  202. </template>
  203. <span v-else>{{row.staffCount}}</span>
  204. </template>
  205. <template #otherBudgetMoney="{row,index}">
  206. <template v-if="row.taskFinishedStatus === 1">
  207. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  208. <template #reference>
  209. <span class="text-hover">{{row.otherBudgetMoney}}</span>
  210. </template>
  211. </el-popover>
  212. </template>
  213. <span v-else>{{row.staffCount}}</span>
  214. </template>
  215. <template #budgetCountMoney="{row,index}">
  216. <template v-if="row.taskFinishedStatus === 1">
  217. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  218. <template #reference>
  219. <span class="text-hover">{{row.budgetCountMoney}}</span>
  220. </template>
  221. </el-popover>
  222. </template>
  223. <span v-else>{{row.staffCount}}</span>
  224. </template>
  225. <template #budgetRemark="{row,index}">
  226. <template v-if="row.taskFinishedStatus === 1">
  227. <el-popover placement="top-start" title="" :width="200" :hide-after="0" :content="row?.outMoneyTips">
  228. <template #reference>
  229. <span class="text-hover">{{row.budgetRemark}}</span>
  230. </template>
  231. </el-popover>
  232. </template>
  233. <span v-else>{{row.staffCount}}</span>
  234. </template>
  235. <template #action="{row,index}">
  236. <el-button size="small" type="success" v-if="row.isEdit" @click="updateMainPlanClick(row)">保存</el-button>
  237. <el-button size="small" type="primary" v-else @click="row.isEdit = true" :disabled="row?.isShowEdit===0">编辑</el-button>
  238. <el-button size="small" type="warning" @click="relatedModalShow(row)">关联回款</el-button>
  239. <el-button size="small" type="danger" @click="subplanModalShow(row)" :disabled="row?.isShowChildren==0">分解子计划</el-button>
  240. </template>
  241. </HcTable>
  242. <template #action>
  243. <el-button size="large" type="info" hc-btn @click="goBackClick">
  244. <HcIcon name="arrow-go-back"/>
  245. <span>取消并返回</span>
  246. </el-button>
  247. <el-button size="large" type="primary" hc-btn @click="saveClick" :loading="saveLoaing">
  248. <HcIcon name="check-double"/>
  249. <span>提交保存</span>
  250. </el-button>
  251. </template>
  252. <!--分解子计划-->
  253. <HcDialog bgColor="#ffffff" isToBody isTable
  254. title="分解子计划" widths="80%"
  255. saveText="保存"
  256. :show="subplanModal"
  257. @close="subplanCloseClick"
  258. @save="updateChildPlanClick"
  259. >
  260. <template #extra>
  261. <el-button size="large" type="primary" @click="addplan">新增</el-button>
  262. </template>
  263. <HcTable :isIndex="false" :column="tableSubplanColumn" :datas="tableSubplanData">
  264. <template #planTaskType="{row,index}">
  265. <el-select v-model="row.planTaskType" clearable @change="changePlanTaskType">
  266. <el-option v-for="item in taskTypeList" :label="item.dictName" :value="item.id"/>
  267. </el-select>
  268. </template>
  269. <template #planTaskDesc="{row,index}">
  270. <el-input v-model="row.planTaskDesc" clearable/>
  271. </template>
  272. <template #planTarget="{row,index}">
  273. <el-input v-model="row.planTarget" clearable/>
  274. </template>
  275. <template #key7="{row,index}">
  276. <HcDatePicker :dates="[row.planStartTime,row.planEndTime]" @change="subbetweenTimeUpdate($event,row)" clearable/>
  277. </template>
  278. <template #planDays="{row,index}" >
  279. <el-input v-model="row.planDays" disabled clearable/>
  280. </template>
  281. <template #key9="{row,index}">
  282. <el-input v-model="row.key9" clearable/>
  283. </template>
  284. <template #action="{row,index}">
  285. <el-button size="small" type="primary" @click="delSubplan(row,index)" :disabled="row?.isShowDelete===0">删除</el-button>
  286. </template>
  287. </HcTable>
  288. </HcDialog>
  289. <!--关联回款里程碑-->
  290. <HcDialog bgColor="#ffffff" isToBody isTable :footer="false" :show="relatedModal" title="关联回款里程碑" widths="70%" @close="relatedCloseClick">
  291. <HcTable :column="tableRelatedColumn" :datas="tableRelatedData">
  292. <template #action="{row,index}">
  293. <el-button size="small" type="success" v-if="row.isRelation==1" @click="relation(row,0)">取消关联</el-button>
  294. <el-button size="small" type="primary" v-else @click="relation(row,1)">关联</el-button>
  295. </template>
  296. </HcTable>
  297. </HcDialog>
  298. </HcCard>
  299. </template>
  300. <script setup>
  301. import {useRouter, useRoute} from 'vue-router'
  302. import {onActivated, ref,watch,getCurrentInstance} from "vue";
  303. import projectApi from '~api/program/project.js';
  304. import contractApi from '~api/project/project-contract.js';
  305. import {getArrValue,getObjValue} from "js-fast-way"
  306. import { getuserList,getTaskType} from "~api/other";
  307. import {useAppStore} from "~src/store";
  308. const useAppState = useAppStore();
  309. //初始变量
  310. const router = useRouter()
  311. const useRoutes = useRoute()
  312. const dataId = ref(useRoutes?.query?.id ?? '')
  313. const dataType = ref(useRoutes?.query?.type ?? '')
  314. //缓存页面被激活时
  315. onActivated(() => {
  316. dataId.value = useRoutes?.query?.id ?? ''
  317. dataType.value = useRoutes?.query?.type ?? ''
  318. getUserDict()
  319. gettaskTypeList()
  320. if(dataType.value!=='add'){
  321. getPlanByProjectId()
  322. }else if(dataType.value=='add'){
  323. }
  324. })
  325. const detailData=ref({})
  326. const constructionData=ref([])
  327. const buildData=ref([])
  328. const supervisorUnitData=ref([])
  329. //获取详情
  330. const getPlanByProjectId=async()=>{
  331. const {error, code, data} = await projectApi.getPlanByProjectId({id: dataId.value})
  332. if (!error && code === 200) {
  333. console.log(getObjValue(data),'详情');
  334. detailData.value=getObjValue(data)
  335. constructionData.value=detailData.value?.constructUnit||[]
  336. buildData.value=detailData.value?.buildUnit||[]
  337. supervisorUnitData.value=detailData.value?.supervisorUnit||[]
  338. tabKey.value='construction'
  339. radioType.value=1
  340. // milestoneData.value=getArrValue(data)
  341. } else {
  342. // milestoneData.value=[]
  343. }
  344. }
  345. //获取所有员工
  346. const userList=ref([])
  347. //获取部门人员列表
  348. const getUserDict=async()=>{
  349. const {error, code, data} = await getuserList({tenantId:useAppState.tenantId})
  350. if (!error && code === 200) {
  351. userList.value = getArrValue(data)
  352. } else {
  353. userList.value = []
  354. }
  355. }
  356. //获取所有任务类型
  357. const taskTypeList=ref([])
  358. //获取部门人员列表
  359. const gettaskTypeList=async()=>{
  360. const {error, code, data} = await getTaskType()
  361. if (!error && code === 200) {
  362. taskTypeList.value = getArrValue(data['records'])
  363. } else {
  364. taskTypeList.value = []
  365. }
  366. }
  367. //类型tab数据和相关处理
  368. const tabKey = ref('')
  369. const tabTab = ref([
  370. {key: 'build', name: '施工单位成本'},
  371. {key: 'supervision', name: '监理单位成本'},
  372. {key: 'construction', name: '建设单位成本'}
  373. ]);
  374. const originTableData=ref([ {}])
  375. const tabChange = ({key}) => {
  376. tabKey.value = key
  377. if(key=='supervision'){
  378. tableData.value=supervisorUnitData.value&&supervisorUnitData.value[radioType.value]?.length>0?supervisorUnitData.value:originTableData.value
  379. detailData.value.supervisorUnit=tableData.value
  380. }else if(key=='construction'){
  381. tableData.value=constructionData.value[radioType.value]?.length>0?constructionData.value:originTableData.value
  382. detailData.value.constructUnit=tableData.value
  383. }else if(key=='bulid'){
  384. tableData.value=buildData.value[radioType.value]?.length>0?buildData.value:originTableData.value
  385. detailData.value.buildUnit=tableData.value
  386. }
  387. }
  388. const radioType = ref('')
  389. //深度监听
  390. watch(() => [
  391. radioType.value,
  392. tabKey.value
  393. ], ([radioType]) => {
  394. if(tabKey.value==='construction'){
  395. console.log(constructionData.value[radioType],'constructionData.value');
  396. tableData.value=constructionData.value[radioType]
  397. }else if(tabKey.value==='build'){
  398. console.log(buildData.value[radioType],'buildData.value');
  399. tableData.value=buildData.value[radioType]
  400. }else if(tabKey.value==='supervision'){
  401. console.log(supervisorUnitData.value[radioType],'supervisorUnitData.value');
  402. tableData.value=supervisorUnitData.value[radioType]
  403. }
  404. }, {deep: true})
  405. //表格
  406. const tableColumn = [
  407. {key: 'projectProcessValue', name: '项目环节', width: '160', align: 'center'},
  408. {key: 'budgetTypeValue', name: '预算类型', width: '160', align: 'center'},
  409. {key: 'taskDetailValue', name: '任务明细', width: '160', align: 'center'},
  410. {key: 'planTaskType', name: '任务类型', width: '160', align: 'center'},
  411. {key: 'planTaskDesc', name: '任务描述', minWidth: '200', align: 'center', isTooltip: true},
  412. {key: 'planTarget', name: '完成指标', minWidth: '200', align: 'center', isTooltip: true},
  413. {key: 'key7', name: '计划起止日期', width: '280', align: 'center'},
  414. {key: 'planDays', name: '预计工作量(小数/整数/天)', width: '160', align: 'center'},
  415. {key: 'postTypeValue', name: '投入岗位类型(日单价)', width: '160', align: 'center'},
  416. {key: 'staffCount', name: '投入人员数量', width: '160', align: 'center'},
  417. {key: 'budgetStaffCost', name: '预计人工成本(元)', width: '160', align: 'center'},
  418. {key: 'budgetTravelExpense', name: '预计差旅费(元)', width: '160', align: 'center'},
  419. {key: 'outsourceUnitPrice', name: '外包单价', width: '160', align: 'center'},
  420. {key: 'outsourcePeopleCount', name: '外包数量', width: '160', align: 'center'},
  421. {key: 'outsourceCountMoney', name: '外包金额', width: '160', align: 'center'},
  422. {key: 'otherBudgetMoney', name: '其他预算额', width: '160', align: 'center'},
  423. {key: 'budgetCountMoney', name: '总预算金额', width: '160', align: 'center'},
  424. {key: 'budgetRemark ', name: '测算备注', width: '160', align: 'center'},
  425. {key: 'returnedValue', name: '关联回款里程碑', minWidth: '200', isTooltip: true},
  426. {key: 'action', name: '操作', width: '280', align: 'center', fixed: 'right'},
  427. ]
  428. const tableData = ref([
  429. ])
  430. //表格行样式
  431. const tableRowStyle = ({row, rowIndex}) => {
  432. if (row.taskFinishedStatus === 1) {
  433. return {
  434. 'background-color': '#E99D42',
  435. '--el-fill-color-lighter': '#E99D42',
  436. '--el-table-row-hover-bg-color': '#E99D42'
  437. }
  438. } else if (row.taskFinishedStatus === 2 ) {
  439. return {
  440. 'background-color': '#7e9559',
  441. '--el-fill-color-lighter': '#7e9559',
  442. '--el-table-row-hover-bg-color': '#7e9559'
  443. }
  444. }
  445. }
  446. //日期时间被选择
  447. const betweenTime = ref(null)
  448. const betweenTimeUpdate = ({arr, query},item) => {
  449. item.planStartTime=arr[0]
  450. item.planEndTime=arr[1]
  451. item.betweenTime=arr
  452. // if(arr.length>0){
  453. // item.planDays=null
  454. // getWorkDays(item)
  455. // }else{
  456. // item.planDays=null
  457. // }
  458. }
  459. //日期时间被选择
  460. const subbetweenTime = ref(null)
  461. const subbetweenTimeUpdate = ({arr, query},item) => {
  462. console.log(item,'item');
  463. item.planStartTime=arr[0]
  464. item.planEndTime=arr[1]
  465. item.subbetweenTime=arr
  466. if(arr.length>0){
  467. item.planDays=null
  468. getWorkDays(item)
  469. }else{
  470. item.planDays=null
  471. }
  472. }
  473. const subplanModal = ref(false)
  474. const subPlanItem=ref({})
  475. const subplanModalShow = (row) => {
  476. console.log(row,'row');
  477. subPlanItem.value=row
  478. subplanModal.value = true
  479. tableSubplanData.value=row?.childrenList||[]
  480. }
  481. //表格
  482. const tableSubplanColumn = [
  483. {key: 'projectProcessValue', name: '项目环节', width: '160', align: 'center'},
  484. {key: 'budgetTypeValue', name: '预算类型', width: '160', align: 'center'},
  485. {key: 'taskDetailValue', name: '任务明细', width: '160', align: 'center'},
  486. {key: 'planTaskType', name: '任务类型', width: '160', align: 'center'},
  487. {key: 'planTaskDesc', name: '任务描述', minWidth: '200', align: 'center', isTooltip: true},
  488. {key: 'planTarget', name: '完成指标', minWidth: '200', align: 'center', isTooltip: true},
  489. {key: 'key7', name: '计划起止日期', width: '280', align: 'center'},
  490. {key: 'planDays', name: '预计工作量(小数/整数/天)', width: '160', align: 'center'},
  491. {key: 'action', name: '操作', width: '180', align: 'center', fixed: 'right'},
  492. ]
  493. const tableSubplanData = ref([
  494. ])
  495. const subplanCloseClick = () => {
  496. subplanModal.value = false
  497. }
  498. const addplan=()=>{
  499. tableSubplanData.value.push({
  500. projectProcessValue:subPlanItem.value?.projectProcessValue,
  501. budgetTypeValue:subPlanItem.value?.budgetTypeValue,
  502. taskDetailValue:subPlanItem.value?.taskDetailValue,
  503. planTaskType:subPlanItem.value?.planTaskType,
  504. isEdit:true
  505. })
  506. }
  507. const changePlanTaskType=(val)=>{
  508. tableSubplanData.value.forEach((ele)=>{
  509. ele.planTaskType=val
  510. })
  511. }
  512. const delSubplan=(row,index)=>{
  513. tableSubplanData.value.splice(index,1)
  514. }
  515. const relatedModal = ref(false)
  516. const rePlanid=ref('')
  517. const relatedModalShow = (row) => {
  518. relatedModal.value = true
  519. rePlanid.value=row.id
  520. getListByProjectId(row.projectId)
  521. }
  522. //保存获取工作时长
  523. const getWorkDays=async(row)=>{
  524. if(row?.planStartTime&&row?.planEndTime){
  525. const {error, code, data,msg} = await projectApi.getWorkDays( {
  526. startDate:row.planStartTime,
  527. endDate:row.planEndTime,
  528. })
  529. if (!error && code === 200) {
  530. row.planDays=data
  531. }
  532. }
  533. }
  534. //编辑主计划
  535. const updateMainPlanClick=async(row)=>{
  536. const {planTaskType}=row
  537. taskTypeList.value.forEach((ele)=>{
  538. if(ele.id===planTaskType){
  539. row.planTaskTypeValue=ele.dictName
  540. }
  541. })
  542. const {error, code, data,msg} = await projectApi.updateMainPlan(
  543. row
  544. )
  545. if (!error && code === 200) {
  546. if(data){
  547. row.taskFinishedStatus=data.taskFinishedStatus
  548. row.outMoneyTips=data.outMoneyTips
  549. row.planDays=data.planDays
  550. row.isShowEdit=data.isShowEdit
  551. row.isShowChildren=data.isShowChildren
  552. row.planTaskType=data.planTaskType
  553. row.planTaskTypeValue=data.planTaskTypeValue
  554. row.isShowChildren=data.isShowChildren
  555. row.isEdit=false
  556. }
  557. }
  558. }
  559. //编辑子计划传入父级
  560. const updateChildPlanClick=async()=>{
  561. subPlanItem.value.childrenList=tableSubplanData.value
  562. const {error, code, data,msg} = await projectApi.updateChildrenPlan(
  563. subPlanItem.value,
  564. )
  565. if (!error && code === 200) {
  566. window.$message.success(msg)
  567. tableData.value.forEach((ele)=>{
  568. if(ele.id==subPlanItem.value.id){
  569. ele.childrenList=tableSubplanData.value
  570. ele.planTarget=data.planTarget
  571. ele.planTaskDesc=data.planTaskDesc
  572. ele.taskFinishedStatus=data.taskFinishedStatus
  573. ele.planDays=data.planDays
  574. ele.outMoneyTips=data.outMoneyTips
  575. ele.isShowEdit=data.isShowEdit
  576. ele.isShowChildren=data.isShowChildren
  577. ele.planTaskType=data.planTaskType
  578. ele.planTaskTypeValue=data.planTaskTypeValue
  579. }
  580. })
  581. subplanModal.value = false
  582. }
  583. }
  584. //关联回款
  585. const relation=async(row,type)=>{
  586. const {error, code, data,msg} = await projectApi.relationPlanAndReturned( {
  587. planId:rePlanid.value,
  588. returnedId:row.id,
  589. type,
  590. projectId:row.projectId
  591. })
  592. if (!error && code === 200) {
  593. window.$message.success(msg)
  594. getListByProjectId(row.projectId).then()
  595. }
  596. }
  597. //表格
  598. const tableRelatedColumn = [
  599. {key: 'returnedCondition', name: '回款条件', minWidth: '260'},
  600. {key: 'shouldReturnedTime', name: '应收回款时间', width: '160', align: 'center'},
  601. {key: 'shouldReturnedMoney', name: '应收回款金额(元)', width: '160', align: 'center'},
  602. {key: 'reminderUserName', name: '催款执行人', width: '160', align: 'center'},
  603. {key: 'action', name: '操作', width: '130', align: 'center'},
  604. ]
  605. const tableRelatedData = ref([
  606. {id: 1, key1: 'xx', key2: 'xx', key3: 'xx', key4: 'xx', key5: 'xx', key6: 'xx', key7: 'xx', key8: 'xx', key9: 'xx', key10: 'xx'},
  607. {id: 2, key1: 'xx', key2: 'xx', key3: 'xx', key4: 'xx', key5: 'xx', key6: 'xx', key7: 'xx', key8: 'xx', key9: 'xx', key10: 'xx'},
  608. {id: 3, key1: 'xx', key2: 'xx', key3: 'xx', key4: 'xx', key5: 'xx', key6: 'xx', key7: 'xx', key8: 'xx', key9: 'xx', key10: 'xx'},
  609. {id: 4, key1: 'xx', key2: 'xx', key3: 'xx', key4: 'xx', key5: 'xx', key6: 'xx', key7: 'xx', key8: 'xx', key9: 'xx', key10: 'xx'},
  610. {id: 5, key1: 'xx', key2: 'xx', key3: 'xx', key4: 'xx', key5: 'xx', key6: 'xx', key7: 'xx', key8: 'xx', key9: 'xx', key10: 'xx'},
  611. {id: 6, key1: 'xx', key2: 'xx', key3: 'xx', key4: 'xx', key5: 'xx', key6: 'xx', key7: 'xx', key8: 'xx', key9: 'xx', key10: 'xx'},
  612. ])
  613. //合同里程碑
  614. const getListByProjectId=async(projectId,planId)=>{
  615. const {error, code, data} = await contractApi.getListByProjectId({projectId,planId:rePlanid.value})
  616. if (!error && code === 200) {
  617. tableRelatedData.value=getArrValue(data)
  618. } else {
  619. tableRelatedData.value=[]
  620. }
  621. }
  622. const relatedCloseClick = () => {
  623. relatedModal.value = false
  624. }
  625. //修改合同
  626. const updatePlan=async(obj)=>{
  627. console.log(obj,'编辑');
  628. saveLoaing.value=true;
  629. const {error, code, data,msg} = await projectApi.updatePlan( obj)
  630. saveLoaing.value=false;
  631. if (!error && code === 200) {
  632. window.$message.success(msg)
  633. getPlanByProjectId()
  634. }
  635. }
  636. const isEmptyObj=(obj)=> {
  637. let arr = Object.keys(obj);
  638. return(arr.length == 0)
  639. }
  640. //批量保存
  641. const saveLoaing=ref(false)
  642. const saveClick = () => {
  643. console.log(tableData.value,'tableData.value');
  644. console.log( detailData.value,' detailData.value');
  645. //取消空对象提交
  646. if(detailData.value?.supervisorUnit?.length>0){
  647. let suisnullObj= isEmptyObj(detailData.value?.supervisorUnit[0])
  648. if(suisnullObj===true){
  649. detailData.value.supervisorUnit=null
  650. }
  651. }
  652. if(detailData.value?.constructUnit?.length>0){
  653. let coisnullObj= isEmptyObj(detailData.value?.constructUnit[0])
  654. if(coisnullObj){
  655. detailData.value.constructUnit=null
  656. }
  657. }
  658. if(detailData.value?.buildUnit?.length>0){
  659. let buisnullObj= isEmptyObj(detailData.value?.buildUnit[0])
  660. if(buisnullObj){
  661. detailData.value.buildUnit=null
  662. }
  663. }
  664. updatePlan(detailData.value)
  665. }
  666. //取消并返回
  667. const goBackClick = () => {
  668. router.back()
  669. }
  670. </script>
  671. <style lang="scss">
  672. .hc-program-project-form-radio-group {
  673. position: relative;
  674. width: 100%;
  675. .el-radio-group, .el-radio-group .el-radio-button .el-radio-button__inner {
  676. width: 100%;
  677. }
  678. .el-radio-group .el-radio-button {
  679. flex: 1;
  680. }
  681. }
  682. </style>