index.vue 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436
  1. <template>
  2. <el-dialog
  3. v-model="state.dialogVisible"
  4. draggable
  5. :title="state.dialogTitle"
  6. ref="dialogRef"
  7. @mouseup="mouseup"
  8. :style="'transform: ' + state.transform + ';'"
  9. destroy-on-close
  10. :close-on-click-modal="false"
  11. @close="close"
  12. :modal-class="isOrderAccept ? 'modal_class' : ''"
  13. :class="isOrderAccept ? 'dialog_class' : ''"
  14. :append-to-body="!isOrderAccept"
  15. :modal="!isOrderAccept"
  16. >
  17. <el-steps :active="activeStep" align-center finish-status="success" class="mb20" v-if="showStepsArr.includes(state.processType)">
  18. <el-step title="业务表单" />
  19. <el-step title="流程表单" />
  20. </el-steps>
  21. <div v-show="activeStep === 0" v-loading="state.loading">
  22. <el-form :model="state.delayForm" label-width="110px" ref="delayFormRef" v-if="state.processType === '延期申请'">
  23. <el-row :gutter="10">
  24. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  25. <el-form-item label="工单编码"> {{ state.orderDetail.no }} </el-form-item>
  26. </el-col>
  27. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  28. <el-form-item label="工单标题"> {{ state.orderDetail.title }} </el-form-item>
  29. </el-col>
  30. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  31. <el-form-item label="申请人"> {{ userInfos.name }} </el-form-item>
  32. </el-col>
  33. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  34. <el-form-item label="申请部门"> {{ userInfos.orgName }} </el-form-item>
  35. </el-col>
  36. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  37. <el-form-item label="申请时间"> {{ formatDate(Date(), 'YYYY-mm-dd HH:MM:SS') }} </el-form-item>
  38. </el-col>
  39. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  40. <el-form-item label="当前期满时间"> {{ formatDate(state.orderDetail.expiredTime, 'YYYY-mm-dd HH:MM:SS') }} </el-form-item>
  41. </el-col>
  42. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="12" v-loading="state.loading">
  43. <el-form-item prop="timeLimitCount" :rules="[{ required: true, message: '请填写延期申请数量', trigger: 'blur' }]" label-width="130px">
  44. <template #label>
  45. <div style="height: 34px; display: flex; align-items: center">
  46. 延期申请数量
  47. <el-tooltip placement="top-start">
  48. <SvgIcon name="ele-QuestionFilled" size="18px" class="ml3" />
  49. <template #content> 延期申请数量为1-{{ AppConfigInfo.applyDelayTime }} </template>
  50. </el-tooltip>
  51. </div>
  52. </template>
  53. <el-row :gutter="10" class="w100">
  54. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  55. <el-input-number
  56. placeholder="延期申请数量"
  57. v-model="state.delayForm.timeLimitCount"
  58. controls-position="right"
  59. :min="1"
  60. :max="AppConfigInfo.applyDelayTime"
  61. class="w100"
  62. ></el-input-number>
  63. </el-col>
  64. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-loading="state.loading">
  65. <el-form-item
  66. label=""
  67. label-width="0"
  68. prop="timeLimitUnit"
  69. :rules="[{ required: true, message: '请选择延期申请单位', trigger: 'change' }]"
  70. >
  71. <el-select disabled v-model="state.delayForm.timeLimitUnit" placeholder="延期申请单位">
  72. <el-option v-for="item in timeType" :value="item.key" :key="item.key" :label="item.value" />
  73. </el-select>
  74. </el-form-item>
  75. </el-col>
  76. </el-row>
  77. </el-form-item>
  78. </el-col>
  79. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  80. <el-form-item label="申请理由" prop="content" :rules="[{ required: true, message: '请填写延期申请理由', trigger: 'blur' }]">
  81. <common-advice
  82. @chooseAdvice="chooseAdviceDelay"
  83. v-model="state.delayForm.content"
  84. placeholder="请填写延期申请理由"
  85. :loading="state.loading"
  86. :commonEnum="commonOpinionType"
  87. :maxlength="AppConfigInfo.handleOpinionWordLimit"
  88. />
  89. </el-form-item>
  90. </el-col>
  91. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  92. <el-form-item label="附件">
  93. <annex-list name="延期附件" v-model:format="handleFilesDelay" :businessId="state.orderDetail.id" classify="延期上传" />
  94. </el-form-item>
  95. </el-col>
  96. </el-row>
  97. </el-form>
  98. <el-form :model="state.discernForm" label-width="110px" ref="discernFormRef" v-if="state.processType === '甄别申请'">
  99. <el-row :gutter="10">
  100. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  101. <el-form-item label="工单编码"> {{ state.orderDetail.no }} </el-form-item>
  102. </el-col>
  103. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  104. <el-form-item label="工单标题"> {{ state.orderDetail.title }} </el-form-item>
  105. </el-col>
  106. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  107. <el-form-item label="申请人"> {{ userInfos.name }} </el-form-item>
  108. </el-col>
  109. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  110. <el-form-item label="申请部门"> {{ userInfos.orgName }} </el-form-item>
  111. </el-col>
  112. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  113. <el-form-item label="申请时间"> {{ formatDate(Date(),'YYYY-MM-DD HH:mm:ss') }} </el-form-item>
  114. </el-col>
  115. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  116. <el-form-item label="申请类型" prop="type" :rules="[{ required: true, message: '请选择申请类型', trigger: 'change' }]">
  117. <el-select v-model="state.discernForm.type" placeholder="请选择申请类型" class="w100" value-key="dicDataValue">
  118. <el-option v-for="item in screenTypeOptions" :value="item" :key="item.dicDataValue" :label="item.dicDataName" />
  119. </el-select>
  120. </el-form-item>
  121. </el-col>
  122. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  123. <el-form-item label="申请理由" prop="content" :rules="[{ required: true, message: '请填写甄别申请理由', trigger: 'blur' }]">
  124. <common-advice
  125. @chooseAdvice="chooseAdviceDiscern"
  126. v-model="state.discernForm.content"
  127. placeholder="请填写甄别申请理由"
  128. :loading="state.loading"
  129. :commonEnum="commonOpinionType"
  130. :maxlength="AppConfigInfo.handleOpinionWordLimit"
  131. />
  132. </el-form-item>
  133. </el-col>
  134. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  135. <el-form-item label="附件">
  136. <annex-list
  137. name="甄别附件"
  138. ref="discernAnnexListRef"
  139. v-model:format="handleFilesDiscern"
  140. :businessId="state.orderDetail.id"
  141. classify="甄别上传"
  142. />
  143. </el-form-item>
  144. </el-col>
  145. </el-row>
  146. </el-form>
  147. <el-form :model="state.terminateForm" label-width="110px" ref="terminateFormRef" v-if="state.processType === '终止申请'">
  148. <el-row :gutter="10">
  149. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  150. <el-form-item label="工单编码"> {{ state.orderDetail.no }} </el-form-item>
  151. </el-col>
  152. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  153. <el-form-item label="工单标题"> {{ state.orderDetail.title }} </el-form-item>
  154. </el-col>
  155. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  156. <el-form-item label="终止理由" prop="content" :rules="[{ required: true, message: '请填写终止申请理由', trigger: 'blur' }]">
  157. <common-advice
  158. @chooseAdvice="chooseAdviceTerminate"
  159. v-model="state.terminateForm.content"
  160. placeholder="请填写终止申请理由"
  161. :loading="state.loading"
  162. :commonEnum="commonOpinionType"
  163. :maxlength="AppConfigInfo.handleOpinionWordLimit"
  164. />
  165. </el-form-item>
  166. </el-col>
  167. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  168. <el-form-item label="附件">
  169. <annex-list
  170. name="终止附件"
  171. ref="terminateAnnexListRef"
  172. v-model:format="handleFilesTerminate"
  173. :businessId="state.orderDetail.id"
  174. classify="终止上传"
  175. />
  176. </el-form-item>
  177. </el-col>
  178. </el-row>
  179. </el-form>
  180. </div>
  181. <el-form :model="state.ruleForm" label-width="110px" ref="ruleFormRef" v-show="activeStep === 1" v-loading="state.loading">
  182. <slot name="header"></slot>
  183. <el-row :gutter="10">
  184. <!-- 审批流程 -->
  185. <template v-if="auditArr.includes(state.processType) && canReject">
  186. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="!returnArr.includes(state.processType)">
  187. <el-form-item label="审批结果" prop="isPass" :rules="[{ required: true, message: '请选择审批结果', trigger: 'change' }]">
  188. <el-radio-group v-model="state.ruleForm.isPass">
  189. <el-radio :value="true">同意</el-radio>
  190. <el-radio :value="false">不同意</el-radio>
  191. </el-radio-group>
  192. </el-form-item>
  193. </el-col>
  194. <!-- 审批通过 -->
  195. <template v-if="state.ruleForm.isPass">
  196. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  197. <el-form-item label="下一环节" prop="nextStepCode" :rules="[{ required: true, message: '请选择下一环节', trigger: 'change' }]">
  198. <el-select v-model="state.ruleForm.nextStepCode" placeholder="请选择下一环节" class="w100" @change="selectNextStep">
  199. <el-option v-for="item in state.nextStepOptions" :key="item.key" :label="item.value" :value="item.key" />
  200. </el-select>
  201. <p class="flex-center-align color-danger" v-if="showFastSendOrder">
  202. 当前推荐派单办理对象:{{ fastStepName }} <el-button type="primary" link class="ml4" @click="fastSendOrder">快捷派单</el-button>
  203. </p>
  204. </el-form-item>
  205. </el-col>
  206. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="!returnArr.includes(state.processType) && showHandlers">
  207. <el-form-item
  208. label="办理对象"
  209. prop="nextHandlers"
  210. :rules="[{ required: nextHandlersRequired, message: '请选择办理对象', trigger: 'change' }]"
  211. v-if="!returnArr.includes(state.processType) && showHandlers"
  212. >
  213. <el-select-v2
  214. v-model="state.ruleForm.nextHandlers"
  215. :options="state.handlerOptions"
  216. placeholder="请选择办理对象"
  217. class="w100"
  218. multiple
  219. clearable
  220. collapse-tags
  221. collapse-tags-tooltip
  222. filterable
  223. value-key="key"
  224. @change="selectHandlers"
  225. :multiple-limit="multipleLimit"
  226. />
  227. </el-form-item>
  228. </el-col>
  229. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="showMainHandler">
  230. <el-form-item label="主办" prop="nextMainHandler" :rules="[{ required: false, message: '请选择主办', trigger: 'change' }]">
  231. <el-select v-model="state.ruleForm.nextMainHandler" placeholder="请选择主办" class="w100" filterable>
  232. <el-option v-for="item in state.handlerMainOptions" :key="item.key" :label="item.value" :value="item.key" />
  233. </el-select>
  234. </el-form-item>
  235. </el-col>
  236. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="countersignAble">
  237. <el-form-item label="发起会签" prop="isStartCountersign" :rules="[{ required: false, message: '请选择发起会签', trigger: 'change' }]">
  238. <el-switch
  239. v-model="state.ruleForm.isStartCountersign"
  240. inline-prompt
  241. active-text="是"
  242. inactive-text="否"
  243. @change="changeStartCountersign"
  244. :disabled="countersignDisabled"
  245. />
  246. </el-form-item>
  247. </el-col>
  248. </template>
  249. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  250. <el-form-item label="" prop="isSms">
  251. <el-checkbox v-model="state.ruleForm.isSms" label="短信通知" />
  252. </el-form-item>
  253. </el-col>
  254. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  255. <el-form-item
  256. :label="state.inputPlaceholder"
  257. prop="opinion"
  258. :rules="[{ required: true, message: `请填写${state.inputPlaceholder}`, trigger: 'blur' }]"
  259. >
  260. <common-advice
  261. @chooseAdvice="chooseAdvice"
  262. v-model="state.ruleForm.opinion"
  263. :placeholder="'请填写' + state.inputPlaceholder"
  264. :loading="state.loading"
  265. :commonEnum="commonOpinionType"
  266. :maxlength="AppConfigInfo.handleOpinionWordLimit"
  267. />
  268. </el-form-item>
  269. </el-col>
  270. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  271. <el-form-item label="附件" :rules="[{ required: false, message: '请填写诉求内容', trigger: 'change' }]">
  272. <annex-list :name="state.annexName" :businessId="state.orderDetail.id" :classify="state.classify" v-model:format="handleFiles" />
  273. </el-form-item>
  274. </el-col>
  275. </template>
  276. <!-- 办理流程 -->
  277. <template v-else>
  278. <!-- 非退回流程都需要选择 -->
  279. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="!returnArr.includes(state.processType)">
  280. <el-form-item label="下一环节" prop="nextStepCode" :rules="[{ required: true, message: '请选择下一环节', trigger: 'change' }]">
  281. <el-select v-model="state.ruleForm.nextStepCode" placeholder="请选择下一环节" class="w100" @change="selectNextStep">
  282. <el-option v-for="item in state.nextStepOptions" :key="item.key" :label="item.value" :value="item.key" />
  283. </el-select>
  284. <p class="flex-center-align color-danger" v-if="showFastSendOrder">
  285. 当前推荐派单办理对象:{{ fastStepName }} <el-button type="primary" link class="ml4" @click="fastSendOrder">快捷派单</el-button>
  286. </p>
  287. </el-form-item>
  288. </el-col>
  289. <!-- 非退回流程都需要选择并且如果选择了结束节点就不需要选择办理对象 -->
  290. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="!returnArr.includes(state.processType) && showHandlers">
  291. <el-form-item
  292. label="办理对象"
  293. prop="nextHandlers"
  294. :rules="[{ required: nextHandlersRequired, message: '请选择办理对象', trigger: 'change' }]"
  295. >
  296. <el-select-v2
  297. v-model="state.ruleForm.nextHandlers"
  298. :options="state.handlerOptions"
  299. placeholder="请选择办理对象"
  300. class="w100"
  301. multiple
  302. clearable
  303. collapse-tags
  304. collapse-tags-tooltip
  305. filterable
  306. value-key="key"
  307. @change="selectHandlers"
  308. :multiple-limit="multipleLimit"
  309. />
  310. </el-form-item>
  311. </el-col>
  312. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="showMainHandler">
  313. <el-form-item label="主办" prop="nextMainHandler" :rules="[{ required: false, message: '请选择主办', trigger: 'change' }]">
  314. <el-select v-model="state.ruleForm.nextMainHandler" placeholder="请选择主办" class="w100" filterable>
  315. <el-option v-for="item in state.handlerMainOptions" :key="item.key" :label="item.value" :value="item.key" />
  316. </el-select>
  317. </el-form-item>
  318. </el-col>
  319. <!-- 工单办理专有参数 -->
  320. <template v-if="flowDirection">
  321. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  322. <el-form-item label="办理时限" prop="timeLimit" :rules="[{ required: true, message: '请填写办理时限', trigger: 'blur' }]">
  323. <el-row :gutter="10">
  324. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  325. <el-input-number
  326. placeholder="办理时限"
  327. v-model="state.ruleForm.timeLimit"
  328. controls-position="right"
  329. class="w100"
  330. :min="1"
  331. :max="99"
  332. disabled
  333. ></el-input-number>
  334. </el-col>
  335. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-loading="state.loading">
  336. <el-form-item
  337. label=""
  338. label-width="0"
  339. prop="timeLimitUnit"
  340. :rules="[{ required: true, message: '请选择办理时限单位', trigger: 'change' }]"
  341. >
  342. <el-select v-model="state.ruleForm.timeLimitUnit" placeholder="办理时限单位" disabled style="width: 240px">
  343. <el-option v-for="item in timeTypeOptions" :value="item.key" :key="item.key" :label="item.value" />
  344. </el-select>
  345. </el-form-item>
  346. </el-col>
  347. </el-row>
  348. </el-form-item>
  349. </el-col>
  350. </template>
  351. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="countersignAble">
  352. <el-form-item label="发起会签" prop="isStartCountersign" :rules="[{ required: false, message: '请选择发起会签', trigger: 'change' }]">
  353. <el-switch
  354. v-model="state.ruleForm.isStartCountersign"
  355. inline-prompt
  356. active-text="是"
  357. inactive-text="否"
  358. @change="changeStartCountersign"
  359. :disabled="countersignDisabled"
  360. />
  361. </el-form-item>
  362. </el-col>
  363. <!-- 汇总节点需要填写 并且是工单办理 -->
  364. <template v-if="inputRealHandler">
  365. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  366. <el-form-item label="经办人" prop="realHandlerName" :rules="[{ required: false, message: '请填写经办人', trigger: 'blur' }]">
  367. <el-input v-model="state.ruleForm.realHandlerName" placeholder="请填写经办人" clearable> </el-input>
  368. </el-form-item>
  369. </el-col>
  370. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  371. <el-form-item label="经办人电话" prop="realHandlerPhone" :rules="[{ required: false, message: '请填写经办人电话', trigger: 'blur' }]">
  372. <el-input v-model="state.ruleForm.realHandlerPhone" placeholder="请填写办理人电话" 请填写经办人电话> </el-input>
  373. </el-form-item>
  374. </el-col>
  375. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  376. <el-form-item label="是否与市民沟通" prop="realIsContacted">
  377. <el-switch v-model="state.ruleForm.realIsContacted" inline-prompt active-text="是" inactive-text="否" />
  378. </el-form-item>
  379. </el-col>
  380. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  381. <el-form-item label="是否与市民现场沟通" prop="realContactLocale" label-width="150">
  382. <el-switch v-model="state.ruleForm.realContactLocale" inline-prompt active-text="是" inactive-text="否" />
  383. </el-form-item>
  384. </el-col>
  385. </template>
  386. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" v-if="isSmsSelectShow">
  387. <el-form-item label="" prop="isSms">
  388. <el-checkbox v-model="state.ruleForm.isSms" label="短信通知" />
  389. </el-form-item>
  390. </el-col>
  391. <!-- 选择结束节点时并且是工单办理并且不是中心,显示部门处理结果 -->
  392. <template v-if="showResult">
  393. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  394. <el-form-item label="处理结果" prop="isResolved" :rules="[{ required: true, message: '请选择处理结果', trigger: 'change' }]">
  395. <el-radio-group v-model="state.ruleForm.isResolved">
  396. <el-radio :value="true">已得到解决</el-radio>
  397. <el-radio :value="false">未得到解决</el-radio>
  398. </el-radio-group>
  399. </el-form-item>
  400. </el-col>
  401. </template>
  402. <!-- 选择结束节点时并且是工单办理并且工单来源是110时,显示警情退回 -->
  403. <template v-if="showPoliceReturn">
  404. <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
  405. <el-form-item label="" prop="isPoliceReturn">
  406. <el-checkbox v-model="state.ruleForm.isPoliceReturn" label="警情退回" />
  407. </el-form-item>
  408. </el-col>
  409. </template>
  410. <template v-if="!['延期申请', '甄别申请', '终止申请'].includes(state.processType)">
  411. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  412. <el-form-item
  413. :label="state.inputPlaceholder"
  414. prop="opinion"
  415. :rules="[{ required: true, message: `请填写${state.inputPlaceholder}`, trigger: 'blur' }]"
  416. >
  417. <common-advice
  418. @chooseAdvice="chooseAdvice"
  419. v-model="state.ruleForm.opinion"
  420. :placeholder="'请填写' + state.inputPlaceholder"
  421. :loading="state.loading"
  422. :commonEnum="commonOpinionType"
  423. :maxlength="AppConfigInfo.handleOpinionWordLimit"
  424. />
  425. </el-form-item>
  426. </el-col>
  427. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="showRemarkTextarea">
  428. <el-form-item label="备注信息" prop="remark" :rules="[{ required: false, message: `请填写备注信息`, trigger: 'blur' }]">
  429. <el-input v-model="state.ruleForm.remark" :rows="2" type="textarea" placeholder="请填写备注信息" />
  430. </el-form-item>
  431. </el-col>
  432. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  433. <el-form-item label="附件" :rules="[{ required: false, message: '请填写诉求内容', trigger: 'change' }]">
  434. <annex-list :name="state.annexName" :businessId="state.orderDetail.id" :classify="state.classify" v-model:format="handleFiles" />
  435. </el-form-item>
  436. </el-col>
  437. </template>
  438. </template>
  439. </el-row>
  440. </el-form>
  441. <template #footer>
  442. <span class="dialog-footer">
  443. <el-text type="danger" class="mr15" tag="b" v-if="showTempSave">温馨提示:临时保存只保存{{ state.inputPlaceholder }}</el-text>
  444. <el-button @click="closeDialog" class="default-button">取 消</el-button>
  445. <el-button type="primary" @click="handleTempSave" :loading="state.loading" v-if="showTempSave">临时保存</el-button>
  446. <el-button
  447. class="default-button"
  448. @click="onPrevious"
  449. :loading="state.loading"
  450. v-if="activeStep === 1 && showStepsArr.includes(state.processType)"
  451. >上一步</el-button
  452. >
  453. <el-button class="default-button" @click="onNext" :loading="state.loading" v-if="activeStep === 0 && showStepsArr.includes(state.processType)"
  454. >下一步</el-button
  455. >
  456. <el-popconfirm
  457. title="该工单属于超期状态,若符合延期要求,请延期通过后办结,是否继续办理?"
  458. v-if="isOverdueTips"
  459. @confirm="onSubmit(ruleFormRef)"
  460. width="300"
  461. >
  462. <template #reference>
  463. <el-button type="primary" :loading="state.loading">办理</el-button>
  464. </template>
  465. </el-popconfirm>
  466. <el-button type="primary" @click="onSubmit(ruleFormRef)" :loading="state.loading" v-else-if="!isOverdueTips && activeStep === 1"
  467. >办理</el-button
  468. >
  469. </span>
  470. </template>
  471. </el-dialog>
  472. </template>
  473. <script setup lang="ts" name="processApproval">
  474. import { computed, defineAsyncComponent, nextTick, reactive, ref, watch, watchEffect } from 'vue';
  475. import { ElMessage, FormInstance } from 'element-plus';
  476. import other from '@/utils/other';
  477. import { useUserInfo } from '@/stores/userInfo';
  478. import { storeToRefs } from 'pinia';
  479. import { commonEnum } from '@/utils/constants';
  480. import { orderFlowParams, orderHandle, orderProcessTempSave, orderStartFlow, orderTimeConfig } from '@/api/business/order';
  481. import {
  482. orderPrevious,
  483. workflowNext,
  484. workflowNextSteps,
  485. workflowNextStepsByOrder,
  486. workflowNextStepsByOrderInstead,
  487. workflowPrevious,
  488. workflowRecall,
  489. workflowRecallParams,
  490. workflowReject,
  491. } from '@/api/system/workflow';
  492. import { delayApply, delayApproveParams, delayBaseData, delayCalcEndTime, workflowDelayParams } from '@/api/business/delay';
  493. import { discernApply, discernApproveParams, screenBaseData, workflowDiscernParams } from '@/api/business/discern';
  494. import { debounce } from '@/utils/tools';
  495. import {
  496. KnowledgeAdd,
  497. KnowledgeAddStartFlowParams,
  498. KnowledgeDel,
  499. KnowledgeDeleteStartFlowParams,
  500. KnowledgeOffShelf,
  501. KnowledgeOffShelfStartFlowParams,
  502. KnowledgeUpdate,
  503. KnowledgeUpdateStartFlowParams,
  504. } from '@/api/knowledge';
  505. import { formatDate } from '@/utils/formatTime';
  506. import { useAppConfig } from '@/stores/appConfig';
  507. import { terminateNextFlowParams, terminateStartFlow, terminateStartFlowParams } from '@/api/business/terminate';
  508. // 引入组件
  509. const CommonAdvice = defineAsyncComponent(() => import('@/components/CommonAdvice/index.vue')); // 常用意见
  510. const AnnexList = defineAsyncComponent(() => import('@/components/AnnexList/index.vue')); // 附件列表
  511. // 定义子组件向父组件传值/事件
  512. const emit = defineEmits(['orderProcessSuccess', 'orderProcessFailed']);
  513. // 定义变量内容
  514. const state = reactive<any>({
  515. dialogVisible: false, // 弹窗显示隐藏
  516. ruleForm: {
  517. isPass: true, // 审批结果
  518. //流程表单
  519. opinion: '', // 意见
  520. nextStepCode: '', // 下一节点
  521. nextStepName: '', // 下一节点名称
  522. backToCountersignEnd: false, // 是否回到会签结束节点
  523. nextHandlers: [], // 下一节点办理对象
  524. nextMainHandler: '', // 主办人
  525. isSms: false, // 是否短信通知
  526. isStartCountersign: false, // 是否发起会签
  527. stepId: null, // 步骤id
  528. // isTransferHandle:false, // 是否转办
  529. },
  530. delayForm: {
  531. //延期申请表单
  532. timeLimitCount: null, // 延期申请数量
  533. content: '', // 延期申请理由
  534. timeLimitUnit: 2, // 延期申请单位 默认工作日
  535. },
  536. discernForm: {
  537. // 甄别表单
  538. content: '', // 甄别理由
  539. },
  540. redoForm: {
  541. // 重办表单
  542. content: '', // 重办理由
  543. },
  544. terminateForm: {
  545. //终止表单
  546. content: '', // 终止理由
  547. },
  548. nextStepOptions: [], // 下一节点
  549. handlerOptions: [], // 办理对象
  550. transform: 'translate(0px, 0px)', // 滚动条位置
  551. loading: false, // 提交按钮loading
  552. processType: 'next', // 流程状态
  553. workflowId: '', // 流程id
  554. handlerClassifies: [], //撤回办理对象
  555. handlerMainOptions: [], // 主办人
  556. handleId: '', // 流程处理ID
  557. dialogTitle: '', // 弹窗标题
  558. annexName: '', // 附件标题
  559. inputPlaceholder: '办理意见', // 意见提示
  560. orderDetail: {}, // 工单详情
  561. });
  562. const ruleFormRef = ref<RefType>(); //表单组件
  563. const storesUserInfo = useUserInfo();
  564. const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
  565. const showStepsArr = ['延期申请', '甄别申请', '终止申请']; // 显示步骤条的流程
  566. const handelArr = ['工单办理']; // 处于办理状态的流程 (如果是汇总节点 需要填写办理对象等 办理流程才有期满时间)
  567. const returnArr = ['工单退回', '甄别退回', '延期退回', '终止退回']; // 退回流程 (退回流程不需要展示其他 只需要填写意见和附件即可)
  568. const auditArr = ['甄别审批', '延期审批', '知识审批', '终止审批']; // 审批流程 (审批流程需要选择是否通过和下一环节)
  569. const appConfigStore = useAppConfig();
  570. const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
  571. const showTempSave = computed(() => {
  572. // 是否显示临时办理
  573. return ['工单办理', '工单代办', '工单受理'].includes(state.processType);
  574. });
  575. const timeType = ref<EmptyArrayType>([]); // 延期申请单位
  576. const screenTypeOptions = ref<EmptyArrayType>([]); // 甄别类型
  577. const screenType = ref(null); // 甄别类型 自贡甄别特殊需求
  578. // 打开弹窗
  579. const openDialog = async (val: any) => {
  580. console.log(val);
  581. selectNext.value = {};
  582. currentParams.value = {};
  583. state.ruleForm.nextHandlers = [];
  584. state.ruleForm.nextHandler = {};
  585. isSmsSelectShow.value = false;
  586. state.ruleForm.isSms = false;
  587. state.loading = true;
  588. state.dialogVisible = true;
  589. try {
  590. const { id, processType, extra, orderDetail } = val;
  591. state.ruleForm.workflowId = state.workflowId = id ?? ''; // 流程id
  592. state.processType = processType ?? '办理流程'; // 业务类型
  593. state.orderDetail = orderDetail ?? {}; // 工单详情
  594. const { dialogTitle, inputPlaceholder, annexName, classify } = extra ?? {};
  595. state.dialogTitle = dialogTitle ?? '提交流程'; // 流程标题
  596. state.annexName = annexName ?? '办理附件'; // 附件标题
  597. state.classify = classify ?? '办理上传'; // 附件分类
  598. state.inputPlaceholder = inputPlaceholder ?? '办理意见'; // 意见提示
  599. screenType.value = extra.screenType;
  600. switch (state.processType) {
  601. case '工单受理': //开始流程
  602. const [orderStartWorkflowResponse] = await Promise.all([orderFlowParams(orderDetail.id)]); //获取开启流程参数
  603. handleResult(orderStartWorkflowResponse);
  604. break;
  605. case '工单撤回': // 撤回流程
  606. const [workflowRecallResponse] = await Promise.all([workflowRecallParams(state.workflowId)]); //获取开启流程参数
  607. handleResult(workflowRecallResponse);
  608. break;
  609. case '延期申请': // 延期申请
  610. const [workflowDelayResponse, responseDelay] = await Promise.all([workflowDelayParams(), delayBaseData()]); //获取开启流程参数
  611. timeType.value = responseDelay.result?.timeType ?? []; // 延期时间单位
  612. handleResult(workflowDelayResponse);
  613. break;
  614. case '延期审批': // 延期审批
  615. const [nextResponseDelayAudit] = await Promise.all([delayApproveParams(state.workflowId)]); //获取延期审批流程参数
  616. handleResult(nextResponseDelayAudit);
  617. break;
  618. case '甄别申请': // 甄别申请
  619. const [workflowDiscernResponse, responseDiscern] = await Promise.all([workflowDiscernParams(), screenBaseData()]); //获取开启流程参数
  620. screenTypeOptions.value = responseDiscern.result?.screenType ?? []; // 甄别理由
  621. handleResult(workflowDiscernResponse);
  622. break;
  623. case '终止申请': // 终止申请
  624. const [workflowTerminateResponse] = await Promise.all([terminateStartFlowParams()]); //获取开启流程参数
  625. handleResult(workflowTerminateResponse);
  626. break;
  627. case '工单退回': // 退回流程
  628. break;
  629. case '甄别退回': // 退回流程
  630. break;
  631. case '甄别审批': // 甄别审批
  632. const [nextResponseDiscernAudit] = await Promise.all([discernApproveParams(state.workflowId)]); //获取甄别审批流程参数
  633. handleResult(nextResponseDiscernAudit);
  634. break;
  635. case '终止审批': // 终止审批
  636. const [nextResponseTerminateAudit] = await Promise.all([terminateNextFlowParams(state.workflowId)]); //获取终止审批流程参数
  637. handleResult(nextResponseTerminateAudit);
  638. break;
  639. case '延期退回': // 退回流程
  640. break;
  641. case '工单办理': // 工单办理
  642. const [workflowNextStepsResponse] = await Promise.all([workflowNextStepsByOrder(state.orderDetail.id)]); // 获取下一节点和下一节点参数
  643. handleResult(workflowNextStepsResponse);
  644. break;
  645. case '工单代办':
  646. const [orderHandleInstanceResponse] = await Promise.all([workflowNextStepsByOrderInstead(state.orderDetail.id)]); // 工单代办参数获取
  647. handleResult(orderHandleInstanceResponse);
  648. break;
  649. case '新增知识':
  650. const [KnowledgeAddStartFlowResponse] = await Promise.all([KnowledgeAddStartFlowParams()]); // 知识库新增参数
  651. handleResult(KnowledgeAddStartFlowResponse);
  652. break;
  653. case '更新知识':
  654. const [KnowledgeUpdateResponse] = await Promise.all([KnowledgeUpdateStartFlowParams()]); // 知识库更新参数
  655. handleResult(KnowledgeUpdateResponse);
  656. break;
  657. case '更新新增知识':
  658. const [KnowledgeAddUpdateResponse] = await Promise.all([KnowledgeAddStartFlowParams()]); // 知识库更新参数
  659. handleResult(KnowledgeAddUpdateResponse);
  660. break;
  661. case '删除知识':
  662. const [KnowledgeDeleteResponse] = await Promise.all([KnowledgeDeleteStartFlowParams()]); // 知识库删除参数
  663. handleResult(KnowledgeDeleteResponse);
  664. break;
  665. case '知识下架':
  666. const [KnowledgeOffShelfResponse] = await Promise.all([KnowledgeOffShelfStartFlowParams()]); // 知识库下架参数
  667. handleResult(KnowledgeOffShelfResponse);
  668. break;
  669. default: // 默认下一流程 工单办理
  670. // 获取下一节点和下一节点参数
  671. const [nextResponse] = await Promise.all([workflowNextSteps(state.workflowId)]);
  672. handleResult(nextResponse);
  673. break;
  674. }
  675. await nextTick(() => {
  676. restForm(ruleFormRef.value);
  677. });
  678. } finally {
  679. state.loading = false;
  680. }
  681. };
  682. const isOrderAccept = computed(() => {
  683. return state.processType === '工单受理';
  684. });
  685. // 常用意见类型
  686. const commonOpinionType = computed(() => {
  687. switch (state.processType) {
  688. case '工单受理':
  689. return commonEnum.Seat;
  690. case '工单退回':
  691. return commonEnum.Return;
  692. case '工单办理':
  693. return commonEnum.OrderCirculation;
  694. case '甄别审批':
  695. case '甄别申请':
  696. return commonEnum.Discriminate;
  697. case '延期审批':
  698. case '延期申请':
  699. return commonEnum.Delay;
  700. case '终止审批':
  701. case '终止申请':
  702. return commonEnum.OrderCirculation;
  703. case '知识审批':
  704. return commonEnum.KnowledgeL;
  705. default:
  706. return commonEnum.OrderCirculation;
  707. }
  708. });
  709. const canReject = ref<boolean>(false); // 是否可以驳回
  710. const timeTypeOptions = ref<EmptyArrayType>([]); // 办理时限单位
  711. const canStartCountersign = ref<boolean>(false); // 是否可以发起会签
  712. const isMainHandlerShow = ref<boolean>(false); // 是否展示主办人
  713. const currentParams = ref<EmptyObjectType>({}); // 当前获取到的参数(当前节点信息)
  714. const handleResult = (res: any) => {
  715. currentParams.value = res.result; // 当前获取到的参数(当前节点信息)
  716. state.nextStepOptions = res.result.steps; //办理对象选择内容
  717. canReject.value = res.result.canReject ?? false; // 是否可以驳回
  718. timeTypeOptions.value = res.result.timeTypeOptions ?? []; // 办理时限申请单位
  719. canStartCountersign.value = res.result.canStartCountersign ?? false; // 是否可以发起会签
  720. isMainHandlerShow.value = res.result.isMainHandlerShow ?? false; // 是否展示主办人
  721. if (handelArr.includes(state.processType)) {
  722. // 办理才有期满时间
  723. state.ruleForm.expiredTime = res.result.expiredTime ?? null; // 期满时间
  724. }
  725. if (state.nextStepOptions.length === 1) {
  726. // 下一节点是否只有一个 默认选中第一个
  727. setTimeout(() => {
  728. state.ruleForm.nextStepCode = state.nextStepOptions[0].key; // 下一节点code
  729. state.ruleForm.nextStepName = state.nextStepOptions[0].value; // 下一节点name
  730. state.ruleForm.backToCountersignEnd = state.nextStepOptions[0].backToCountersignEnd ?? false; // 是否回到会签结束节点
  731. }, 100);
  732. selectNextStep(state.nextStepOptions[0].key); // 查询流程下一节点参数
  733. } else {
  734. state.ruleForm.nextStepCode = '';
  735. state.ruleForm.nextStepName = '';
  736. }
  737. if (res.result.opinion) {
  738. // 如果有汇总意见没有临时保存 取汇总意见 临时保存会覆盖汇总意见
  739. setTimeout(() => {
  740. state.ruleForm.opinion = res.result.opinion;
  741. }, 100);
  742. }
  743. state.ruleForm.stepId = res.result.stepId;
  744. state.loading = false;
  745. };
  746. // 上一部
  747. const onPrevious = () => {
  748. activeStep.value = 0;
  749. };
  750. const delayFormRef = ref<RefType>(); //延期申请表单组件
  751. const discernFormRef = ref<RefType>(); //甄别申请表单组件
  752. const terminateFormRef = ref<RefType>(); // 终止申请表单组件
  753. const redoFormRef = ref<RefType>(); //重办表单组件
  754. // 下一步
  755. const onNext = () => {
  756. switch (state.processType) {
  757. case '延期申请':
  758. delayFormRef.value?.validate((valid: boolean) => {
  759. if (!valid) return;
  760. activeStep.value = 1;
  761. });
  762. break;
  763. case '甄别申请': // 甄别申请
  764. discernFormRef.value?.validate((valid: boolean) => {
  765. if (!valid) return;
  766. activeStep.value = 1;
  767. });
  768. break;
  769. case '终止申请': // 终止申请
  770. terminateFormRef.value?.validate((valid: boolean) => {
  771. if (!valid) return;
  772. activeStep.value = 1;
  773. });
  774. break;
  775. default: // 默认下一流程
  776. activeStep.value = 1;
  777. break;
  778. }
  779. };
  780. const activeStep = ref(0); //步骤条
  781. watchEffect(() => {
  782. if (state.dialogVisible) {
  783. activeStep.value = showStepsArr.includes(state.processType) ? 0 : 1;
  784. }
  785. });
  786. // 流程选择下一环节
  787. const fastStepCode = ref(''); // 推荐派单处理对象code
  788. const fastStepName = ref(''); // 推荐派单处理对象
  789. // expiredStatus 超期状态(0正常 1即将超期 2已超期) 工单流转选择“结束”节点,点击“办理”时需验证该工单是否处于已超期状态
  790. const isOverdueTips = computed(() => {
  791. return state.orderDetail.expiredStatus === 2 && state.ruleForm.nextStepCode === 'end';
  792. });
  793. // 先确定当前环节是那一步
  794. /*
  795. * currentParams.value.currentStepBusinessType 表示当前节点到哪一步 0坐席 1派单 2部门节点 3部门领导节点
  796. * */
  797. /*selectNext.value.businessType 表示选择节点到哪一步 0 坐席 1派单 2部门节点 3部门领导节点
  798. * selectNext.value.orgLevel 表示部门等级 1 一级部门 2 二级部门 3 三级部门 4 四级部门
  799. * selectNext.value.stepType 3汇总节点
  800. * */
  801. // 话务部到派单组
  802. const seatTopaidan = computed(() => {
  803. return currentParams.value.currentStepBusinessType === 0 && selectNext.value.businessType === 1;
  804. });
  805. // 派单组到部门
  806. const paidanToOrg = computed(() => {
  807. return currentParams.value.currentStepBusinessType === 1 && selectNext.value.businessType === 2;
  808. });
  809. // 是否展示短信通知选择
  810. const isSmsSelectShow = ref(false);
  811. // 办理对象是否必填 0-角色 1-部门类型 2-部门类型 3-指定用户 4-指定部门
  812. // 2024/10/28 新增甄别申请 延期申请 终止申请选择办理对象非必填 !showStepsArr.includes(state.processType)
  813. const nextHandlersRequired = ref<Boolean>(false);
  814. const selectNext = ref<EmptyObjectType>({}); // 选择的下一个节点
  815. const selectNextStep = (val: any) => {
  816. ruleFormRef.value?.resetFields('nextHandlers');
  817. ruleFormRef.value?.resetFields('nextMainHandler');
  818. const next = state.nextStepOptions.find((item: any) => item.key === val);
  819. selectNext.value = next;
  820. const items = next.items; //获取下一节点
  821. state.ruleForm.nextStepName = next.value; // 下一节点name
  822. state.ruleForm.handlerType = next.handlerType;
  823. state.ruleForm.businessType = next.businessType;
  824. state.ruleForm.flowDirection = next.flowDirection;
  825. state.ruleForm.backToCountersignEnd = next.backToCountersignEnd ?? false; // 是否回到会签结束节点
  826. state.handlerOptions = items ?? [];
  827. state.handlerOptions = state.handlerOptions.map((item: any) => {
  828. return {
  829. value: {
  830. ...item,
  831. },
  832. label: item.value,
  833. };
  834. });
  835. fastStepName.value = next.recommendOrgName; // 推荐派单处理对象
  836. fastStepCode.value = next.recommendOrgId; // 推荐派单处理对象code
  837. if (items.length === 1) {
  838. // 如果办理对象只有一个默认选中
  839. state.ruleForm.nextHandlers = [items[0]];
  840. }
  841. // 办理对象是否必填
  842. // nextHandlersRequired.value = ![0].includes(next.handlerType) && !showStepsArr.includes(state.processType);
  843. nextHandlersRequired.value = ![0].includes(next.handlerType);
  844. // 以下是默认需要吧短信勾上的场景 派单组到部门
  845. state.ruleForm.isSms = paidanToOrg.value;
  846. // 是否展示短信通知 (取消坐席流转至“派单组”时的短信通知选项框 )
  847. isSmsSelectShow.value = !seatTopaidan.value;
  848. };
  849. // 会签是否可用 (多个办理对象,并且配置可以会签)
  850. const countersignAble = computed(() => {
  851. return canStartCountersign.value;
  852. });
  853. // 办理对象是否能够选择多个(可以发起会签可以选择多个,不能发起会签只能选择一个)
  854. const multipleLimit = computed(() => {
  855. return canStartCountersign.value ? 0 : 1;
  856. });
  857. watch(
  858. () => state.ruleForm.nextHandlers, // 监听办理对象 多个办理对象自动发起会签
  859. (val) => {
  860. state.ruleForm.isStartCountersign = val.length > 1;
  861. }
  862. );
  863. const countersignDisabled = computed(() => {
  864. // 是否可以发起会签
  865. return state.ruleForm.nextHandlers.length <= 1;
  866. });
  867. // 是否发起会签
  868. const changeStartCountersign = (val: boolean) => {
  869. if (!val) {
  870. // 如果不能会签清空办理对象
  871. state.ruleForm.nextHandlers = [];
  872. ruleFormRef.value?.resetFields('nextHandlers');
  873. }
  874. };
  875. // 是否展示办理对象 (结束节点不展示: next.stepType===2 表示为结束节点,下一环节为派单组时 next.businessType === 1,办理对象下拉框隐藏:AppConfigInfo.value.isAverageSendOrder= true 表示开启了平均派单 )
  876. const showHandlers = computed(() => {
  877. const next = state.nextStepOptions.find((item: any) => item.key === state.ruleForm.nextStepCode);
  878. const isAverageSendOrder = AppConfigInfo.value.isAverageSendOrder && next?.businessType === 1; // 开启平均派单并且下一个环节是派单组 !isAverageSendOrder
  879. if (!next) return true;
  880. return next?.stepType !== 2;
  881. });
  882. // 是否展示部门处理结果 ( 选择结束节点时并且当前操作人不是中心时,显示部门处理结果 )
  883. const showResult = computed(() => {
  884. const next = state.nextStepOptions.find((item: any) => item.key === state.ruleForm.nextStepCode);
  885. return next?.stepType === 2 && !userInfos.value.isCenter;
  886. });
  887. // 是否展示警情退回 (选择结束节点时并且工单来源是110时,显示警情退回)
  888. const showPoliceReturn = computed(() => {
  889. const next = state.nextStepOptions.find((item: any) => item.key === state.ruleForm.nextStepCode);
  890. return next?.stepType === 2 && state.orderDetail?.source === 200;
  891. });
  892. // 是否是汇总节点(汇总需要填入其他参数)并且是工单办理
  893. const inputRealHandler = computed(() => {
  894. const next = state.nextStepOptions.find((item: any) => item.key === state.ruleForm.nextStepCode);
  895. return next?.inputRealHandler && handelArr.includes(state.processType);
  896. });
  897. // 是否显示快捷派单
  898. const showFastSendOrder = computed(() => {
  899. const next = state.nextStepOptions.find((item: any) => item.key === state.ruleForm.nextStepCode);
  900. if (!next) return false;
  901. return next?.recommendOrgName && next?.recommendOrgId;
  902. });
  903. // 快速派单
  904. const fastSendOrder = () => {
  905. if (!fastStepCode.value) return;
  906. // 如果办理对象中没有推荐派单的对象就添加
  907. if (!state.ruleForm.nextHandlers.find((item: any) => item.key === fastStepCode.value)) {
  908. const next = state.handlerOptions.find((item: any) => item.value.key === fastStepCode.value);
  909. if (next) state.ruleForm.nextHandlers = [...state.ruleForm.nextHandlers, next.value];
  910. }
  911. };
  912. // 是否展示办理时限 flowDirection 并且是工单办理
  913. const flowDirection = computed(() => {
  914. const next = state.nextStepOptions.find((item: any) => item.key === state.ruleForm.nextStepCode);
  915. if (!next) return false;
  916. return [0, 1].includes(next.flowDirection) && handelArr.includes(state.processType);
  917. });
  918. // 是否展示备注输入框
  919. const showRemarkTextarea = computed(() => {
  920. return ['工单受理', '工单办理'].includes(state.processType);
  921. });
  922. // 计算工单期满时间
  923. watch(
  924. () => flowDirection.value,
  925. (val) => {
  926. if (val) {
  927. const next = state.nextStepOptions.find((item: any) => item.key === state.ruleForm.nextStepCode);
  928. state.ruleForm.flowDirection = next.flowDirection;
  929. orderTimeConfig({ flowDirection: next.flowDirection, acceptTypeCode: state.orderDetail.acceptTypeCode }).then((res: any) => {
  930. state.ruleForm.timeLimit = res.result.count ?? null; // 办理时限
  931. state.ruleForm.timeLimitUnit = res.result.timeType ?? ''; // 办理时限单位
  932. computeTimeNext();
  933. });
  934. }
  935. }
  936. );
  937. // 办理计算工单期满时间
  938. const computeTimeNext = debounce(() => {
  939. if (!state.ruleForm.timeLimit || !state.ruleForm.timeLimitUnit) return;
  940. let request = {
  941. delayNum: state.ruleForm.timeLimit,
  942. delayUnit: state.ruleForm.timeLimitUnit,
  943. beginTime: state.ruleForm.expiredTime,
  944. };
  945. state.loading = true;
  946. delayCalcEndTime(request)
  947. .then((res: any) => {
  948. state.ruleForm.endTime = formatDate(res.result.endTime,'YYYY-MM-DD HH:mm:ss');
  949. state.loading = false;
  950. })
  951. .catch(() => {
  952. state.delayForm.endTime = '';
  953. state.loading = false;
  954. });
  955. }, 300);
  956. // 选择办理对象
  957. const selectHandlers = () => {
  958. ruleFormRef.value?.resetFields('nextMainHandler');
  959. if (state.ruleForm.nextHandlers.length > 1) {
  960. // 多个办理对象 主办
  961. state.ruleForm.nextMainHandler = state.ruleForm.nextHandlers[0].key;
  962. // AppConfigInfo.value.noSignOrgCode 对应的办理对象不能参与会签
  963. const isProvince12345 = state.ruleForm.nextHandlers.find((item: any) => AppConfigInfo.value.noSignOrgCode.includes(item.key));
  964. if (isProvince12345) {
  965. // 如果选择了省12345平台或者省12345交办就提示不能参与会签 并且从选择中移除
  966. ElMessage({
  967. message: '省12345平台和省12345交办不能参与会签',
  968. grouping: true,
  969. });
  970. state.ruleForm.nextHandlers = state.ruleForm.nextHandlers.filter((item: any) => !AppConfigInfo.value.noSignOrgCode.includes(item.key));
  971. }
  972. }
  973. if (state.ruleForm.nextHandlers.length <= 1) {
  974. // 如果只有一个办理对象就不需要发起会签
  975. state.ruleForm.isStartCountersign = false;
  976. }
  977. };
  978. // 是否展示主办
  979. const showMainHandler = computed(() => {
  980. return state.ruleForm.nextHandlers.length > 1 && isMainHandlerShow.value;
  981. });
  982. // 主办从办理对象中选择
  983. state.handlerMainOptions = computed(() => {
  984. return state.ruleForm.nextHandlers;
  985. });
  986. // 设置抽屉
  987. const dialogRef = ref<RefType>();
  988. const mouseup = () => {
  989. state.transform = dialogRef.value.dialogContentRef.$el.style.transform;
  990. };
  991. // 关闭弹窗
  992. const closeDialog = () => {
  993. state.dialogVisible = false;
  994. };
  995. // 重置表单方法
  996. const restForm = (formEl: FormInstance | undefined) => {
  997. if (!formEl) return;
  998. state.ruleForm.opinion = '';
  999. state.delayForm.endTime = '';
  1000. formEl.resetFields();
  1001. formEl.clearValidate();
  1002. };
  1003. // 选择常用意见 填入填写框 办理
  1004. const chooseAdvice = (item: any) => {
  1005. state.ruleForm.opinion += item.content;
  1006. };
  1007. // 选择常用意见 填入填写框 延期
  1008. const chooseAdviceDelay = (item: any) => {
  1009. state.delayForm.content += item.content;
  1010. };
  1011. // 选择常用意见 填入填写框 甄别
  1012. const chooseAdviceDiscern = (item: any) => {
  1013. state.discernForm.content += item.content;
  1014. };
  1015. // 选择常用意见 填入填写框 终止
  1016. const chooseAdviceTerminate = (item: any) => {
  1017. state.terminateForm.content += item.content;
  1018. };
  1019. const afterSubmit = (emitType?: 'orderProcessSuccess' | 'orderProcessFailed', showMessage?: boolean, message?: string) => {
  1020. state.loading = false;
  1021. closeDialog();
  1022. const msg = message ?? '操作成功';
  1023. if (showMessage) ElMessage.success(msg);
  1024. if (emitType) emit(emitType);
  1025. };
  1026. const close = () => {
  1027. restForm(ruleFormRef.value);
  1028. restForm(delayFormRef.value);
  1029. restForm(discernFormRef.value);
  1030. restForm(terminateFormRef.value);
  1031. restForm(redoFormRef.value);
  1032. };
  1033. // 办理
  1034. const handleFiles = ref<EmptyArrayType>([]); // 流程附件
  1035. const handleFilesDelay = ref<EmptyArrayType>([]); // 延期附件
  1036. const handleFilesDiscern = ref<EmptyArrayType>([]); // 甄别附件
  1037. const handleFilesTerminate = ref<EmptyArrayType>([]); // 终止附件
  1038. const onSubmit = (formEl: FormInstance | undefined) => {
  1039. if (!formEl) return;
  1040. formEl.validate((valid: boolean) => {
  1041. if (!valid) return;
  1042. state.loading = true;
  1043. let submitObj = other.deepClone(state.ruleForm);
  1044. if (submitObj.nextHandlers && submitObj.nextHandlers.length) {
  1045. if (submitObj.nextHandlers.length === 1) {
  1046. submitObj.nextMainHandler = submitObj.nextHandlers[0].key;
  1047. }
  1048. }
  1049. if (!flowDirection.value) {
  1050. // 需要填写办理时限
  1051. Reflect.deleteProperty(submitObj, 'timeLimit');
  1052. Reflect.deleteProperty(submitObj, 'timeLimitUnit');
  1053. } else {
  1054. submitObj.external = {
  1055. timeLimit: state.ruleForm.timeLimit,
  1056. timeLimitUnit: state.ruleForm.timeLimitUnit,
  1057. };
  1058. }
  1059. Reflect.deleteProperty(submitObj, 'isPoliceReturn');
  1060. Reflect.deleteProperty(submitObj, 'isResolved');
  1061. submitObj.external = {
  1062. isPoliceReturn: state.ruleForm.isPoliceReturn,
  1063. isResolved: state.ruleForm.isResolved,
  1064. };
  1065. // submitObj.stepExpiredTime = submitObj.expiredTime; //节点过期时间
  1066. switch (state.processType) {
  1067. case '工单受理':
  1068. const request = {
  1069. data: { orderId: state.orderDetail.id, ...submitObj },
  1070. workflow: { ...submitObj, files: handleFiles.value },
  1071. };
  1072. orderStartFlow(request)
  1073. .then(() => {
  1074. afterSubmit('orderProcessSuccess', true);
  1075. })
  1076. .catch(() => {
  1077. afterSubmit('orderProcessFailed');
  1078. });
  1079. break;
  1080. case '工单撤回':
  1081. workflowRecall({ ...submitObj, files: handleFiles.value })
  1082. .then(() => {
  1083. afterSubmit('orderProcessSuccess', true);
  1084. })
  1085. .catch(() => {
  1086. afterSubmit('orderProcessFailed');
  1087. });
  1088. break;
  1089. case '延期申请':
  1090. const requestDelay = {
  1091. data: {
  1092. orderId: state.orderDetail.id,
  1093. delayNum: state.delayForm.timeLimitCount,
  1094. delayUnit: state.delayForm.timeLimitUnit,
  1095. delayReason: state.delayForm.content,
  1096. files: handleFilesDelay.value,
  1097. },
  1098. workflow: {
  1099. ...submitObj,
  1100. opinion: state.delayForm.content,
  1101. files: handleFilesDelay.value,
  1102. },
  1103. };
  1104. delayApply(requestDelay)
  1105. .then(() => {
  1106. afterSubmit('orderProcessSuccess', true, '延期申请成功');
  1107. })
  1108. .catch(() => {
  1109. afterSubmit('orderProcessFailed');
  1110. });
  1111. break;
  1112. case '延期退回':
  1113. workflowPrevious({ ...submitObj, files: handleFiles.value })
  1114. .then(() => {
  1115. afterSubmit('orderProcessSuccess', true);
  1116. })
  1117. .catch(() => {
  1118. afterSubmit('orderProcessFailed');
  1119. });
  1120. break;
  1121. case '延期审批':
  1122. if (state.ruleForm.isPass) {
  1123. // 审批通过 下一步
  1124. workflowNext({ ...submitObj, reviewResult: 1, files: handleFiles.value })
  1125. .then(() => {
  1126. afterSubmit('orderProcessSuccess', true);
  1127. })
  1128. .catch(() => {
  1129. afterSubmit('orderProcessFailed');
  1130. });
  1131. } else {
  1132. // 审批拒绝
  1133. const requestDelayAudit = {
  1134. opinion: state.ruleForm.opinion,
  1135. workflowId: state.workflowId,
  1136. files: handleFiles.value,
  1137. stepId: state.ruleForm.stepId,
  1138. };
  1139. workflowReject(requestDelayAudit)
  1140. .then(() => {
  1141. afterSubmit('orderProcessSuccess', true);
  1142. })
  1143. .catch(() => {
  1144. afterSubmit('orderProcessFailed');
  1145. });
  1146. }
  1147. break;
  1148. case '甄别申请':
  1149. const requestDiscern = {
  1150. data: {
  1151. no: state.orderDetail.no,
  1152. visitId: state.orderDetail.visitId,
  1153. visitDetailId: state.orderDetail.visitDetailId,
  1154. orderId: state.orderDetail.id,
  1155. typeDicId: state.discernForm.type.dicDataValue,
  1156. typeDicName: state.discernForm.type.dicDataName,
  1157. content: state.discernForm.content,
  1158. screenType: screenType.value,
  1159. files: handleFilesDiscern.value,
  1160. },
  1161. workflow: { ...submitObj, files: handleFilesDiscern.value, opinion: state.discernForm.content },
  1162. };
  1163. discernApply(requestDiscern)
  1164. .then(() => {
  1165. afterSubmit('orderProcessSuccess', true, '甄别申请成功');
  1166. })
  1167. .catch(() => {
  1168. afterSubmit('orderProcessFailed');
  1169. });
  1170. break;
  1171. case '甄别退回':
  1172. workflowPrevious({ ...submitObj, files: handleFiles.value })
  1173. .then(() => {
  1174. afterSubmit('orderProcessSuccess', true);
  1175. })
  1176. .catch(() => {
  1177. afterSubmit('orderProcessFailed');
  1178. });
  1179. break;
  1180. case '甄别审批':
  1181. if (state.ruleForm.isPass) {
  1182. // 审批通过 下一步
  1183. workflowNext({ ...submitObj, reviewResult: 1, files: handleFiles.value })
  1184. .then(() => {
  1185. afterSubmit('orderProcessSuccess', true);
  1186. })
  1187. .catch(() => {
  1188. afterSubmit('orderProcessFailed');
  1189. });
  1190. } else {
  1191. // 审批拒绝
  1192. const requestDiscernAudit = {
  1193. opinion: state.ruleForm.opinion,
  1194. workflowId: state.workflowId,
  1195. files: handleFiles.value,
  1196. stepId: state.ruleForm.stepId,
  1197. };
  1198. workflowReject(requestDiscernAudit)
  1199. .then(() => {
  1200. afterSubmit('orderProcessSuccess', true);
  1201. })
  1202. .catch(() => {
  1203. afterSubmit('orderProcessFailed');
  1204. });
  1205. }
  1206. break;
  1207. case '终止申请':
  1208. const requestTerminate = {
  1209. data: {
  1210. no: state.orderDetail.no,
  1211. orderId: state.orderDetail.id,
  1212. content: state.terminateForm.content,
  1213. files: handleFilesTerminate.value,
  1214. },
  1215. workflow: { ...submitObj, files: handleFilesTerminate.value, opinion: state.terminateForm.content },
  1216. };
  1217. terminateStartFlow(requestTerminate)
  1218. .then(() => {
  1219. afterSubmit('orderProcessSuccess', true, '终止申请成功');
  1220. })
  1221. .catch(() => {
  1222. afterSubmit('orderProcessFailed');
  1223. });
  1224. break;
  1225. case '终止审批':
  1226. if (state.ruleForm.isPass) {
  1227. // 审批通过 下一步
  1228. workflowNext({ ...submitObj, reviewResult: 1, files: handleFiles.value })
  1229. .then(() => {
  1230. afterSubmit('orderProcessSuccess', true);
  1231. })
  1232. .catch(() => {
  1233. afterSubmit('orderProcessFailed');
  1234. });
  1235. } else {
  1236. // 审批拒绝
  1237. const requestTerminateAudit = {
  1238. opinion: state.ruleForm.opinion,
  1239. workflowId: state.workflowId,
  1240. files: handleFiles.value,
  1241. stepId: state.ruleForm.stepId,
  1242. };
  1243. workflowReject(requestTerminateAudit)
  1244. .then(() => {
  1245. afterSubmit('orderProcessSuccess', true);
  1246. })
  1247. .catch(() => {
  1248. afterSubmit('orderProcessFailed');
  1249. });
  1250. }
  1251. break;
  1252. case '终止退回':
  1253. workflowPrevious({ ...submitObj, files: handleFiles.value })
  1254. .then(() => {
  1255. afterSubmit('orderProcessSuccess', true);
  1256. })
  1257. .catch(() => {
  1258. afterSubmit('orderProcessFailed');
  1259. });
  1260. break;
  1261. case '工单退回':
  1262. orderPrevious({ ...submitObj, files: handleFiles.value })
  1263. .then(() => {
  1264. afterSubmit('orderProcessSuccess', true, '退回申请成功');
  1265. })
  1266. .catch(() => {
  1267. afterSubmit('orderProcessFailed');
  1268. });
  1269. break;
  1270. case '工单办理': // 工单办理流程
  1271. case '工单代办': // 工单代办流程
  1272. const requestHandle = {
  1273. data: { orderId: state.orderDetail.id, ...submitObj },
  1274. workflow: { ...submitObj, files: handleFiles.value },
  1275. };
  1276. orderHandle(requestHandle)
  1277. .then(() => {
  1278. afterSubmit('orderProcessSuccess', true);
  1279. })
  1280. .catch(() => {
  1281. afterSubmit('orderProcessFailed');
  1282. });
  1283. break;
  1284. case '新增知识':
  1285. const KnowledgeAddRequest = {
  1286. data: { ...state.orderDetail },
  1287. workflow: { ...submitObj, files: handleFiles.value },
  1288. };
  1289. KnowledgeAdd(KnowledgeAddRequest)
  1290. .then(() => {
  1291. afterSubmit('orderProcessSuccess', true, '新增知识成功');
  1292. })
  1293. .catch(() => {
  1294. afterSubmit('orderProcessFailed');
  1295. });
  1296. break;
  1297. case '知识审批':
  1298. if (state.ruleForm.isPass) {
  1299. // 审批通过 下一步
  1300. workflowNext({ ...submitObj, reviewResult: 1, files: handleFiles.value })
  1301. .then(() => {
  1302. afterSubmit('orderProcessSuccess', true);
  1303. })
  1304. .catch(() => {
  1305. afterSubmit('orderProcessFailed');
  1306. });
  1307. } else {
  1308. // 审批拒绝
  1309. const requestDiscernAudit = {
  1310. opinion: state.ruleForm.opinion,
  1311. workflowId: state.workflowId,
  1312. files: handleFiles.value,
  1313. stepId: state.ruleForm.stepId,
  1314. };
  1315. workflowReject(requestDiscernAudit)
  1316. .then(() => {
  1317. afterSubmit('orderProcessSuccess', true);
  1318. })
  1319. .catch(() => {
  1320. afterSubmit('orderProcessFailed');
  1321. });
  1322. }
  1323. break;
  1324. case '更新新增知识':
  1325. const KnowledgeAddUpdateRequest = {
  1326. data: { ...state.orderDetail },
  1327. workflow: { ...submitObj, files: handleFiles.value },
  1328. };
  1329. KnowledgeUpdate(KnowledgeAddUpdateRequest)
  1330. .then(() => {
  1331. afterSubmit('orderProcessSuccess', true);
  1332. })
  1333. .catch(() => {
  1334. afterSubmit('orderProcessFailed');
  1335. });
  1336. break;
  1337. case '更新知识':
  1338. const KnowledgeUpdateRequest = {
  1339. data: { ...state.orderDetail },
  1340. workflow: { ...submitObj, files: handleFiles.value },
  1341. };
  1342. KnowledgeUpdate(KnowledgeUpdateRequest)
  1343. .then(() => {
  1344. afterSubmit('orderProcessSuccess', true);
  1345. })
  1346. .catch(() => {
  1347. afterSubmit('orderProcessFailed');
  1348. });
  1349. break;
  1350. case '删除知识':
  1351. const KnowledgeRemoveRequest = {
  1352. data: { ...state.orderDetail },
  1353. workflow: { ...submitObj, files: handleFiles.value },
  1354. };
  1355. KnowledgeDel(KnowledgeRemoveRequest)
  1356. .then(() => {
  1357. afterSubmit('orderProcessSuccess', true, '删除知识申请成功');
  1358. })
  1359. .catch(() => {
  1360. afterSubmit('orderProcessFailed');
  1361. });
  1362. break;
  1363. case '知识下架':
  1364. const KnowledgeOffShelfRequest = {
  1365. data: { ...state.orderDetail },
  1366. workflow: { ...submitObj, files: handleFiles.value },
  1367. };
  1368. KnowledgeOffShelf(KnowledgeOffShelfRequest)
  1369. .then(() => {
  1370. afterSubmit('orderProcessSuccess', true, '下架知识申请成功');
  1371. })
  1372. .catch(() => {
  1373. afterSubmit('orderProcessFailed');
  1374. });
  1375. break;
  1376. default: // 默认工单办理
  1377. const requestDefault = {
  1378. data: { orderId: state.orderDetail.id, ...submitObj },
  1379. workflow: { ...submitObj, files: handleFiles.value },
  1380. };
  1381. orderHandle(requestDefault)
  1382. .then(() => {
  1383. afterSubmit('orderProcessSuccess', true);
  1384. })
  1385. .catch(() => {
  1386. afterSubmit('orderProcessFailed');
  1387. });
  1388. break;
  1389. }
  1390. });
  1391. };
  1392. // 临时保存
  1393. const handleTempSave = () => {
  1394. ruleFormRef.value
  1395. .validateField('opinion')
  1396. .then(() => {
  1397. state.loading = true;
  1398. orderProcessTempSave({ orderId: state.orderDetail.id, opinion: state.ruleForm.opinion })
  1399. .then(() => {
  1400. state.loading = false;
  1401. ElMessage.success('临时保存成功');
  1402. })
  1403. .catch((err) => {
  1404. state.loading = false;
  1405. console.log(err);
  1406. });
  1407. })
  1408. .catch(() => {});
  1409. };
  1410. // 暴露变量
  1411. defineExpose({
  1412. openDialog,
  1413. closeDialog,
  1414. });
  1415. </script>
  1416. <style lang="scss">
  1417. .modal_class {
  1418. pointer-events: none;
  1419. height: 100%;
  1420. }
  1421. .dialog_class {
  1422. pointer-events: auto;
  1423. flex-direction: column;
  1424. margin: 0 !important;
  1425. position: absolute;
  1426. top: 20%;
  1427. left: 25%;
  1428. }
  1429. </style>