flowForm copy.vue 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  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'] }}
  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'] }}
  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 { formatDate, jsonToFormData } from "@/utils/common";
  85. import { FlowDTO, getNextActivity } from "@/service/flow";
  86. import { getTemplateOpinionListByFlowInstanceId, getOpinionListByFlowInstanceId } from '@/service/flow';
  87. defineOptions({
  88. name: 'FlowForm'
  89. })
  90. const isSubmitVisabled = ref<boolean>(true)
  91. const isSubmitDisabled = ref<boolean>(false)
  92. const userInfo = JSON.parse(localStorage.getItem('_userInfo') as string);
  93. const userId: string = userInfo ? userInfo['id'] ?? '' : ''
  94. const signatureUrl: string = userInfo ? userInfo['signatureUrl'] ?? '' : ''
  95. const currentUserName: string = userInfo ? userInfo['nickname'] ?? '' : ''
  96. defineProps<{
  97. data: any
  98. }>();
  99. const emit = defineEmits<{
  100. (e: 'submit', payload?: any):void
  101. }>()
  102. const route = useRoute();
  103. const currentActive = ref<string>('基础信息')
  104. const { flowInstanceId, activityInstanceId, participant, _o, _top } = route.query as {
  105. flowInstanceId: string
  106. activityInstanceId: string
  107. participant: string
  108. _o: string
  109. _top: string
  110. }
  111. if (_o && _o == 'v') {
  112. isSubmitVisabled.value = false
  113. }
  114. const currentOpinion = ref({
  115. id: '',
  116. opinionContent: '',
  117. opinionTime: '',
  118. sign: ''
  119. })
  120. const isShowTab = ref<boolean>(true)
  121. const templateOpinion = ref<any[]>([]) //用来缓存展示节点
  122. getTemplateOpinionListByFlowInstanceId(flowInstanceId).then((tResult) => {
  123. let tList = tResult.data ?? []
  124. getOpinionListByFlowInstanceId(flowInstanceId).then((oResult) => {
  125. const oList = oResult.data ?? []
  126. if(oList.length === 0){
  127. isShowTab.value = false;
  128. }
  129. if (oList.length > 0) {
  130. for (let i = 0; i < tList.length; i++) {
  131. const tItem = tList[i];
  132. if (tItem['iDisplayOpinion'] === 0) {
  133. tList.splice(i, 1)
  134. i--;
  135. continue;
  136. }
  137. tItem['opinions'] = []
  138. for (let j = 0; j < oList.length; j++) {
  139. const oItem = oList[j]
  140. if (oItem['status'] == '40') {
  141. oList.splice(j, 1);
  142. j--;
  143. continue;
  144. }
  145. if (tItem['id'] === oItem['flowOpinionId']) {
  146. if (_o !== 'v' && oItem['activityInstanceId'] === activityInstanceId && oItem['participantId'] === participant) {
  147. oItem['isEditor'] = true;
  148. currentOpinion.value.id = oItem['id']
  149. currentOpinion.value.opinionContent = oItem['opinionContent'] ?? '同意'
  150. currentOpinion.value.opinionTime = formatDate(new Date())
  151. currentOpinion.value.sign = signatureUrl ? signatureUrl : currentUserName;
  152. }
  153. oItem['opinionTime'] = oItem['opinionTime'] ? formatDate(new Date(oItem['opinionTime'])) : ''
  154. if (tItem['iHideNonFilledComment'] == 1 && !oItem['opinionContent'] && oItem['activityInstanceId'] !== activityInstanceId) continue;
  155. templateOpinion.value.push({
  156. opinionName: tItem['opinionName'],
  157. opinionUserText: tItem['opinionUserText'],
  158. opinionTimeText: tItem['opinionTimeText'],
  159. ...oItem
  160. })
  161. continue
  162. }
  163. }
  164. }
  165. }
  166. })
  167. })
  168. const activityData: FlowDTO = {
  169. activityInstanceId,
  170. participantId: participant,
  171. flowOpinion: "",
  172. };
  173. const router = useRouter();
  174. const submitHandle = async (): Promise<any> => {
  175. emit('submit', async () => {
  176. isSubmitDisabled.value = true;
  177. //工作流转件
  178. activityData.activityInstanceId = activityInstanceId;
  179. activityData.participantId = participant;
  180. activityData.flowOpinion = JSON.stringify(currentOpinion.value);
  181. const result = await getNextActivity(jsonToFormData(activityData) as FormData);
  182. if (result) {
  183. //@ts-ignore
  184. if (result.error_code) {
  185. showNotify({
  186. type: 'danger',
  187. //@ts-ignore
  188. message: result.msg,
  189. position: 'top',
  190. onClose() {
  191. isSubmitDisabled.value = false;
  192. }
  193. });
  194. } else {
  195. showNotify({
  196. type: 'primary',
  197. message: '转件成功',
  198. position: 'top',
  199. onClose() {
  200. isSubmitDisabled.value = false;
  201. if (_top == '1') {
  202. closePage({})
  203. } else {
  204. router.back();
  205. }
  206. }
  207. });
  208. }
  209. }
  210. return result;
  211. });
  212. }
  213. </script>
  214. <style scoped lang="scss">
  215. .flow_form_box {
  216. height: 100%;
  217. display: flex;
  218. flex-direction: column;
  219. background-color: #f7f8fa;
  220. >.flow_container {
  221. flex-grow: 1;
  222. height: 0px;
  223. overflow-y: scroll;
  224. }
  225. >.fixed-btn {
  226. padding: 10px 20px;
  227. }
  228. .flowOpinionBox {
  229. margin: 10px;
  230. >.flowOpinionItem {
  231. margin-bottom: 15px;
  232. background-color: #fff;
  233. padding: 10px 0px;
  234. &.disabled {
  235. >h4 {
  236. color: #999;
  237. }
  238. >.footer {
  239. > p {
  240. color: #999;
  241. }
  242. }
  243. }
  244. >h4 {
  245. font-size: 17px;
  246. margin: 0px;
  247. padding: 0px 16px;
  248. }
  249. >.content {
  250. :deep(.van-field__value) {
  251. border: 1px solid #ececec;
  252. border-radius: 5px;
  253. padding: 10px
  254. }
  255. }
  256. >.footer {
  257. display: flex;
  258. align-items: center;
  259. padding: 0px 16px;
  260. >p {
  261. margin: 0px;
  262. flex: 1;
  263. white-space: nowrap;
  264. color: #333;
  265. >span {
  266. display: inline-block;
  267. &:first-child {
  268. margin-right: 5px;
  269. }
  270. }
  271. .signImg {
  272. height: 30px;
  273. vertical-align: middle;
  274. }
  275. }
  276. }
  277. }
  278. }
  279. }
  280. </style>