Newer
Older
KaiFengPC / src / views / project / compensation / recordsRewardComponents / operate.vue
@zhangdeliang zhangdeliang on 23 May 19 KB 初始化项目
  1. <template>
  2. <div class="operate" v-loading.fullscreen.lock="loading" element-loading-text="加载中..." element-loading-background="rgba(0, 0, 0, 0.6)">
  3. <div>
  4. <el-steps :active="active" finish-status="success" align-center class="steps">
  5. <el-step title="验收申请提交" />
  6. <el-step title="验收审查" />
  7. <el-step title="验收合格" />
  8. </el-steps>
  9. <el-form ref="ruleForm" :model="form" :rules="rules" :disabled="opts.type === 'view'">
  10. <el-row :gutter="20">
  11. <el-col :span="8">
  12. <el-form-item label="项目名称:" prop="projectNo" class="formItem110">
  13. <el-select v-model="form.projectNo" placeholder="请选择项目名称" style="width: 100%" @change="projectChange">
  14. <el-option v-for="dict in projectList" :key="dict.projectNo" :label="dict.projectName" :value="dict.projectNo" />
  15. </el-select>
  16. </el-form-item>
  17. </el-col>
  18. <el-col :span="8">
  19. <el-form-item label="项目编码:" prop="projectNo" class="formItem110">
  20. <el-input v-model="form.projectNo" disabled />
  21. </el-form-item>
  22. </el-col>
  23. <el-col :span="8">
  24. <el-form-item label="项目类型:" prop="projectTypeName" class="formItem110">
  25. <el-input v-model="form.projectTypeName" disabled />
  26. </el-form-item>
  27. </el-col>
  28. <el-col :span="8">
  29. <el-form-item label="申请时间:" prop="applicationTime">
  30. <el-date-picker
  31. style="width: 100%"
  32. clearable
  33. format="YYYY-MM-DD"
  34. value-format="YYYY-MM-DD HH:mm:ss"
  35. v-model="form.applicationTime"
  36. type="date"
  37. range-separator="到"
  38. placeholder="申请时间"
  39. />
  40. </el-form-item>
  41. </el-col>
  42. <el-col :span="8">
  43. <el-form-item label="海绵占地面积:" prop="spongeProjectArea" class="formItem110">
  44. <el-input v-model="form.spongeProjectArea" />
  45. </el-form-item>
  46. </el-col>
  47. <el-col :span="8">
  48. <el-form-item label="建设单位:" prop="chargeDepartment" class="formItem110">
  49. <el-input v-model="form.chargeDepartment" />
  50. </el-form-item>
  51. </el-col>
  52. <el-col :span="8">
  53. <el-form-item label="项目总投资(万元):" prop="accomplishTotalInvest">
  54. <el-input v-model="form.accomplishTotalInvest" placeholder="请输入完成项目总投资" />
  55. </el-form-item>
  56. </el-col>
  57. <el-col :span="8">
  58. <el-form-item label="海绵投资(万元):" prop="spongeInvest">
  59. <el-input v-model="form.spongeInvest" placeholder="请输入海绵投资" />
  60. </el-form-item>
  61. </el-col>
  62. <el-col :span="8">
  63. <el-form-item label="年径流量总控制率%:" prop="annualRunoffTotalControlRate">
  64. <el-input v-model="form.annualRunoffTotalControlRate" placeholder="请输入年径流量总控制率" />
  65. </el-form-item>
  66. </el-col>
  67. <el-col :span="8">
  68. <el-form-item label="年SS总量去除率不低于%:" prop="turbidityRemovalRate">
  69. <el-input v-model="form.turbidityRemovalRate" placeholder="请输入年SS总量去除率不低于" />
  70. </el-form-item>
  71. </el-col>
  72. <el-col :span="8">
  73. <el-form-item label="申请奖励金额(万元):" prop="bonusAmountApplied">
  74. <el-input v-model="form.bonusAmountApplied" placeholder="请输入申请奖励金额" />
  75. </el-form-item>
  76. </el-col>
  77. </el-row>
  78. <el-divider content-position="left">海绵建设内容</el-divider>
  79. <div class="pl20">
  80. <el-form-item label="(定量填写海绵设施面积、体积等信息):" prop="achievementTarget" class="formItem140">
  81. <el-input v-model="form.achievementTarget" type="textarea" resize="none" />
  82. </el-form-item>
  83. <!-- <el-form-item label="海绵设施类型及规模:" prop="spongeTypeScale" class="formItem140">
  84. <el-input v-model="form.spongeTypeScale" type="textarea" resize="none" :disabled="opts.type === 'audit'" />
  85. </el-form-item> -->
  86. <el-form-item label="其他情况说明:" prop="otherDescription" class="formItem140">
  87. <el-input v-model="form.otherDescription" type="textarea" resize="none" :disabled="opts.type === 'audit'" />
  88. </el-form-item>
  89. </div>
  90. <el-divider content-position="left">奖补申请资料上传</el-divider>
  91. <div class="box" v-for="(item, i) in form.projectProcessAttachmentSaveRequestList">
  92. <el-row :gutter="20">
  93. <el-col :span="12">
  94. <el-form-item
  95. :label="`${item.name}:`"
  96. :prop="'projectProcessAttachmentSaveRequestList.' + i + '.' + 'filieDescription'"
  97. class="formItem300"
  98. :rules="opts.type === 'add' || (i < 10 && opts.type === 'audit') ? rules['filieDescription'] : []"
  99. >
  100. <el-input v-model="item.filieDescription" />
  101. </el-form-item>
  102. </el-col>
  103. <el-col :span="2">
  104. <el-upload
  105. class="upload-demo"
  106. action="/system/upload"
  107. :headers="uploadHeader"
  108. :before-upload="rawFile => beforeUpload(rawFile, ['.rar', '.zip', '.doc', '.docx', '.pdf'])"
  109. :on-success="response => onSuccess(response, item)"
  110. :on-error="(error, uploadFile, uploadFiles) => onError(error, uploadFile, uploadFiles)"
  111. :show-file-list="false"
  112. >
  113. <el-button icon="Upload" size="mini" type="primary" :disabled="i < 10 && opts.type === 'audit'">上传文件</el-button>
  114. </el-upload>
  115. </el-col>
  116. <el-col :span="10">
  117. <span class="tips">支持文件格式:.rar .zip .doc .docx .pdf ,单个文件不能超过500kb</span>
  118. </el-col>
  119. </el-row>
  120. <el-row :gutter="20">
  121. <el-col :span="12" :offset="12">
  122. <div class="fileSaveRequestList">
  123. <div class="file-item" v-for="(it, index) in item.fileList">
  124. <span>{{ it.name }}</span>
  125. <el-button type="danger" link @click="reoveFile(item.fileList, index)" :disabled="i < 10 && opts.type === 'audit'"
  126. >删除</el-button
  127. >
  128. </div>
  129. </div>
  130. </el-col>
  131. </el-row>
  132. </div>
  133. <el-row :gutter="20">
  134. <el-col :span="12">
  135. <el-form-item label="指定处理人:" prop="dealUsers" class="formItem110">
  136. <el-select v-model="form.dealUsers" placeholder="请选择指定处理人" style="width: 100%" :disabled="opts.type === 'audit'">
  137. <el-option v-for="dict in userLists" :key="dict.userId" :label="dict.nickName" :value="dict.userId" />
  138. </el-select>
  139. </el-form-item>
  140. </el-col>
  141. <el-col :span="12">
  142. <el-form-item label="流程抄送人:" prop="pushUsers" class="formItem110">
  143. <el-select v-model="form.pushUsers" placeholder="请选择流程抄送人" style="width: 100%" :disabled="opts.type === 'audit'">
  144. <el-option v-for="dict in userLists" :key="dict.userId" :label="dict.nickName" :value="dict.userId" />
  145. </el-select>
  146. </el-form-item>
  147. </el-col>
  148. </el-row>
  149. <el-form-item label="审核意见:" prop="approveComment" class="formItem110" v-if="opts.type === 'audit'">
  150. <el-input v-model="form.approveComment" type="textarea" resize="none" />
  151. </el-form-item>
  152. <el-divider content-position="left" v-if="form.status && form.status !== 'start'">流程日志</el-divider>
  153. <div class="stapesBox" v-if="form.status && form.status !== 'start'">
  154. <el-steps direction="vertical" :active="stapesDate.length">
  155. <el-step v-for="i in stapesDate" :title="i.activityName" style="width: 300px">
  156. <template #description>
  157. <div class="direction">时间:{{ i.endTime }}</div>
  158. <div class="direction">分配人:{{ i.assigneeName }}</div>
  159. <div class="direction">任务备注:{{ i.comment }}</div>
  160. </template>
  161. </el-step>
  162. </el-steps>
  163. </div>
  164. </el-form>
  165. </div>
  166. </div>
  167. </template>
  168.  
  169. <script setup>
  170. import { required } from '@/utils/validate-helper';
  171. import { inheritAttr } from '@/utils/v3';
  172. import { getProjectInfoNewList, getDicts } from '@/api/project/projectApproval';
  173. import { projectInfoNewDetail } from '@/api/project/projectInformationNew';
  174. import {
  175. projectCompletionAcceptanceeAdd,
  176. projectCompletionAcceptanceeEdit,
  177. projectCompletionAcceptanceeStartWorkFlow,
  178. projectCompletionAcceptanceeDetail,
  179. projectCompletionAcceptanceApprove,
  180. } from '@/api/project/recordsReward';
  181. import { workflowProcess, userList } from '@/api/project/constructionPermits';
  182. import uploadHeader from '@/utils/getUploadHeader';
  183. import useUserStore from '@/store/modules/user';
  184. const { proxy } = getCurrentInstance();
  185. const emit = defineEmits(['close']);
  186. const props = defineProps({
  187. curRow: {
  188. type: Object,
  189. default: () => ({}),
  190. },
  191. opts: {
  192. type: Object,
  193. default: () => ({}),
  194. },
  195. types: {
  196. type: Array,
  197. default: [],
  198. },
  199. companyList: {
  200. type: Array,
  201. default: () => [],
  202. },
  203. });
  204. const { acceptance_material } = proxy.useDict('acceptance_material');
  205. const { curRow, opts } = props;
  206. const loading = ref(false);
  207. const active = ref(0);
  208. const form = reactive({
  209. achievementTarget: '',
  210. bonusAmountApplied: '',
  211. turbidityRemovalRate: '',
  212. annualRunoffTotalControlRate: '',
  213. spongeInvest: '',
  214. accomplishTotalInvest: '',
  215. spongeProjectArea: '',
  216. projectName: '',
  217. projectNo: '',
  218. projectTypeId: '',
  219. projectTypeName: '',
  220. chargeUser: '',
  221. phone: '',
  222. applicationTime: '',
  223. chargeDepartment: '',
  224. designUnit: '',
  225. designUnitName: '',
  226. constructUnit: '',
  227. constructUnitName: '',
  228. supervisorUnit: '',
  229. supervisorUnitName: '',
  230. achievementTarget: '',
  231. spongeTypeScale: '',
  232. otherDescription: '',
  233. projectProcessAttachmentSaveRequestList: [],
  234. fileSaveRequestList: [],
  235. dealUsers: '',
  236. pushUsers: '',
  237. status: '',
  238. approveComment: '',
  239. workflowInstanceId: '',
  240. });
  241.  
  242. const rules = reactive({
  243. projectName: required('项目名称'),
  244. projectNo: required('项目编码'),
  245. projectTypeId: required('项目类型'),
  246. chargeUser: required('联系人'),
  247. phone: required('联系电话'),
  248. chargeDepartment: required('建设单位'),
  249. designUnit: required('设计单位'),
  250. constructUnit: required('施工单位'),
  251. supervisorUnit: required('监理单位'),
  252. achievementTarget: required('建设指标达成情况'),
  253. spongeTypeScale: required('海绵设施类型及规模'),
  254. otherDescription: required('其他情况说明'),
  255. filieDescription: required('内容'),
  256. approveComment: required('审核意见'),
  257. });
  258.  
  259. const stapesDate = ref([]);
  260.  
  261. const projectList = ref([]);
  262. const userLists = ref([]);
  263.  
  264. const getUserList = async () => {
  265. const res = await userList();
  266. if (res?.code !== 200) return;
  267. userLists.value = res?.data || [];
  268. };
  269.  
  270. const getProjectList = async () => {
  271. const res = await getProjectInfoNewList();
  272. if (res?.code !== 200) return;
  273. projectList.value = res?.data || [];
  274. if (opts.type === 'add' && projectList.value.length) {
  275. projectChange(projectList.value[0].projectNo);
  276. }
  277. };
  278.  
  279. const projectChange = async val => {
  280. const res = await projectInfoNewDetail(val);
  281. if (res?.code !== 200) return;
  282. inheritAttr(res.data, form);
  283. // form.projectTypeIdName = props.types.find(it => it.id === form.projectTypeId)?.projectTypeName;
  284. form.designUnitName = props.companyList.find(it => it.id === form.designUnit)?.unitName || '';
  285. form.constructUnitName = props.companyList.find(it => it.id === form.constructUnit)?.unitName || '';
  286.  
  287. form.achievementTarget = '';
  288. form.spongeTypeScale = '';
  289. form.otherDescription = '';
  290. form.dealUsers = '';
  291. form.pushUsers = '';
  292. getDictMaps('acceptance_material');
  293. };
  294.  
  295. const getDictMaps = async dictType => {
  296. const res = await getDicts(dictType);
  297. if (res?.code !== 200) return;
  298. if (res?.data) {
  299. form.projectProcessAttachmentSaveRequestList = [];
  300. for (const item of res.data) {
  301. form.projectProcessAttachmentSaveRequestList.push({
  302. fileList: [],
  303. dictData: item.dictValue,
  304. dictType: item.dictType,
  305. filieDescription: '',
  306. projectNo: '',
  307. name: item.dictLabel,
  308. });
  309. }
  310. form.projectProcessAttachmentSaveRequestList = form.projectProcessAttachmentSaveRequestList.slice(0, 10);
  311. }
  312.  
  313. setTimeout(() => {
  314. if (proxy.$refs.ruleForm) {
  315. proxy.$refs.ruleForm.clearValidate();
  316. }
  317. });
  318. };
  319.  
  320. const getProjectTypeFileList = async (fileGroup, type, list, filterList) => {
  321. for (const key in fileGroup) {
  322. if (key === type) {
  323. if (Object.hasOwnProperty.call(fileGroup, key)) {
  324. const element = fileGroup[key];
  325. for (const item of element) {
  326. const info = filterList.value.find(it => it.value === item.dictData);
  327. if (!info) continue;
  328. list.push({
  329. fileList: item.fileList,
  330. dictData: item.dictData,
  331. dictType: item.dictType,
  332. filieDescription: item.filieDescription,
  333. projectNo: item.projectNo,
  334. name: info.label,
  335. });
  336. }
  337. }
  338. }
  339. }
  340. };
  341.  
  342. const getDetail = async () => {
  343. const res = await projectCompletionAcceptanceeDetail(curRow.id);
  344. if (res?.code !== 200) return;
  345. inheritAttr(res.data, form);
  346. // form.projectTypeIdName = props.types.find(it => it.id === form.projectTypeId)?.projectTypeName;
  347. form.designUnitName = props.companyList.find(it => it.id === form.designUnit)?.unitName || '';
  348. form.constructUnitName = props.companyList.find(it => it.id === form.constructUnit)?.unitName || '';
  349. form.dealUsers = form.dealUsers * 1 || '';
  350. form.pushUsers = form.pushUsers * 1 || '';
  351.  
  352. const fileGroup = res.data.fileGroup;
  353. form.projectProcessAttachmentSaveRequestList = [];
  354. getProjectTypeFileList(fileGroup, 'acceptance_material', form.projectProcessAttachmentSaveRequestList, acceptance_material);
  355.  
  356. if (form.status && form.status !== 'start') {
  357. workflowProcessM(res.data.id);
  358. if (form.status === 'projectInquiry') {
  359. active.value = 1;
  360. } else if (form.status === 'manualReview') {
  361. active.value = 2;
  362. }
  363. }
  364.  
  365. if (opts.type === 'audit') {
  366. const res = await getDicts('acceptance_material');
  367. if (res?.code !== 200) return;
  368. if (res?.data) {
  369. res.data = res.data.slice(10);
  370. for (const item of res.data) {
  371. form.projectProcessAttachmentSaveRequestList.push({
  372. fileList: [],
  373. dictData: item.dictValue,
  374. dictType: item.dictType,
  375. filieDescription: '',
  376. projectNo: '',
  377. name: item.dictLabel,
  378. });
  379. }
  380. }
  381. }
  382. };
  383.  
  384. const beforeUpload = rawFile => {
  385. console.log(rawFile);
  386. if (rawFile.name.length > 50) {
  387. proxy.$modal.msgError(`文件名称过长(50个字符以内),请先修改再上传!`);
  388. return false;
  389. }
  390. return true;
  391. };
  392.  
  393. const onSuccess = (response, item) => {
  394. console.log(response);
  395. item.fileList.push({
  396. ...response.data,
  397. refType: item.dictType,
  398. refField: item.dictData,
  399. });
  400. };
  401.  
  402. const onError = (error, uploadFile, uploadFiles) => {
  403. console.log(error, uploadFile, uploadFiles);
  404. };
  405.  
  406. const reoveFile = (fileList, index) => {
  407. proxy.$modal
  408. .confirm('是否确认删除?')
  409. .then(async () => {
  410. fileList.splice(index, 1);
  411. })
  412. .catch(() => {});
  413. };
  414.  
  415. const submit = type => {
  416. proxy.$refs.ruleForm.validate(async (valid, fields) => {
  417. if (valid) {
  418. if (type === 2) {
  419. if (!form.dealUsers) return proxy.$modal.msgError('请指定处理人!');
  420. if (!form.pushUsers) return proxy.$modal.msgError('请指定抄送人!');
  421. }
  422. loading.value = true;
  423. const params = JSON.parse(JSON.stringify(form));
  424. params.status = '';
  425. for (const item of params.projectProcessAttachmentSaveRequestList) {
  426. item.projectNo = params.projectNo;
  427. for (const it of item.fileList) {
  428. params.fileSaveRequestList.push(it);
  429. }
  430. }
  431. console.log(params);
  432. let methed = '';
  433. if (type === 1) {
  434. if (curRow?.id) {
  435. params.id = curRow.id;
  436. methed = projectCompletionAcceptanceeEdit;
  437. } else {
  438. methed = projectCompletionAcceptanceeAdd;
  439. }
  440. } else {
  441. if (curRow?.id) {
  442. params.id = curRow.id;
  443. }
  444. methed = projectCompletionAcceptanceeStartWorkFlow;
  445. }
  446. const res = await methed(params);
  447. loading.value = false;
  448. if (res?.code !== 200) return;
  449. proxy.$modal.msgSuccess('操作成功!');
  450. emit('close');
  451. } else {
  452. console.log('error submit!', fields);
  453. }
  454. });
  455. };
  456.  
  457. const handleAudit = result => {
  458. proxy.$refs.ruleForm.validate(async (valid, fields) => {
  459. if (valid) {
  460. const params = JSON.parse(JSON.stringify(form));
  461. delete params.list1;
  462. params.fileSaveRequestList = [];
  463. for (let i = 0; i < params.projectProcessAttachmentSaveRequestList.length; i++) {
  464. if (opts.type === 'audit' && i < 10) continue;
  465. const item = params.projectProcessAttachmentSaveRequestList[i];
  466. if (result === 'true' && !item.filieDescription) {
  467. return proxy.$modal.msgError(`${item.name}文件说明不能为空!`);
  468. }
  469. item.projectNo = params.projectNo;
  470. for (const it of item.fileList) {
  471. params.fileSaveRequestList.push(it);
  472. }
  473. }
  474. loading.value = true;
  475. if (opts.type === 'audit') {
  476. params.projectProcessAttachmentSaveRequestList = params.projectProcessAttachmentSaveRequestList.slice(10);
  477. }
  478. params.approveResult = result;
  479. params.submitUserId = useUserStore().userId;
  480. params.id = curRow.id;
  481. console.log(params);
  482. try {
  483. const res = await projectCompletionAcceptanceApprove(params);
  484. loading.value = false;
  485. if (res?.code !== 200) return;
  486. proxy.$modal.msgSuccess('操作成功!');
  487. emit('close');
  488. } catch (error) {
  489. loading.value = false;
  490. }
  491. } else {
  492. console.log('error submit!', fields);
  493. }
  494. });
  495. };
  496.  
  497. //获取流程日志
  498. const workflowProcessM = async id => {
  499. let params = {
  500. businessKey: id,
  501. workflowKey: 'projectBonusNoticeRecord',
  502. workflowUserId: '',
  503. };
  504. let { data } = await workflowProcess(params);
  505. stapesDate.value = data;
  506. };
  507.  
  508. onMounted(() => {
  509. getProjectList();
  510. getUserList();
  511. if (curRow?.id) {
  512. getDetail();
  513. }
  514. });
  515.  
  516. defineExpose({
  517. submit,
  518. handleAudit,
  519. });
  520. </script>
  521.  
  522. <style lang="scss" scoped>
  523. .operate {
  524. .steps {
  525. margin-bottom: 20px;
  526. }
  527.  
  528. .pl20 {
  529. padding-left: 20px;
  530. }
  531.  
  532. .tips {
  533. margin-left: 10px;
  534. line-height: 30px;
  535. }
  536.  
  537. .mb5 {
  538. margin-bottom: 5px;
  539. }
  540.  
  541. .mb0 {
  542. margin-bottom: 0;
  543. }
  544.  
  545. .fileSaveRequestList {
  546. .file-item {
  547. white-space: nowrap;
  548. display: flex;
  549. align-items: center;
  550. .del {
  551. flex-shrink: 0;
  552. color: #f56c6c;
  553. cursor: pointer;
  554. margin-left: 10px;
  555. }
  556. }
  557. }
  558. .box {
  559. margin-bottom: 10px;
  560. }
  561.  
  562. .direction {
  563. min-width: 190px;
  564. }
  565.  
  566. .stapesBox {
  567. min-height: 100px;
  568. margin-bottom: 30px;
  569. margin-left: 30px;
  570. }
  571. }
  572. </style>