You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

519 lines
20 KiB

1 month ago
  1. <template>
  2. <div class="customer-css">
  3. <!-- 查询区域 - rqrq -->
  4. <el-form :inline="true" label-position="top" label-width="100px" style="margin-top: 0px;">
  5. <el-row>
  6. <el-col :span="24">
  7. <el-form-item label="单据号:">
  8. <el-input v-model="searchData.applyNo" style="width: 150px"></el-input>
  9. </el-form-item>
  10. <el-form-item label="单据类型:">
  11. <el-select v-model="searchData.orderType" style="width: 130px" clearable>
  12. <el-option label="全部" value=""></el-option>
  13. <el-option label="产品资料" value="产品资料"></el-option>
  14. </el-select>
  15. </el-form-item>
  16. <el-form-item label="流程状态:">
  17. <el-select v-model="searchData.status" style="width: 130px" clearable>
  18. <el-option label="全部" value=""></el-option>
  19. <el-option label="运行中" value="RUNNING"></el-option>
  20. <el-option label="已完成" value="COMPLETED"></el-option>
  21. <el-option label="已终止" value="TERMINATED"></el-option>
  22. </el-select>
  23. </el-form-item>
  24. <el-form-item label=" ">
  25. <el-button class="customer-bun-min" type="primary" @click="getInstanceList">查询</el-button>
  26. <el-button type="primary" @click="openAddDialog">新增测试</el-button>
  27. </el-form-item>
  28. </el-col>
  29. </el-row>
  30. </el-form>
  31. <!-- 上表流程实例列表 -->
  32. <div style="font-weight: bold; margin-bottom: 5px;">流程实例列表</div>
  33. <el-table
  34. :height="height1"
  35. :data="instanceList"
  36. border
  37. ref="instanceTable"
  38. highlight-current-row
  39. @row-click="selectInstance"
  40. v-loading="instanceLoading"
  41. style="width: 100%;">
  42. <el-table-column prop="applyNo" label="单据号" min-width="150" header-align="center" align="center"></el-table-column>
  43. <el-table-column prop="orderType" label="单据类型" min-width="100" header-align="center" align="center"></el-table-column>
  44. <el-table-column prop="flowName" label="流程名称" min-width="150" header-align="center" align="left"></el-table-column>
  45. <el-table-column prop="currentNodeName" label="当前节点" min-width="120" header-align="center" align="center"></el-table-column>
  46. <el-table-column prop="status" label="状态" min-width="80" header-align="center" align="center">
  47. <template slot-scope="scope">
  48. <span :style="{ color: getStatusColor(scope.row.status) }">{{ getStatusText(scope.row.status) }}</span>
  49. </template>
  50. </el-table-column>
  51. <el-table-column prop="startTime" label="开始时间" min-width="150" header-align="center" align="center"></el-table-column>
  52. <el-table-column prop="applicant" label="申请人" min-width="100" header-align="center" align="center"></el-table-column>
  53. <el-table-column fixed="right" header-align="center" align="center" width="100" label="操作">
  54. <template slot-scope="scope">
  55. <a type="text" v-if="scope.row.status === 'COMPLETED' || scope.row.status === 'TERMINATED'" size="small" @click="handleRestart(scope.row)">重新审批</a>
  56. </template>
  57. </el-table-column>
  58. </el-table>
  59. <el-pagination
  60. style="margin-top: 5px"
  61. @size-change="instanceSizeChange"
  62. @current-change="instancePageChange"
  63. :current-page="instancePageIndex"
  64. :page-sizes="[20, 50, 100, 200]"
  65. :page-size="instancePageSize"
  66. :total="instanceTotal"
  67. layout="total, sizes, prev, pager, next, jumper">
  68. </el-pagination>
  69. <!-- 下表节点实例列表 -->
  70. <div style="font-weight: bold; margin: 10px 0 5px 0;">节点审批记录</div>
  71. <el-table
  72. :height="height2"
  73. :data="nodeInstanceList"
  74. border
  75. ref="nodeTable"
  76. highlight-current-row
  77. v-loading="nodeLoading"
  78. style="width: 100%;">
  79. <el-table-column prop="nodeOrder" label="序号" width="60" header-align="center" align="center"></el-table-column>
  80. <el-table-column prop="nodeName" label="节点名称" min-width="100" header-align="center" align="center"></el-table-column>
  81. <el-table-column prop="departmentName" label="审批部门" min-width="100" header-align="center" align="center">
  82. <template slot-scope="scope">{{ scope.row.departmentName || '-' }}</template>
  83. </el-table-column>
  84. <el-table-column prop="assigneeName" label="审批人" min-width="80" header-align="center" align="center"></el-table-column>
  85. <el-table-column prop="attemptNo" label="次数" width="60" header-align="center" align="center"></el-table-column>
  86. <el-table-column prop="approveType" label="审批类型" min-width="100" header-align="center" align="center">
  87. <template slot-scope="scope">
  88. <span v-if="scope.row.approveType === 'SINGLE'">单人审批</span>
  89. <span v-else-if="scope.row.approveType === 'ALL'">会签</span>
  90. <span v-else-if="scope.row.approveType === 'ANY'">或签</span>
  91. <span v-else>{{ scope.row.approveType }}</span>
  92. </template>
  93. </el-table-column>
  94. <el-table-column prop="status" label="状态" min-width="80" header-align="center" align="center">
  95. <template slot-scope="scope">
  96. <span :style="{ color: getNodeStatusColor(scope.row.status) }">{{ getNodeStatusText(scope.row.status) }}</span>
  97. </template>
  98. </el-table-column>
  99. <el-table-column prop="comment" label="审批意见" min-width="150" header-align="center" align="left" show-overflow-tooltip></el-table-column>
  100. <el-table-column prop="completeTime" label="完成时间" min-width="150" header-align="center" align="center">
  101. <template slot-scope="scope">{{ scope.row.completeTime || '-' }}</template>
  102. </el-table-column>
  103. <el-table-column fixed="right" header-align="center" align="center" width="100" label="操作">
  104. <template slot-scope="scope">
  105. <a type="text" size="small" @click="openApproveDialog(scope.row)">审批</a>
  106. <!-- <el-button v-if="scope.row.status === 'PENDING'" size="mini" type="text" @click="openApproveDialog(scope.row)">审批</el-button>-->
  107. </template>
  108. </el-table-column>
  109. </el-table>
  110. <!-- 新增测试对话框 - rqrq -->
  111. <el-dialog
  112. title="新增审批流程(测试)"
  113. :visible.sync="addDialogVisible"
  114. width="500px"
  115. :close-on-click-modal="false"
  116. v-drag>
  117. <el-form :model="addFormData" :rules="addFormRules" ref="addFormRef" label-position="top">
  118. <el-form-item label="工厂编码" prop="site">
  119. <el-input v-model="addFormData.site" placeholder="请输入工厂编码"></el-input>
  120. </el-form-item>
  121. <el-form-item label="单据号" prop="applyNo">
  122. <el-input v-model="addFormData.applyNo" placeholder="请输入单据号"></el-input>
  123. </el-form-item>
  124. <el-form-item label="单据类型" prop="orderType">
  125. <el-select v-model="addFormData.orderType" style="width: 100%" placeholder="请选择单据类型">
  126. <el-option label="产品资料" value="产品资料"></el-option>
  127. </el-select>
  128. </el-form-item>
  129. <el-form-item label="流程编码" prop="flowCode">
  130. <el-input v-model="addFormData.flowCode" placeholder="请输入流程编码"></el-input>
  131. </el-form-item>
  132. </el-form>
  133. <span slot="footer" class="dialog-footer">
  134. <el-button type="primary" @click="submitAddForm" :loading="addLoading">{{ addLoading ? '创建中...' : '创建' }}</el-button>
  135. <el-button @click="addDialogVisible = false" :disabled="addLoading">取消</el-button>
  136. </span>
  137. </el-dialog>
  138. <!-- 审批对话框 - rqrq -->
  139. <el-dialog
  140. title="审批"
  141. :visible.sync="approveDialogVisible"
  142. width="550px"
  143. :close-on-click-modal="false"
  144. v-drag>
  145. <el-form :model="approveData" label-position="top">
  146. <el-row :gutter="20">
  147. <el-col :span="12">
  148. <el-form-item label="单据号">
  149. <el-input v-model="approveData.applyNo" disabled></el-input>
  150. </el-form-item>
  151. </el-col>
  152. <el-col :span="12">
  153. <el-form-item label="当前节点">
  154. <el-input v-model="approveData.nodeName" disabled></el-input>
  155. </el-form-item>
  156. </el-col>
  157. </el-row>
  158. <el-row :gutter="20">
  159. <el-col :span="12">
  160. <el-form-item label="审批部门">
  161. <el-input v-model="approveData.departmentName" disabled></el-input>
  162. </el-form-item>
  163. </el-col>
  164. <el-col :span="12">
  165. <el-form-item label="审批人">
  166. <el-input v-model="approveData.assigneeName" disabled></el-input>
  167. </el-form-item>
  168. </el-col>
  169. </el-row>
  170. <el-form-item label="审批意见">
  171. <el-input type="textarea" v-model="approveData.comment" :rows="3" placeholder="请输入审批意见"></el-input>
  172. </el-form-item>
  173. </el-form>
  174. <el-footer style="height:40px;margin-top: 60px;text-align:center">
  175. <el-button type="success" @click="submitApprove('APPROVED')" :loading="approveLoading">同意</el-button>
  176. <el-button type="danger" @click="submitApprove('REJECTED')" :loading="approveLoading">驳回</el-button>
  177. <el-button type="info" @click="openFlowPreview">流程预览</el-button>
  178. <el-button @click="approveDialogVisible = false" :disabled="approveLoading">取消</el-button>
  179. </el-footer>
  180. </el-dialog>
  181. <!-- 流程预览对话框 - rqrq -->
  182. <el-dialog
  183. title="流程预览"
  184. :visible.sync="previewDialogVisible"
  185. width="700px"
  186. :close-on-click-modal="false"
  187. append-to-body
  188. v-drag>
  189. <div style="margin-bottom: 15px;">
  190. <span style="font-weight: bold;">流程名称</span>{{ previewData.flowName }}
  191. <span style="margin-left: 20px; font-weight: bold;">流程编码</span>{{ previewData.flowCode }}
  192. <span style="margin-left: 20px; font-weight: bold;">版本</span>{{ previewData.flowVersion }}
  193. </div>
  194. <el-table :data="previewData.nodeList" border style="width: 100%;">
  195. <el-table-column prop="nodeOrder" label="顺序" width="60" header-align="center" align="center">
  196. <template slot-scope="scope">{{ scope.$index + 1 }}</template>
  197. </el-table-column>
  198. <el-table-column prop="nodeCode" label="节点编码" min-width="100" header-align="center" align="center"></el-table-column>
  199. <el-table-column prop="nodeName" label="节点名称" min-width="120" header-align="center" align="center"></el-table-column>
  200. <el-table-column prop="nodeType" label="节点类型" min-width="80" header-align="center" align="center">
  201. <template slot-scope="scope">
  202. <span v-if="scope.row.nodeType === 'START'" style="color: #67C23A">开始</span>
  203. <span v-else-if="scope.row.nodeType === 'END'" style="color: #F56C6C">结束</span>
  204. <span v-else style="color: #409EFF">审批</span>
  205. </template>
  206. </el-table-column>
  207. <el-table-column prop="approveType" label="审批类型" min-width="100" header-align="center" align="center">
  208. <template slot-scope="scope">
  209. <span v-if="scope.row.approveType === 'SINGLE'">单人审批</span>
  210. <span v-else-if="scope.row.approveType === 'ALL'">会签</span>
  211. <span v-else-if="scope.row.approveType === 'ANY'">或签</span>
  212. <span v-else>-</span>
  213. </template>
  214. </el-table-column>
  215. <el-table-column prop="departmentName" label="审批部门" min-width="120" header-align="center" align="center">
  216. <template slot-scope="scope">{{ scope.row.departmentName || '-' }}</template>
  217. </el-table-column>
  218. <el-table-column prop="approverNames" label="审批人" min-width="150" header-align="center" align="left">
  219. <template slot-scope="scope">{{ scope.row.approverNames || '-' }}</template>
  220. </el-table-column>
  221. </el-table>
  222. <span slot="footer" class="dialog-footer">
  223. <el-button type="primary" @click="previewDialogVisible = false">关闭</el-button>
  224. </span>
  225. </el-dialog>
  226. </div>
  227. </template>
  228. <script>
  229. import {
  230. searchInstanceList,
  231. searchNodeInstanceList,
  232. createFlowInstance,
  233. approveNodeInstance,
  234. getFlowPreview,
  235. restartFlowInstance
  236. } from '@/api/workFlow/workFlow.js'
  237. export default {
  238. data() {
  239. return {
  240. height1: 200,
  241. height2: 200,
  242. // 流程实例
  243. instanceLoading: false,
  244. instanceList: [],
  245. instancePageIndex: 1,
  246. instancePageSize: 20,
  247. instanceTotal: 0,
  248. currentInstance: null,
  249. searchData: {
  250. site: this.$store.state.user.site,
  251. applyNo: '',
  252. orderType: '',
  253. status: ''
  254. },
  255. // 节点实例
  256. nodeLoading: false,
  257. nodeInstanceList: [],
  258. // 当前登录用户
  259. currentUser: this.$store.state.user.username,
  260. // 新增对话框
  261. addDialogVisible: false,
  262. addLoading: false,
  263. addFormData: {
  264. site: this.$store.state.user.site,
  265. applyNo: '',
  266. orderType: '产品资料',
  267. flowCode: ''
  268. },
  269. addFormRules: {
  270. site: [{ required: true, message: '请输入工厂编码', trigger: 'blur' }],
  271. applyNo: [{ required: true, message: '请输入单据号', trigger: 'blur' }],
  272. orderType: [{ required: true, message: '请选择单据类型', trigger: 'change' }],
  273. flowCode: [{ required: true, message: '请输入流程编码', trigger: 'blur' }]
  274. },
  275. // 审批对话框
  276. approveDialogVisible: false,
  277. approveLoading: false,
  278. approveData: {
  279. applyNo: '',
  280. nodeCode: '',
  281. nodeName: '',
  282. departmentName: '', // 审批部门 - rqrq
  283. assigneeName: '',
  284. site: '',
  285. orderType: '',
  286. comment: '',
  287. flowCode: '',
  288. flowVersion: null
  289. },
  290. // 流程预览
  291. previewDialogVisible: false,
  292. previewData: {
  293. flowCode: '',
  294. flowName: '',
  295. flowVersion: '',
  296. nodeList: []
  297. }
  298. }
  299. },
  300. mounted() {
  301. this.$nextTick(() => {
  302. this.height1 = (window.innerHeight - 250) / 2
  303. this.height2 = (window.innerHeight - 250) / 2
  304. })
  305. this.getInstanceList()
  306. },
  307. methods: {
  308. // 获取流程实例列表
  309. getInstanceList() {
  310. this.instanceLoading = true
  311. const params = {
  312. ...this.searchData,
  313. limit: this.instancePageSize,
  314. page: this.instancePageIndex
  315. }
  316. searchInstanceList(params).then(({ data }) => {
  317. if (data && data.code === 0) {
  318. this.instanceList = data.page.list
  319. this.instanceTotal = data.page.totalCount
  320. }
  321. this.instanceLoading = false
  322. })
  323. },
  324. instanceSizeChange(val) {
  325. this.instancePageSize = val
  326. this.instancePageIndex = 1
  327. this.getInstanceList()
  328. },
  329. instancePageChange(val) {
  330. this.instancePageIndex = val
  331. this.getInstanceList()
  332. },
  333. // 选中流程实例
  334. selectInstance(row) {
  335. this.currentInstance = row
  336. this.getNodeInstanceList()
  337. },
  338. // 获取节点实例列表
  339. getNodeInstanceList() {
  340. if (!this.currentInstance) {
  341. this.nodeInstanceList = []
  342. return
  343. }
  344. this.nodeLoading = true
  345. searchNodeInstanceList({
  346. applyNo: this.currentInstance.applyNo,
  347. site: this.currentInstance.site,
  348. orderType: this.currentInstance.orderType
  349. }).then(({ data }) => {
  350. if (data && data.code === 0) {
  351. this.nodeInstanceList = data.rows
  352. }
  353. this.nodeLoading = false
  354. })
  355. },
  356. // 状态颜色
  357. getStatusColor(status) {
  358. switch (status) {
  359. case 'RUNNING': return '#409EFF'
  360. case 'COMPLETED': return '#67C23A'
  361. case 'TERMINATED': return '#F56C6C'
  362. default: return '#909399'
  363. }
  364. },
  365. getStatusText(status) {
  366. switch (status) {
  367. case 'RUNNING': return '运行中'
  368. case 'COMPLETED': return '已完成'
  369. case 'TERMINATED': return '已终止'
  370. default: return status
  371. }
  372. },
  373. getNodeStatusColor(status) {
  374. switch (status) {
  375. case 'PENDING': return '#E6A23C'
  376. case 'APPROVED': return '#67C23A'
  377. case 'REJECTED': return '#F56C6C'
  378. case 'SKIPPED': return '#909399'
  379. default: return '#909399'
  380. }
  381. },
  382. getNodeStatusText(status) {
  383. switch (status) {
  384. case 'PENDING': return '待审批'
  385. case 'APPROVED': return '已通过'
  386. case 'REJECTED': return '已驳回'
  387. case 'SKIPPED': return '已跳过'
  388. default: return status
  389. }
  390. },
  391. // 打开新增对话框
  392. openAddDialog() {
  393. this.addFormData = {
  394. site: this.$store.state.user.site,
  395. applyNo: '',
  396. orderType: '产品资料',
  397. flowCode: ''
  398. }
  399. this.addDialogVisible = true
  400. },
  401. // 提交新增
  402. submitAddForm() {
  403. this.$refs.addFormRef.validate((valid) => {
  404. if (valid) {
  405. this.addLoading = true
  406. createFlowInstance(this.addFormData).then(({ data }) => {
  407. if (data && data.code === 0) {
  408. this.$message.success('流程实例创建成功')
  409. this.addDialogVisible = false
  410. this.getInstanceList()
  411. } else {
  412. this.$message.error(data.msg || '创建失败')
  413. }
  414. }).finally(() => {
  415. this.addLoading = false
  416. })
  417. }
  418. })
  419. },
  420. // 打开审批对话框
  421. openApproveDialog(row) {
  422. this.approveData = {
  423. applyNo: this.currentInstance.applyNo,
  424. nodeCode: row.nodeCode,
  425. nodeName: row.nodeName,
  426. departmentName: row.departmentName || '', // 审批部门 - rqrq
  427. assigneeName: row.assigneeName,
  428. site: this.currentInstance.site,
  429. orderType: this.currentInstance.orderType,
  430. comment: '',
  431. flowCode: this.currentInstance.flowCode,
  432. flowVersion: this.currentInstance.flowVersion
  433. }
  434. this.approveDialogVisible = true
  435. },
  436. // 提交审批
  437. submitApprove(action) {
  438. if (action === 'REJECTED' && !this.approveData.comment) {
  439. this.$message.warning('驳回时必须填写审批意见')
  440. return
  441. }
  442. this.approveLoading = true
  443. approveNodeInstance({
  444. applyNo: this.approveData.applyNo,
  445. nodeCode: this.approveData.nodeCode,
  446. site: this.approveData.site,
  447. orderType: this.approveData.orderType,
  448. action: action,
  449. comment: this.approveData.comment
  450. }).then(({ data }) => {
  451. if (data && data.code === 0) {
  452. this.$message.success(action === 'APPROVED' ? '审批通过成功' : '驳回成功')
  453. this.approveDialogVisible = false
  454. this.getInstanceList()
  455. this.getNodeInstanceList()
  456. } else {
  457. this.$message.error(data.msg || '操作失败')
  458. }
  459. }).finally(() => {
  460. this.approveLoading = false
  461. })
  462. },
  463. // 流程预览
  464. openFlowPreview() {
  465. getFlowPreview({
  466. flowCode: this.approveData.flowCode,
  467. flowVersion: this.approveData.flowVersion,
  468. site: this.approveData.site
  469. }).then(({ data }) => {
  470. if (data && data.code === 0) {
  471. this.previewData = data.row
  472. this.previewDialogVisible = true
  473. } else {
  474. this.$message.error(data.msg || '获取流程信息失败')
  475. }
  476. })
  477. },
  478. // 重新审批 - rqrq
  479. handleRestart(row) {
  480. this.$confirm('确定要重新发起审批流程吗?', '提示', {
  481. confirmButtonText: '确定',
  482. cancelButtonText: '取消',
  483. type: 'warning'
  484. }).then(() => {
  485. restartFlowInstance({
  486. applyNo: row.applyNo,
  487. site: row.site,
  488. orderType: row.orderType
  489. }).then(({ data }) => {
  490. if (data && data.code === 0) {
  491. this.$message.success('重新审批成功')
  492. this.getInstanceList()
  493. this.nodeInstanceList = []
  494. this.currentInstance = null
  495. } else {
  496. this.$message.error(data.msg || '操作失败')
  497. }
  498. })
  499. }).catch(() => {})
  500. }
  501. }
  502. }
  503. </script>
  504. <style scoped>
  505. /deep/ .el-dialog__body {
  506. padding: 10px 20px;
  507. }
  508. </style>