flowForm.vue 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <template>
  2. <div class="flow_form_box">
  3. <div class="flow_container">
  4. <template v-if="isShowTab">
  5. <van-tabs v-model:active="currentActive" :sticky="true">
  6. <van-tab title="基础信息">
  7. <slot></slot>
  8. </van-tab>
  9. <van-tab title="审批意见">
  10. <div class="flowOpinionBox">
  11. <template v-if="templateOpinion.length > 0">
  12. <div v-for="(item,index) in templateOpinion" :key="index" :class="{'flowOpinionItem': true, 'disabled': !item['isEditor']}">
  13. <h4>{{ item['opinionName'] }}</h4>
  14. <div class="content">
  15. <template v-if="item['isEditor']">
  16. <van-field
  17. v-model="currentOpinion.opinionContent"
  18. rows="3"
  19. autosize
  20. label=""
  21. type="textarea"
  22. maxlength="50"
  23. placeholder="请输入留言"
  24. />
  25. </template>
  26. <template v-else>
  27. <van-field
  28. v-model="item.opinionContent"
  29. rows="3"
  30. autosize
  31. label=""
  32. type="textarea"
  33. :disabled="true"
  34. maxlength="50"
  35. placeholder="请输入留言"
  36. />
  37. </template>
  38. </div>
  39. <div class="footer">
  40. <p>
  41. <span>办理人:</span>
  42. <span v-if="item['isEditor']">
  43. <template v-if="currentOpinion['sign'] && currentOpinion['sign'].indexOf('http') !== -1">
  44. <img class="signImg" :src="currentOpinion['sign']" />
  45. </template>
  46. <template v-else>
  47. {{ currentOpinion['sign'] ?? currentUserName }}
  48. </template>
  49. </span>
  50. <span v-else>
  51. <template v-if="item['sign'] && item['sign'].indexOf('http') !== -1">
  52. <img class="signImg" :src="item['sign']" />
  53. </template>
  54. <template v-else>
  55. {{ item['sign'] ?? userMap[item['userId'] ]}}
  56. </template>
  57. </span>
  58. </p>
  59. <p>
  60. <span>办理时间:</span>
  61. <span>{{ item['isEditor'] ? currentOpinion['opinionTime'] : item['opinionTime']}}</span>
  62. </p>
  63. </div>
  64. </div>
  65. </template>
  66. </div>
  67. </van-tab>
  68. </van-tabs>
  69. </template>
  70. <template v-else>
  71. <slot></slot>
  72. </template>
  73. </div>
  74. <div class="fixed-btn" v-if="isSubmitVisabled">
  75. <van-button :disabled="isSubmitDisabled" round block type="primary" @click="submitHandle">
  76. 转件
  77. </van-button>
  78. </div>
  79. </div>
  80. </template>
  81. <script setup lang="ts">
  82. import { showNotify } from 'vant';
  83. import { closePage } from 'dingtalk-jsapi';
  84. import { getSimpleUserMap } from '@/service/user'
  85. import PubsubService from "@/utils/PubsubService";
  86. import { formatDate, jsonToFormData } from "@/utils/common";
  87. import { FlowDTO, getNextActivity } from "@/service/flow";
  88. import { getTemplateOpinionListByFlowInstanceId, getOpinionListByFlowInstanceId } from '@/service/flow';
  89. defineOptions({
  90. name: 'FlowForm'
  91. })
  92. const isSubmitVisabled = ref<boolean>(true)
  93. const isSubmitDisabled = ref<boolean>(false)
  94. const userInfo = JSON.parse(localStorage.getItem('_userInfo') as string);
  95. const signatureUrl: string = userInfo ? userInfo['signatureUrl'] ?? '' : ''
  96. const currentUserName: string = userInfo ? userInfo['nickname'] ?? '' : ''
  97. const userMap = ref<any>({})
  98. async function initSimpleUserMap() {
  99. userMap.value = await getSimpleUserMap()
  100. }
  101. initSimpleUserMap()
  102. defineProps<{
  103. data: any
  104. }>();
  105. const emit = defineEmits<{
  106. (e: 'submit', payload?: any):void
  107. }>()
  108. const route = useRoute();
  109. const currentActive = ref<string>('基础信息')
  110. const { flowInstanceId, activityInstanceId, participant, _o, _top } = route.query as {
  111. flowInstanceId: string
  112. activityInstanceId: string
  113. participant: string
  114. _o: string
  115. _top: string
  116. }
  117. if (_o && _o == 'v') {
  118. isSubmitVisabled.value = false
  119. }
  120. const currentOpinion = ref({
  121. id: '',
  122. opinionContent: '',
  123. opinionTime: '',
  124. sign: ''
  125. })
  126. const isShowTab = ref<boolean>(true)
  127. const templateOpinion = ref<any[]>([]) //用来缓存展示节点
  128. const initTemplateOptinionFunc = async () => {
  129. const templateOpinions = [];
  130. const tResult = await getTemplateOpinionListByFlowInstanceId(flowInstanceId);
  131. const tList = tResult.data ?? []
  132. const oResult = await getOpinionListByFlowInstanceId(flowInstanceId);
  133. const oList = oResult.data ?? []
  134. if (oList.length === 0) {
  135. isShowTab.value = false;
  136. }
  137. for (let j = 0; j < oList.length; j++) {
  138. const oItem = oList[j]
  139. if (oItem['status'] == '40') {
  140. oList.splice(j, 1);
  141. j--;
  142. continue;
  143. }
  144. const tItems = tList.filter((item: any) => {
  145. return item['id'] === oItem['flowOpinionId']
  146. })
  147. if (tItems.length > 0) {
  148. const tItem = tItems[0]
  149. if (_o !== 'v' && oItem['activityInstanceId'] === activityInstanceId && oItem['participantId'] === participant) {
  150. oItem['isEditor'] = true;
  151. currentOpinion.value.id = oItem['id']
  152. currentOpinion.value.opinionContent = oItem['opinionContent'] ?? '同意'
  153. currentOpinion.value.opinionTime = formatDate(new Date())
  154. currentOpinion.value.sign = signatureUrl ? signatureUrl : null;
  155. }
  156. oItem['opinionTime'] = oItem['opinionTime'] ? formatDate(new Date(oItem['opinionTime'])) : ''
  157. if (tItem['iHideNonFilledComment'] == 1 && !oItem['opinionContent'] && oItem['activityInstanceId'] !== activityInstanceId) continue;
  158. templateOpinions.push({
  159. opinionName: tItem['opinionName'],
  160. opinionUserText: tItem['opinionUserText'],
  161. opinionTimeText: tItem['opinionTimeText'],
  162. ...oItem
  163. })
  164. }
  165. }
  166. templateOpinions.sort((a, b) => {
  167. return a.isEditor === b.isEditor ? 0 : a.isEditor ? -1 : 1
  168. })
  169. templateOpinion.value = templateOpinions;
  170. }
  171. initTemplateOptinionFunc();
  172. const activityData: FlowDTO = {
  173. activityInstanceId,
  174. participantId: participant,
  175. flowOpinion: "",
  176. };
  177. const router = useRouter();
  178. const submitHandle = async (): Promise<any> => {
  179. emit('submit', async () => {
  180. isSubmitDisabled.value = true;
  181. //工作流转件
  182. activityData.activityInstanceId = activityInstanceId;
  183. activityData.participantId = participant;
  184. activityData.flowOpinion = JSON.stringify(currentOpinion.value);
  185. const result = await getNextActivity(jsonToFormData(activityData) as FormData);
  186. if (result) {
  187. //@ts-ignore
  188. if (result.error_code) {
  189. showNotify({
  190. type: 'danger',
  191. //@ts-ignore
  192. message: result.msg,
  193. position: 'top',
  194. onClose() {
  195. isSubmitDisabled.value = false;
  196. }
  197. });
  198. } else {
  199. showNotify({
  200. type: 'primary',
  201. message: '转件成功',
  202. position: 'top',
  203. onClose() {
  204. isSubmitDisabled.value = false;
  205. PubsubService.publish('clear_keep_alive')
  206. if (_top == '1') {
  207. closePage({})
  208. } else {
  209. router.back();
  210. }
  211. }
  212. });
  213. }
  214. }
  215. return result;
  216. });
  217. }
  218. </script>
  219. <style scoped lang="scss">
  220. .flow_form_box {
  221. height: 100%;
  222. display: flex;
  223. flex-direction: column;
  224. background-color: #f7f8fa;
  225. >.flow_container {
  226. flex-grow: 1;
  227. height: 0px;
  228. overflow-y: scroll;
  229. }
  230. >.fixed-btn {
  231. padding: 10px 20px;
  232. }
  233. .flowOpinionBox {
  234. margin: 10px;
  235. >.flowOpinionItem {
  236. margin-bottom: 15px;
  237. background-color: #fff;
  238. padding: 10px 0px;
  239. &.disabled {
  240. >h4 {
  241. color: #999;
  242. }
  243. >.footer {
  244. > p {
  245. color: #999;
  246. }
  247. }
  248. }
  249. >h4 {
  250. font-size: 17px;
  251. margin: 0px;
  252. padding: 0px 16px;
  253. }
  254. >.content {
  255. :deep(.van-field__value) {
  256. border: 1px solid #ececec;
  257. border-radius: 5px;
  258. padding: 10px
  259. }
  260. }
  261. >.footer {
  262. display: flex;
  263. align-items: center;
  264. padding: 0px 16px;
  265. >p {
  266. margin: 0px;
  267. flex: 1;
  268. white-space: nowrap;
  269. color: #333;
  270. >span {
  271. display: inline-block;
  272. &:first-child {
  273. margin-right: 5px;
  274. }
  275. }
  276. .signImg {
  277. height: 30px;
  278. vertical-align: middle;
  279. }
  280. }
  281. }
  282. }
  283. }
  284. }
  285. </style>