approveTasks.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <template>
  2. <div>
  3. <el-dialog :title="dialog.title" v-model="dialog.isShowDialog" width="90%">
  4. <el-collapse v-model="activeNames">
  5. <el-collapse-item name="2" disabled>
  6. <template #title>
  7. <el-icon class="header-icon"><info-filled /></el-icon>
  8. <span>审批意见</span>
  9. </template>
  10. <el-form ref="formRef" :rules="rules" :model="state.form" label-position="top" label-width="150px" style="padding: 10px 0">
  11. <el-form-item label="审批意见" prop="approveOpinion">
  12. <el-input
  13. v-model="state.form.approveOpinion"
  14. type="textarea"
  15. :rows="3"
  16. resize="none"
  17. placeholder="请输入审批意见"
  18. clearable
  19. style="width: 100%"
  20. ></el-input>
  21. </el-form-item>
  22. <el-form-item label="审批结果" prop="approveResult">
  23. <el-radio-group v-model="state.form.approveResult">
  24. <el-radio label="pass">通过</el-radio>
  25. <el-radio label="rejection">拒绝</el-radio>
  26. </el-radio-group>
  27. </el-form-item>
  28. <el-form-item v-show="state.taskDetail.isFile && state.form.approveResult === 'pass'" label="附件" prop="fileList">
  29. <el-upload
  30. :accept="state.SUPPORT_FILE_UPLOAD_TYPE_MAX"
  31. ref="upload"
  32. :file-list="state.form.fileList"
  33. :action="uploadUrl"
  34. :headers="getUploadHeaders()"
  35. :before-upload="beforeAvatarFileUpload"
  36. :on-success="handleSuccess"
  37. :limit="1"
  38. :on-exceed="handleExceed"
  39. style="width: 100%"
  40. >
  41. <template #trigger>
  42. <el-button type="primary" size="default">点击上传</el-button>
  43. </template>
  44. </el-upload>
  45. </el-form-item>
  46. </el-form>
  47. </el-collapse-item>
  48. </el-collapse>
  49. <template #footer>
  50. <el-button @click="dialog.isShowDialog = false">取 消</el-button>
  51. <el-button type="primary" @click="onSave">提 交</el-button>
  52. </template>
  53. </el-dialog>
  54. </div>
  55. </template>
  56. <script setup lang="ts" name="approvalForm">
  57. import to from 'await-to-js'
  58. import { nextTick, reactive, ref } from 'vue'
  59. import { ElMessage } from 'element-plus'
  60. import { useExecutionApi } from '/@/api/platform/execution'
  61. import { useDictApi } from '/@/api/system/dict'
  62. import type { UploadFile, UploadUserFile, UploadProps, UploadRawFile } from 'element-plus'
  63. import { genFileId } from 'element-plus'
  64. import { Session } from '/@/utils/storage'
  65. import { getUploadHeaders } from '/@/utils/upload'
  66. import { getFileUrl } from '/@/utils/url'
  67. import { SUPPORT_FILE_UPLOAD_TYPE_MAX } from '/@/constants/pageConstants'
  68. // 定义变量内容
  69. const uploadUrl = import.meta.env.VITE_UPLOAD
  70. const upload = ref()
  71. const dictApi = useDictApi()
  72. const executionApi = useExecutionApi()
  73. const riskLevelOption = ref<RowDicDataType[]>([])
  74. const activeNames = ref(['1', '2', '3'])
  75. const formRef = ref()
  76. const dialog = reactive({
  77. type: '',
  78. isShowDialog: false,
  79. title: '',
  80. submitTxt: ''
  81. })
  82. const idList = ref<number[]>([])
  83. const state = reactive<any>({
  84. SUPPORT_FILE_UPLOAD_TYPE_MAX,
  85. taskDetail: {},
  86. detail: {},
  87. form: {
  88. taskId: 0,
  89. approveResult: 'pass',
  90. approveOpinion: '',
  91. fileList: [] as UploadUserFile[],
  92. fileUrl: ''
  93. },
  94. tableData: {
  95. data: [],
  96. loading: false,
  97. param: {
  98. id: 0
  99. }
  100. }
  101. })
  102. const checkFileUrl = (rule: any, value: any, callback: any) => {
  103. if (state.form.isFile && state.form.approveResult === 'pass') {
  104. if (!state.form.fileUrl) {
  105. callback(new Error('请上传附件'))
  106. }
  107. } else {
  108. callback()
  109. }
  110. }
  111. const rules = {
  112. approveResult: [{ required: true, message: '请选择审批结果', trigger: 'blur' }],
  113. approveOpinion: [{ required: true, message: '请输入审批意见', trigger: 'blur' }],
  114. fileList: [{ validator: checkFileUrl }]
  115. }
  116. const beforeAvatarFileUpload = (file: any) => {
  117. let isLt10m = file.size / 1024 / 1024 / 20 < 1
  118. if (!isLt10m) {
  119. ElMessage.error('上传文件大小不能超过 20MB!')
  120. return false
  121. }
  122. return true
  123. }
  124. const handleExceed: UploadProps['onExceed'] = (files) => {
  125. upload.value!.clearFiles()
  126. const file = files[0] as UploadRawFile
  127. file.uid = genFileId()
  128. upload.value!.handleStart(file)
  129. }
  130. const handleSuccess = (res: any, uploadFile: UploadFile) => {
  131. state.form.fileUrl = res.Data
  132. state.form.fileList = [
  133. {
  134. name: uploadFile?.name,
  135. url: getFileUrl(res.Data),
  136. uid: uploadFile?.uid
  137. }
  138. ]
  139. }
  140. // 初始化表格数据
  141. const getTableData = async (id: number) => {
  142. state.tableData.loading = true
  143. state.tableData.param.id = id
  144. const [err, res]: ToResponse = await to(executionApi.getParticipantByProcInstID({ id }))
  145. if (err) return
  146. const arr = res?.data || []
  147. state.tableData.data = arr
  148. setTimeout(() => {
  149. state.tableData.loading = false
  150. }, 500)
  151. }
  152. // 刷新上级列表
  153. const emit = defineEmits(['getParentTableDate'])
  154. // 保存
  155. const onSave = async () => {
  156. formRef.value.validate(async (valid: any) => {
  157. if (valid) {
  158. let params = {
  159. paramIds: idList.value,
  160. result: state.form.approveResult,
  161. opinion: state.form.approveOpinion
  162. }
  163. const [err]: ToResponse = await to(executionApi.batchApprove(params))
  164. if (err) return
  165. ElMessage({ type: 'success', message: '提交成功' })
  166. dialog.isShowDialog = false
  167. emit('getParentTableDate')
  168. }
  169. })
  170. }
  171. const getDicts = () => {
  172. Promise.all([dictApi.getDictDataByType('RiskLevel')]).then(([riskLevel]) => {
  173. riskLevelOption.value = riskLevel.data.values
  174. })
  175. }
  176. // 打开弹窗
  177. const openDialog = (ids: number[]) => {
  178. getDicts()
  179. idList.value = ids
  180. activeNames.value = ['1', '2', '3']
  181. dialog.isShowDialog = true
  182. nextTick(() => {
  183. formRef.value.resetFields()
  184. })
  185. }
  186. // 暴露变量
  187. defineExpose({
  188. openDialog
  189. })
  190. </script>
  191. <style scoped lang="scss">
  192. .system-user-container {
  193. :deep(.el-card__body) {
  194. display: flex;
  195. flex-direction: column;
  196. flex: 1;
  197. overflow: auto;
  198. .vxe-table {
  199. flex: 1;
  200. }
  201. }
  202. }
  203. .card-header {
  204. display: flex;
  205. justify-content: space-between;
  206. align-items: center;
  207. span {
  208. font-size: 18px;
  209. font-weight: bold;
  210. color: #2c405e;
  211. }
  212. }
  213. :deep(.el-descriptions__label) {
  214. width: 10%;
  215. }
  216. :deep(.el-descriptions__content) {
  217. width: 23%;
  218. }
  219. </style>