index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. <template>
  2. <div class="processApproval">
  3. <div class="left-card">
  4. <div class="top">
  5. <div class="commons-title title">
  6. {{ route.query.flowName || "流程标题(发起)" }}
  7. </div>
  8. <div class="line"></div>
  9. <!-- 报价单 -->
  10. <template v-if="flowForm.flowKey == 'sale_quotation_flow'">
  11. <PriceSheetEHSD
  12. ref="makeDom"
  13. v-if="flowForm.tenantType === 'EHSD'"
  14. :queryData="queryData.data"
  15. ></PriceSheetEHSD>
  16. </template>
  17. <!-- 样品单 -->
  18. <template v-else-if="flowForm.flowKey == 'sample_flow'">
  19. <SampleEHSD ref="makeDom" :queryData="queryData.data"></SampleEHSD>
  20. </template>
  21. <!-- 销售合同 -->
  22. <template v-else-if="flowForm.flowKey == 'contract_flow'">
  23. <ContractEHSD
  24. ref="makeDom"
  25. :queryData="queryData.data"
  26. @auxiliaryChange="(e) => getAuxiliaryData(e)"
  27. ></ContractEHSD>
  28. </template>
  29. <!-- 销售合同变更 -->
  30. <template v-else-if="flowForm.flowKey == 'contract_update_flow'">
  31. <ContractChangeEHSD
  32. ref="makeDom"
  33. :queryData="queryData.data"
  34. @auxiliaryChange="(e) => getAuxiliaryData(e)"
  35. ></ContractChangeEHSD>
  36. </template>
  37. <!-- 申购 -->
  38. <SendSubscribe
  39. ref="makeDom"
  40. @auxiliaryChange="(e) => getAuxiliaryData(e)"
  41. v-else-if="flowForm.flowKey == 'subscribe_flow'"
  42. :queryData="queryData.data"
  43. ></SendSubscribe>
  44. <!-- 样品单采购、交接单采购 -->
  45. <template v-else-if="flowForm.flowKey == 'ehsd_purchase_flow'">
  46. <PurchaseEHSD
  47. ref="makeDom"
  48. :queryData="queryData.data"
  49. v-if="flowForm.submitType === '10'"
  50. @auxiliaryChange="(e) => getAuxiliaryData(e)"
  51. ></PurchaseEHSD>
  52. <SendPurchase
  53. ref="makeDom"
  54. :queryData="queryData.data"
  55. v-else
  56. @auxiliaryChange="(e) => getAuxiliaryData(e)"
  57. ></SendPurchase>
  58. </template>
  59. <!-- 采购付款 -->
  60. <PurchasePayment
  61. ref="makeDom"
  62. @auxiliaryChange="(e) => getAuxiliaryData(e)"
  63. v-else-if="flowForm.flowKey == 'pay_flow'"
  64. :queryData="queryData.data"
  65. ></PurchasePayment>
  66. <!-- 请款 -->
  67. <SendFunds
  68. ref="makeDom"
  69. v-else-if="flowForm.flowKey == 'account_request_funds_flow'"
  70. :queryData="queryData.data"
  71. ></SendFunds>
  72. </div>
  73. <div class="bottom" v-if="route.query.processType != 20">
  74. <div class="commons-title title">处理意见</div>
  75. <el-form :model="flowForm" :rules="flowRules" ref="flowFormDom">
  76. <el-form-item prop="remark" label-width="0px" label="">
  77. <el-input
  78. type="textarea"
  79. placeholder="请输入"
  80. v-model="flowForm.remark"
  81. >
  82. </el-input>
  83. </el-form-item>
  84. <el-form-item prop="remark" label-width="80px" label="附件上传">
  85. <el-upload
  86. v-model:fileList="flowForm.fileList"
  87. action="https://winfaster.obs.cn-south-1.myhuaweicloud.com"
  88. :data="uploadData"
  89. multiple
  90. :before-upload="uploadFile"
  91. :on-success="handleSuccess"
  92. :on-preview="onPreviewFile"
  93. >
  94. <el-button>选择</el-button>
  95. </el-upload>
  96. </el-form-item>
  97. <el-form-item>
  98. <el-button
  99. type="primary"
  100. v-if="approvalRecordData.buttonInfoList.length == 0"
  101. @click="handleSubmit"
  102. :loading="btnLoading"
  103. >提交</el-button
  104. >
  105. <el-button
  106. type="primary"
  107. v-else
  108. v-for="i in approvalRecordData.buttonInfoList"
  109. :key="i.type"
  110. :loading="btnLoading"
  111. @click="handleSubmit(i.type)"
  112. >{{ i.name }}</el-button
  113. >
  114. </el-form-item>
  115. </el-form>
  116. </div>
  117. </div>
  118. <div class="right-card">
  119. <el-tabs v-model="activeName" class="demo-tabs">
  120. <el-tab-pane label="审批记录" name="first">
  121. <ul class="flow-chart">
  122. <li
  123. v-for="item in recordList"
  124. :key="item.id"
  125. :class="
  126. !route.query.id
  127. ? ''
  128. : item.status == 2
  129. ? 'flow-orange'
  130. : item.status == 3 && !route.query.id
  131. ? 'flow-orange'
  132. : item.status == 3 && route.query.id
  133. ? 'flow-grey'
  134. : ''
  135. "
  136. >
  137. <div class="left-icon">
  138. <i class="iconfont icon-iconm_daick"></i>
  139. <i class="iconfont icon-icomx_quertj1 right-btm-status"></i>
  140. </div>
  141. <div class="right-conetnt">
  142. <div class="name">{{ item.nodeName }}</div>
  143. <div class="remark">
  144. <div class="label">
  145. <span v-if="item.status != 3">办理人:</span
  146. >{{ item.processedUser
  147. }}<span class="time">{{ item.processedDate }}</span>
  148. </div>
  149. {{ item.remark }}
  150. <div
  151. v-for="j in fileObj[item.flowExampleDetailId]"
  152. v-if="fileObj[item.flowExampleDetailId]"
  153. >
  154. <a
  155. :href="j.fileUrl"
  156. style="color: #409eff; line-height: 30px"
  157. >{{ j.fileName }}</a
  158. >
  159. </div>
  160. </div>
  161. </div>
  162. <div class="line"></div>
  163. </li>
  164. </ul>
  165. </el-tab-pane>
  166. <el-tab-pane
  167. label="决策辅助"
  168. name="second"
  169. v-if="auxiliaryData.length > 0"
  170. >
  171. <div style="overflow: auto; height: calc(100vh - 200px)">
  172. <auxiliary :data="auxiliaryData"></auxiliary>
  173. </div>
  174. </el-tab-pane>
  175. </el-tabs>
  176. </div>
  177. <el-dialog title="下一处理人" width="400" v-model="dialogVisible">
  178. <el-form :model="flowForm">
  179. <el-form-item prop="remark" label="处理人">
  180. <el-select
  181. v-model="flowForm.handleUserId"
  182. placeholder="请选择"
  183. filterable
  184. style="width: 100%"
  185. >
  186. <el-option
  187. v-for="item in nextHandleUser"
  188. :label="item.name"
  189. :value="item.id"
  190. >
  191. </el-option>
  192. </el-select>
  193. </el-form-item>
  194. <el-form-item>
  195. <div style="width: 100%; text-align: center">
  196. <el-button type="primary" @click="handleSelectUser">提交</el-button>
  197. </div>
  198. </el-form-item>
  199. </el-form>
  200. </el-dialog>
  201. </div>
  202. </template>
  203. <script setup name="ProcessApproval">
  204. import useTagsViewStore from "@/store/modules/tagsView.js";
  205. import { useRouter, useRoute } from "vue-router";
  206. // 消息提示
  207. import { ElMessage, ElMessageBox } from "element-plus";
  208. //决策辅助
  209. import auxiliary from "./auxiliary";
  210. // 报价单-EHSD
  211. import PriceSheetEHSD from "@/components/process/EHSD/PriceSheet";
  212. // 销售合同-EHSD
  213. import ContractEHSD from "@/components/process/EHSD/Contract";
  214. // 销售合同变更-EHSD
  215. import ContractChangeEHSD from "@/components/process/EHSD/ContractChange";
  216. // 样品单-EHSD
  217. import SampleEHSD from "@/components/process/EHSD/Sample";
  218. // 采购交接单-EHSD
  219. import PurchaseEHSD from "@/components/process/EHSD/Purchase";
  220. //申购发起
  221. import SendSubscribe from "@/components/process/SendSubscribe";
  222. //采购发起
  223. import SendPurchase from "@/components/process/SendPurchase";
  224. //请款发起
  225. import SendFunds from "@/components/process/SendFunds";
  226. // 采购付款
  227. import PurchasePayment from "@/components/process/PurchasePayment";
  228. import { ref } from "vue";
  229. const router = useRouter();
  230. const route = useRoute();
  231. // tab切换逻辑
  232. const activeName = ref("first");
  233. let auxiliaryData = ref([]);
  234. const getAuxiliaryData = (data) => {
  235. auxiliaryData.value = data;
  236. };
  237. const btnLoading = ref(false);
  238. // 意见表单
  239. const flowForm = reactive({
  240. flowKey: "",
  241. tenantType: "",
  242. handleUserId: "",
  243. remark: "",
  244. data: {},
  245. fileList: [],
  246. });
  247. const uploadData = ref({});
  248. const flowRules = reactive({
  249. // remark: [{ required: true, message: "请输入处理意见", trigger: "blur" }],
  250. });
  251. //组件实例
  252. const { proxy } = getCurrentInstance();
  253. const makeDom = ref(null);
  254. const flowFormDom = ref(null);
  255. let dialogVisible = ref(false);
  256. const nextHandleUser = ref([]);
  257. const handleSelectUser = () => {
  258. if (!flowForm.handleUserId) {
  259. return ElMessage({
  260. message: "请选择下一节点处理人!",
  261. type: "info",
  262. });
  263. }
  264. handleSubmit();
  265. };
  266. const handleResult = (res) => {
  267. if (res !== null && res.success) {
  268. skipPage();
  269. } else {
  270. dialogVisible.value = true;
  271. nextHandleUser.value = res.userList;
  272. }
  273. };
  274. const uploadFile = async (file) => {
  275. const res = await proxy.post("/fileInfo/getSing", { fileName: file.name });
  276. uploadData.value = res.uploadBody;
  277. file.id = res.id;
  278. file.fileName = res.fileName;
  279. file.fileUrl = res.fileUrl;
  280. file.uploadState = true;
  281. return true;
  282. };
  283. const handleSuccess = (any, UploadFile) => {
  284. UploadFile.raw.uploadState = false;
  285. };
  286. const onPreviewFile = (file) => {
  287. window.open(file.raw.fileUrl, "_blank");
  288. };
  289. // 提交逻辑
  290. const handleSubmit = async (_type) => {
  291. try {
  292. // 调用发起组件的提交事件
  293. const flag = await makeDom.value.handleSubmit();
  294. if (flag) {
  295. flowFormDom.value.validate((valid) => {
  296. btnLoading.value = true;
  297. if (valid) {
  298. const data = { ...makeDom.value.getFormData() };
  299. if (flowForm.flowKey == "subscribe_flow") {
  300. } else if (flowForm.flowKey == "account_request_funds_flow") {
  301. } else if (flowForm.flowKey == "sale_quotation_flow") {
  302. if (flowForm.tenantType === "EHSD") {
  303. data.ehsdJson = JSON.stringify({
  304. deliveryTime: data.deliveryTime,
  305. });
  306. data.quotationProductList = data.quotationProductList.map(
  307. (item) => {
  308. let ehsdJson = JSON.stringify({
  309. packMethod: item.packMethod,
  310. tradeMethods: item.tradeMethods,
  311. });
  312. return {
  313. ...item,
  314. ehsdJson: ehsdJson,
  315. };
  316. }
  317. );
  318. }
  319. } else if (flowForm.flowKey == "contract_flow") {
  320. if (flowForm.tenantType === "EHSD") {
  321. if (data.fileList && data.fileList.length > 0) {
  322. data.fileList = data.fileList.map((item) => {
  323. return {
  324. id: item.raw.id,
  325. fileName: item.raw.fileName,
  326. fileUrl: item.raw.fileUrl,
  327. };
  328. });
  329. } else {
  330. data.fileList = [];
  331. }
  332. if (data.packageFileList && data.packageFileList.length > 0) {
  333. data.packageFileList = data.packageFileList.map((item) => {
  334. return {
  335. id: item.raw.id,
  336. fileName: item.raw.fileName,
  337. fileUrl: item.raw.fileUrl,
  338. };
  339. });
  340. } else {
  341. data.packageFileList = [];
  342. }
  343. data.ehsdJson = JSON.stringify({
  344. deliveryTime: data.deliveryTime,
  345. });
  346. data.contractProductList = data.contractProductList.map(
  347. (item) => {
  348. let ehsdJson = JSON.stringify({
  349. packMethod: item.packMethod,
  350. tradeMethods: item.tradeMethods,
  351. });
  352. return {
  353. ...item,
  354. ehsdJson: ehsdJson,
  355. };
  356. }
  357. );
  358. }
  359. } else if (flowForm.flowKey == "sample_flow") {
  360. if (data.fileList && data.fileList.length > 0) {
  361. data.fileList = data.fileList.map((item) => {
  362. return {
  363. id: item.raw.id,
  364. fileName: item.raw.fileName,
  365. fileUrl: item.raw.fileUrl,
  366. };
  367. });
  368. } else {
  369. data.fileList = [];
  370. }
  371. if (data.packageFileList && data.packageFileList.length > 0) {
  372. data.packageFileList = data.packageFileList.map((item) => {
  373. return {
  374. id: item.raw.id,
  375. fileName: item.raw.fileName,
  376. fileUrl: item.raw.fileUrl,
  377. };
  378. });
  379. } else {
  380. data.packageFileList = [];
  381. }
  382. data.ehsdJson = JSON.stringify({
  383. deliveryTime: data.deliveryTime,
  384. });
  385. data.sampleProductList = data.sampleProductList.map((item) => {
  386. let ehsdJson = JSON.stringify({
  387. packMethod: item.packMethod,
  388. tradeMethods: item.tradeMethods,
  389. });
  390. return {
  391. ...item,
  392. ehsdJson: ehsdJson,
  393. };
  394. });
  395. }
  396. flowForm.fileList = flowForm.fileList.map((item) => {
  397. return {
  398. ...item,
  399. ...item.raw,
  400. };
  401. });
  402. if (route.query.processType == 10 || route.query.processType == 30) {
  403. // if (_type && _type == 1) {
  404. // proxy
  405. // .post("/flowExample/setStartData", {
  406. // exampleId: route.query.id,
  407. // startData: data,
  408. // })
  409. // .then();
  410. // }
  411. proxy
  412. .post("/flowProcess/jump", {
  413. ...flowForm,
  414. data,
  415. handleType: _type,
  416. version: route.query.version,
  417. flowId: route.query.id,
  418. })
  419. .then(
  420. (res) => {
  421. handleResult(res);
  422. },
  423. (err) => {
  424. btnLoading.value = false;
  425. }
  426. );
  427. return;
  428. } else {
  429. proxy
  430. .post("/flowProcess/initiate", {
  431. ...flowForm,
  432. data,
  433. })
  434. .then(
  435. (res) => {
  436. handleResult(res);
  437. },
  438. (err) => {
  439. btnLoading.value = false;
  440. }
  441. );
  442. }
  443. }
  444. });
  445. }
  446. } catch (err) {
  447. console.log("数据未填完整!", err);
  448. }
  449. };
  450. // 页面跳转
  451. const skipPage = () => {
  452. const useTagsStore = useTagsViewStore();
  453. useTagsStore.delVisitedView(router.currentRoute.value);
  454. if (route.query.processType) {
  455. router.replace({
  456. path: "/oa/1/dealWith",
  457. });
  458. } else {
  459. ElMessage({
  460. message: "操作成功!",
  461. type: "success",
  462. });
  463. if (flowForm.flowKey == "subscribe_flow") {
  464. router.replace({
  465. path: "/ehsd/procurement/subscribe",
  466. });
  467. } else if (flowForm.flowKey == "account_request_funds_flow") {
  468. router.replace({
  469. path: "/ehsd/fundManage/funds",
  470. });
  471. } else if (flowForm.flowKey == "pay_flow") {
  472. router.replace({
  473. path: "/ehsd/purchasePayment/payment",
  474. });
  475. } else if (flowForm.flowKey == "sale_quotation_flow") {
  476. if (flowForm.tenantType === "EHSD") {
  477. router.replace({
  478. path: "/ehsd/saleContract/quotation",
  479. });
  480. }
  481. } else if (
  482. flowForm.flowKey == "contract_flow" ||
  483. flowForm.flowKey == "contract_update_flow"
  484. ) {
  485. router.replace({
  486. path: "/ehsd/saleContract/contract",
  487. });
  488. } else if (flowForm.flowKey == "sample_flow") {
  489. router.replace({
  490. path: "/ehsd/saleContract/sample",
  491. });
  492. } else if (flowForm.flowKey == "ehsd_purchase_flow") {
  493. router.replace({
  494. path: "/ehsd/procurement/purchased",
  495. });
  496. }
  497. }
  498. };
  499. let queryData = reactive({
  500. data: {},
  501. });
  502. // 记录
  503. const recordList = ref([]);
  504. const fileIds = ref([]);
  505. const fileObj = ref({});
  506. const approvalRecordData = ref({
  507. buttonInfoList: [],
  508. });
  509. const getRecords = (_id) => {
  510. if (_id) {
  511. proxy
  512. .post("/flowExample/getApprovalRecord", {
  513. id: _id,
  514. })
  515. .then((res) => {
  516. recordList.value = res.recordList;
  517. queryData.data.recordList = res.recordList;
  518. approvalRecordData.value = res;
  519. fileIds.value = res.recordList.map((item) => {
  520. return item.flowExampleDetailId;
  521. });
  522. proxy
  523. .post("fileInfo/getList", { businessIdList: fileIds.value })
  524. .then((res2) => {
  525. console.log(res2);
  526. fileObj.value = res2;
  527. });
  528. console.log(fileObj.value);
  529. });
  530. } else {
  531. proxy
  532. .post("/flowExample/getFlowNode", {
  533. flowKey: flowForm.flowKey,
  534. })
  535. .then((res) => {
  536. recordList.value = res;
  537. });
  538. }
  539. };
  540. onMounted(async () => {
  541. //processType 10 为修改 20为查看 30回退发起
  542. if (
  543. route.query.processType == 10 ||
  544. route.query.processType == 20 ||
  545. route.query.processType == 30
  546. ) {
  547. // await proxy
  548. // .post("/flowProcess/getStartData", { flowId: route.query.id })
  549. // .then((res) => {
  550. // queryData.data = { ...res };
  551. // });
  552. } else {
  553. queryData.data = { ...route.query };
  554. }
  555. flowForm.flowKey = route.query.flowKey;
  556. flowForm.tenantType = route.query.tenantType;
  557. flowForm.submitType = route.query.submitType;
  558. getRecords(route.query.id);
  559. });
  560. </script>
  561. <style>
  562. .el-upload-list {
  563. float: left;
  564. margin: 0 !important;
  565. }
  566. .el-upload-list li {
  567. width: 200px;
  568. margin-left: 10px;
  569. }
  570. .el-upload--text {
  571. float: left;
  572. }
  573. </style>
  574. <style lang="scss" scoped>
  575. .processApproval {
  576. display: flex;
  577. justify-content: space-between;
  578. margin-top: 20px;
  579. padding: 0 20px;
  580. height: calc(100vh - 130px);
  581. .left-card {
  582. // background: #fff;
  583. border-radius: 4px;
  584. // padding: 20px;
  585. // flex: 1;
  586. width: calc(100% - 400px - 20px);
  587. margin-right: 20px;
  588. display: flex;
  589. flex-direction: column;
  590. .top {
  591. flex: 1;
  592. overflow-y: auto;
  593. background: #fff;
  594. padding: 20px 20px 0px 20px;
  595. .line {
  596. border-bottom: 1px solid #ddd;
  597. margin-bottom: 20px;
  598. }
  599. }
  600. .bottom {
  601. margin-top: 10px;
  602. height: 220px;
  603. background: #fff;
  604. padding: 20px 20px 0px 20px;
  605. }
  606. }
  607. .right-card {
  608. background: #fff;
  609. border-radius: 4px;
  610. padding: 0 20px 20px;
  611. width: 400px;
  612. box-sizing: border-box;
  613. .flow-chart {
  614. overflow: auto;
  615. height: calc(100vh - 200px);
  616. padding: 0;
  617. margin: 0;
  618. li {
  619. margin: 0;
  620. padding: 0 0 20px;
  621. list-style: none;
  622. display: flex;
  623. justify-content: space-between;
  624. position: relative;
  625. .right-conetnt {
  626. flex: 1;
  627. .name {
  628. font-size: 12px;
  629. color: #39c55a;
  630. margin-bottom: 10px;
  631. span {
  632. color: #999;
  633. }
  634. }
  635. .time {
  636. float: right;
  637. }
  638. .remark {
  639. padding: 10px;
  640. color: #666666;
  641. font-size: 12px;
  642. background: #f1f1f1;
  643. border-radius: 2px;
  644. .label {
  645. color: #999;
  646. margin-bottom: 10px;
  647. }
  648. }
  649. }
  650. .left-icon {
  651. width: 40px;
  652. height: 40px;
  653. text-align: center;
  654. line-height: 40px;
  655. background: #0084ff;
  656. border-radius: 10px;
  657. color: #fff;
  658. font-size: 20px;
  659. position: relative;
  660. margin-right: 27px;
  661. z-index: 2;
  662. .right-btm-status {
  663. position: absolute;
  664. bottom: 0px;
  665. right: -10px;
  666. height: 20px;
  667. width: 20px;
  668. line-height: 16px;
  669. border-radius: 10px;
  670. background: #39c55a;
  671. border: 2px solid #fff;
  672. font-size: 12px;
  673. box-sizing: border-box;
  674. }
  675. }
  676. }
  677. li::before {
  678. content: "";
  679. position: absolute;
  680. top: 0;
  681. left: 20px;
  682. width: 2px;
  683. height: 100%;
  684. background: #ddd;
  685. z-index: 1;
  686. }
  687. li:last-child::before {
  688. display: none;
  689. }
  690. .flow-orange {
  691. .right-btm-status {
  692. background: #ff9a00 !important;
  693. }
  694. .name {
  695. color: #ff9a00 !important;
  696. }
  697. .left-icon {
  698. background: #ff9a00 !important;
  699. }
  700. }
  701. .flow-grey {
  702. .right-btm-status {
  703. background: #999 !important;
  704. }
  705. .name {
  706. color: #999 !important;
  707. }
  708. .left-icon {
  709. background: #999 !important;
  710. }
  711. }
  712. .flow-red {
  713. .right-btm-status {
  714. background: #ff4d4f !important;
  715. }
  716. .name {
  717. color: #ff4d4f !important;
  718. }
  719. .left-icon {
  720. background: #ff4d4f !important;
  721. }
  722. }
  723. }
  724. }
  725. }
  726. </style>