index.vue 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292
  1. <template>
  2. <div class="order-add-container layout-padding">
  3. <el-row :gutter="10" class="h100">
  4. <!-- 左侧语音助手 -->
  5. <el-col :span="6" class="left-content mb20 h100">
  6. <el-scrollbar class="h100" noresize>
  7. <el-card shadow="never">
  8. <div class="flex-center-between pb10">
  9. <p class="border-title mb10">语音助手</p>
  10. <el-radio-group v-model="voiceType" @change="changeVoiceType" size="small">
  11. <el-radio-button label="全部" />
  12. <el-radio-button label="市民" />
  13. <el-radio-button label="坐席" />
  14. </el-radio-group>
  15. </div>
  16. <voice-assistant @orderOverwrite="orderOverwrite" ref="voiceAssistantRef" />
  17. </el-card>
  18. <el-card shadow="never">
  19. <el-tabs v-model="leftTopActive" @tab-change="handleLeftTop" stretch>
  20. <el-tab-pane label="实时质检" name="realtime">
  21. <real-time-quality />
  22. </el-tab-pane>
  23. <el-tab-pane label="工单小结" name="summary">
  24. <call-summary ref="callSummaryRef" @orderOverwrite="orderOverwrite" />
  25. </el-tab-pane>
  26. </el-tabs>
  27. </el-card>
  28. </el-scrollbar>
  29. </el-col>
  30. <!-- 中间工单信息 -->
  31. <el-col :span="12" class="left-content mb20 h100" v-loading="state.formLoading">
  32. <el-scrollbar class="h100" noresize>
  33. <el-card shadow="never">
  34. <el-form :model="state.ruleForm" ref="ruleFormRef" label-width="110px" label-position="right" scroll-to-error>
  35. <p class="border-title mb10">来电信息</p>
  36. <el-row :gutter="20">
  37. <!-- 来源渠道 -->
  38. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  39. <!-- 手动创建 -->
  40. <template v-if="state.createBy === 'manual'">
  41. <el-form-item label="来源渠道" prop="channel" :rules="[{ required: true, message: '请选择来源渠道', trigger: 'change' }]">
  42. <el-select
  43. v-model="state.ruleForm.channel"
  44. placeholder="请选择来源渠道"
  45. class="w100"
  46. clearable
  47. value-key="dicDataValue"
  48. @change="
  49. (val) => {
  50. ruleFormRef.resetFields('fromPhone');
  51. state.ruleForm.fromPhone = null;
  52. state.ruleForm.sourceChannel = val?.dicDataName ?? null;
  53. state.ruleForm.sourceChannelCode = val?.dicDataValue ?? null;
  54. }
  55. "
  56. >
  57. <el-option v-for="item in state.channelOptions" :value="item" :key="item.dicDataValue" :label="item.dicDataName" />
  58. </el-select>
  59. </el-form-item>
  60. </template>
  61. <!-- 来电弹单 -->
  62. <template v-if="state.createBy === 'tel'">
  63. <el-form-item label="来源渠道" prop="channel">
  64. <el-select v-model="state.ruleForm.channel" placeholder="请选择来源渠道" class="w100" value-key="dicDataValue" disabled>
  65. <el-option v-for="item in state.channelOptions" :value="item" :key="item.dicDataValue" :label="item.dicDataName" />
  66. </el-select>
  67. </el-form-item>
  68. </template>
  69. <!-- 互联网来信 -->
  70. <template v-if="state.createBy === 'letter'">
  71. <el-form-item label="来源渠道" prop="channel">
  72. 互联网来信
  73. <span>[{{ state.ruleForm.channel }}]</span>
  74. </el-form-item>
  75. </template>
  76. </el-col>
  77. <!-- 转接来源 -->
  78. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  79. <!-- 手动创建 -->
  80. <template v-if="state.createBy === 'manual'">
  81. <el-form-item label="转接来源" prop="transferPhone"> 暂无 </el-form-item>
  82. </template>
  83. <!-- 来电弹单 -->
  84. <template v-if="state.createBy === 'tel'">
  85. <el-form-item label="转接来源" prop="transferPhone">
  86. <span>[{{ state.ruleForm.transferPhone }}]</span>
  87. </el-form-item>
  88. </template>
  89. <!-- 互联网来信 -->
  90. <template v-if="state.createBy === 'letter'">
  91. <el-form-item label="转接来源" prop="transferPhone">
  92. <span>[{{ state.ruleForm.transferPhone }}]</span>
  93. </el-form-item>
  94. </template>
  95. </el-col>
  96. <!-- 来电号码 -->
  97. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" v-if="state.ruleForm.sourceChannelCode === 'RGDH'">
  98. <!-- 手动创建 -->
  99. <template v-if="state.createBy === 'manual'">
  100. <el-form-item label="来电号码" prop="fromPhone" :rules="[{ required: true, message: '请填写来电号码', trigger: 'blur' }]">
  101. <el-input v-model="state.ruleForm.fromPhone" placeholder="请填写来电号码" clearable> </el-input>
  102. </el-form-item>
  103. </template>
  104. <!-- 来电弹单 -->
  105. <template v-if="state.createBy === 'tel'">
  106. <el-form-item label="来电号码" prop="fromPhone">
  107. <el-input v-model="state.ruleForm.fromPhone" placeholder="请填写来电号码" disabled> </el-input>
  108. </el-form-item>
  109. </template>
  110. <!-- 互联网来信 -->
  111. <template v-if="state.createBy === 'letter'">
  112. <el-form-item label="来电号码">
  113. <span>[{{ state.ruleForm.fromPhone }}]</span>
  114. </el-form-item>
  115. </template>
  116. </el-col>
  117. <!-- 服务坐席 -->
  118. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  119. <el-form-item label="服务坐席">
  120. <!-- 手动创建 -->
  121. <template v-if="state.createBy === 'manual'">
  122. <span>{{ state.ruleForm.acceptorName }}</span>
  123. </template>
  124. <!-- 来电弹单 -->
  125. <template v-if="state.createBy === 'tel'">
  126. <span>{{ state.ruleForm.acceptorName }}</span>
  127. </template>
  128. <!-- 互联网来信 -->
  129. <template v-if="state.createBy === 'letter'">
  130. <span>[{{ telStatusInfo.telsNo }}]</span>
  131. </template>
  132. </el-form-item>
  133. </el-col>
  134. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  135. <el-form-item label="来电人姓名" prop="fromName" :rules="[{ required: true, message: '请填写来电人姓名', trigger: 'blur' }]">
  136. <el-row :gutter="10">
  137. <el-col :xs="24" :sm="24" :md="24" :lg="18" :xl="18">
  138. <el-input v-model="state.ruleForm.fromName" placeholder="请填写来电人姓名" clearable @input="inputName"> </el-input>
  139. </el-col>
  140. <el-col :xs="24" :sm="24" :md="24" :lg="6" :xl="6">
  141. <el-checkbox v-model="state.ruleForm.isSecret" label="保密" />
  142. </el-col>
  143. </el-row>
  144. </el-form-item>
  145. </el-col>
  146. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  147. <el-form-item label="来电人性别" prop="fromGender" :rules="[{ required: true, message: '请选择来电人性别', trigger: 'change' }]">
  148. <el-radio-group v-model="state.ruleForm.fromGender">
  149. <el-radio :label="item.key" v-for="item in state.genderOptions" :key="item.key">{{ item.value }}</el-radio>
  150. </el-radio-group>
  151. </el-form-item>
  152. </el-col>
  153. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  154. <el-form-item label="来电人身份" prop="identityType" :rules="[{ required: true, message: '请选择来电人身份', trigger: 'change' }]">
  155. <el-radio-group v-model="state.ruleForm.identityType" @change="selectIdentity">
  156. <el-radio :label="item.key" v-for="item in state.identityTypeOptions" :key="item.key">{{ item.value }}</el-radio>
  157. </el-radio-group>
  158. </el-form-item>
  159. </el-col>
  160. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  161. <el-form-item label="证件类型" prop="licenceTypeObj" :rules="[{ required: false, message: '请选择证件类型', trigger: 'change' }]">
  162. <el-select
  163. v-model="state.ruleForm.licenceTypeObj"
  164. placeholder="请选择证件类型"
  165. class="w100"
  166. clearable
  167. value-key="dicDataValue"
  168. @change="(val:any) => {
  169. state.ruleForm.licenceType = val?.dicDataName ?? null;
  170. state.ruleForm.licenceTypeCode = val?.dicDataValue ?? null;
  171. }"
  172. >
  173. <el-option v-for="item in state.licenceTypeOptions" :key="item.dicDataValue" :label="item.dicDataName" :value="item" />
  174. </el-select>
  175. </el-form-item>
  176. </el-col>
  177. <!-- 若“证件类型”有值,则证件号码必填 -->
  178. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  179. <el-form-item
  180. label="证件号码"
  181. prop="licenceNo"
  182. :rules="[
  183. { required: state.ruleForm.licenceTypeCode, message: '请填写证件号码', trigger: 'blur' },
  184. {
  185. pattern: licenceNoPattern,
  186. message: '证件号码格式错误',
  187. trigger: 'blur',
  188. },
  189. ]"
  190. >
  191. <el-input v-model="state.ruleForm.licenceNo" placeholder="请填写证件号码" clearable> </el-input>
  192. </el-form-item>
  193. </el-col>
  194. <!-- <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  195. <el-form-item label="年龄段" prop="ageRangeObj" :rules="[{ required: false, message: '请选择年龄段', trigger: 'change' }]">
  196. <el-select
  197. v-model="state.ruleForm.ageRangeObj"
  198. placeholder="请选择年龄段"
  199. class="w100"
  200. clearable
  201. value-key="dicDataValue"
  202. @change="(val:any) => {
  203. state.ruleForm.ageRange = val?.dicDataName ?? null;
  204. state.ruleForm.ageRangeCode = val?.dicDataValue ?? null;
  205. }"
  206. >
  207. <el-option v-for="item in state.ageRangeOptions" :key="item.dicDataValue" :label="item.dicDataName" :value="item" />
  208. </el-select>
  209. </el-form-item>
  210. </el-col>-->
  211. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  212. <el-form-item label="联系电话" prop="contact" :rules="[{ required: true, message: '请填写联系电话', trigger: 'blur' }]">
  213. <el-row :gutter="9">
  214. <el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
  215. <el-input v-model="state.ruleForm.contact" placeholder="请填写联系电话" @blur="searchHistory" clearable> </el-input>
  216. </el-col>
  217. <el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
  218. <el-checkbox v-model="state.ruleForm.acceptSms" label="受理短信" />
  219. </el-col>
  220. </el-row>
  221. </el-form-item>
  222. </el-col>
  223. <!-- 当“来电/信人身份”为“企业”时必填 -->
  224. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  225. <el-form-item label="企业名称" prop="enterpriseName" :rules="[{ required: false, message: '请填写企业名称', trigger: 'blur' }]">
  226. <el-input v-model="state.ruleForm.enterpriseName" placeholder="请填写企业名称" clearable> </el-input>
  227. </el-form-item>
  228. </el-col>
  229. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  230. <el-form-item label="专班名称" prop="zhuanBanMingCheng" :rules="[{ required: false, message: '请填写专班名称', trigger: 'blur' }]">
  231. <el-input v-model="state.ruleForm.zhuanBanMingCheng" placeholder="请填写专班名称" clearable>
  232. <template #append>
  233. <el-button type="primary" @click="handleSelect"><SvgIcon name="ele-Search" class="mr4" /> 查询企业</el-button>
  234. </template>
  235. </el-input>
  236. </el-form-item>
  237. </el-col>
  238. </el-row>
  239. <p class="border-title mb10">诉求信息</p>
  240. <el-row>
  241. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="state.ruleForm.no">
  242. <el-form-item label="工单编码">
  243. {{ state.ruleForm.no }} <span v-if="state.ruleForm?.password">【{{ state.ruleForm.password }}】</span>
  244. </el-form-item>
  245. </el-col>
  246. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  247. <el-form-item label="拓展信息">
  248. <el-button @click="showExpandForm" :loading="extraLoading">
  249. <SvgIcon name="ele-CirclePlus" class="mr3" size="16px" /> 拓展信息
  250. </el-button>
  251. </el-form-item>
  252. </el-col>
  253. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  254. <el-form-item label="受理类型" prop="acceptTypeObj" :rules="[{ required: true, message: '请选择受理类型', trigger: 'change' }]">
  255. <el-select
  256. v-model="state.ruleForm.acceptTypeObj"
  257. placeholder="请选择受理类型"
  258. class="w100"
  259. value-key="dicDataValue"
  260. @change="
  261. (val) => {
  262. state.ruleForm.acceptType = val?.dicDataName ?? null;
  263. state.ruleForm.acceptTypeCode = val?.dicDataValue ?? null;
  264. }
  265. "
  266. >
  267. <el-option
  268. v-for="item in state.acceptTypeOptions"
  269. :key="item.dicDataValue"
  270. :disabled="item.disabled"
  271. :label="item.dicDataName"
  272. :value="item"
  273. />
  274. </el-select>
  275. </el-form-item>
  276. </el-col>
  277. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  278. <el-form-item
  279. label="重点关注事件"
  280. prop="focusOnEventsArr"
  281. :rules="[{ required: false, message: '请选择重点关注事件', trigger: 'change' }]"
  282. >
  283. <el-select
  284. v-model="state.ruleForm.focusOnEventsArr"
  285. placeholder="请选择重点关注事件"
  286. class="w100"
  287. multiple
  288. @change="changeFocusEvent"
  289. >
  290. <el-option v-for="item in state.focusOnEvents" :key="item.key" :label="item.value" :value="item.key" />
  291. </el-select>
  292. </el-form-item>
  293. </el-col>
  294. <!-- <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  295. <el-form-item label="紧急程度" prop="emergencyLevel" :rules="[{ required: true, message: '请选择紧急程度', trigger: 'change' }]">
  296. <el-select v-model="state.ruleForm.emergencyLevel" placeholder="请选择紧急程度" class="w100">
  297. <el-option v-for="item in state.emergencyLevelOptions" :key="item.key" :label="item.value" :value="item.key" />
  298. </el-select>
  299. </el-form-item>
  300. </el-col>-->
  301. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  302. <el-form-item label="推送分类" prop="pushTypeObj" :rules="[{ required: false, message: '请选择推送分类', trigger: 'change' }]">
  303. <el-select
  304. v-model="state.ruleForm.pushTypeObj"
  305. placeholder="请选择推送分类"
  306. class="w100"
  307. clearable
  308. value-key="dicDataValue"
  309. @change="(val:any) => {
  310. state.ruleForm.pushType = val?.dicDataName ?? null;
  311. state.ruleForm.pushTypeCode = val?.dicDataValue ?? null;
  312. }"
  313. >
  314. <el-option v-for="item in state.pushTypeOptions" :key="item.dicDataValue" :label="item.dicDataName" :value="item" />
  315. </el-select>
  316. </el-form-item>
  317. </el-col>
  318. <!-- 宜宾特殊需求,新增一个事件分类可以自行维护(辅助功能-事件分类管理) -->
  319. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="AppConfigInfo.isCustomEvent">
  320. <el-form-item label="事件分类" prop="eventCategoryId" :rules="[{ required: true, message: '请选择事件分类', trigger: 'change' }]">
  321. <event-select
  322. @choose="chooseEvent"
  323. v-model="state.ruleForm.eventCategoryId"
  324. :externalArr="state.eventCategoryExternal"
  325. class="w100"
  326. placeholder="请选择事件分类"
  327. clearable
  328. />
  329. </el-form-item>
  330. </el-col>
  331. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  332. <el-form-item label="热点分类" prop="hotspotId" :rules="[{ required: true, message: '请选择热点分类', trigger: 'change' }]">
  333. <hot-spot-select
  334. v-model="state.ruleForm.hotspotId"
  335. class="w100"
  336. :externalArr="state.hotspotExternal"
  337. @choose="chooseHotSpot"
  338. placeholder="请选择热点分类"
  339. clearable
  340. />
  341. </el-form-item>
  342. </el-col>
  343. <!-- <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  344. <el-form-item label="事发时间" prop="incidentTime" :rules="[{ required: false, message: '请选择事发时间', trigger: 'change' }]">
  345. <el-date-picker
  346. v-model="state.ruleForm.incidentTime"
  347. type="datetime"
  348. placeholder="请选择事发时间"
  349. value-format="YYYY-MM-DD[T]HH:mm:ss"
  350. class="w100"
  351. />
  352. </el-form-item>
  353. </el-col>
  354. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  355. <el-form-item label="事件目的" prop="incidentPurpose" :rules="[{ required: false, message: '请填写事件目的', trigger: 'blur' }]">
  356. <el-input v-model="state.ruleForm.incidentPurpose" placeholder="请填写事件目的" clearable> </el-input>
  357. </el-form-item>
  358. </el-col>-->
  359. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  360. <el-row :gutter="0">
  361. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  362. <el-form-item
  363. label="事发地址"
  364. prop="areaCode"
  365. :rules="[{ required: true, message: '请选择事发地址', trigger: 'change' }]"
  366. v-loading="addressLoading"
  367. >
  368. <el-cascader
  369. :options="state.areaOptions"
  370. filterable
  371. :props="{ value: 'id', label: 'areaName', emitPath: false, checkStrictly: true }"
  372. placeholder="请选择事发地址"
  373. class="w100"
  374. v-model="state.ruleForm.areaCode"
  375. ref="areaRef"
  376. @change="changeArea"
  377. >
  378. </el-cascader>
  379. </el-form-item>
  380. </el-col>
  381. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  382. <el-form-item
  383. label=""
  384. prop="street"
  385. :rules="[{ required: false, message: '请填写详细地址', trigger: 'blur' }]"
  386. label-width="10px"
  387. class="w100 flex"
  388. >
  389. <el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
  390. <el-input v-model="state.ruleForm.street" placeholder="请填写详细地址" clearable> </el-input>
  391. </el-col>
  392. <el-col :xs="24" :sm="24" :md="24" :lg="7" :xl="7" :offset="1">
  393. <el-button type="primary" link @click="selectLocation"><SvgIcon name="ele-Location" size="16px" /> 地图定位</el-button>
  394. </el-col>
  395. </el-form-item>
  396. </el-col>
  397. <div v-if="showRepeatEvent" class="color-danger mb10" style="margin-left: 110px">
  398. 【{{ state.ruleForm.address }}】下存在多起【{{ state.ruleForm.hotspotSpliceName }}】事件,点击前往查看或右侧添加重复性事件
  399. <el-button type="primary" link style="padding: 0 0 3px" @click="onRepeatEvent"> 查看详情</el-button>
  400. </div>
  401. </el-row>
  402. </el-col>
  403. <!-- 系统配置 可以配置是否开启重复工单 -->
  404. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="AppConfigInfo.isOpenRepeatedWorkOrders">
  405. <el-row>
  406. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  407. <el-form-item label="是否重复" prop="isRepeat" :rules="[{ required: true, message: '请选择是否重复', trigger: 'change' }]">
  408. <el-select v-model="state.ruleForm.isRepeat" placeholder="请选择是否重复" class="w100" @change="isRepeatChange">
  409. <el-option v-for="item in state.repeatOptions" :key="item.key" :label="item.value" :value="item.key" />
  410. </el-select>
  411. </el-form-item>
  412. </el-col>
  413. <!-- 必填,若“是否重复”为“是”,则展示重复件选择框 -->
  414. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" v-if="state.ruleForm.isRepeat === 'true'">
  415. <el-form-item
  416. label=""
  417. prop="duplicateTitle"
  418. label-width="10px"
  419. :rules="[{ required: true, message: '请选择重复件', trigger: 'change' }]"
  420. >
  421. <el-input v-model="state.ruleForm.duplicateTitle" placeholder="请选择重复件" readonly>
  422. <template #suffix>
  423. <el-button link type="danger" v-if="state.ruleForm.duplicateTitle" @click="clearRepeat" title="清除历史工单">
  424. <SvgIcon name="ele-Delete" size="16px" />
  425. </el-button>
  426. <el-button link type="primary" class="ml1" @click="selectRepeat" title="选择历史工单">
  427. <SvgIcon name="iconfont icon-tianjiatuozhanxinxi" size="18px" />
  428. </el-button>
  429. </template>
  430. </el-input>
  431. </el-form-item>
  432. </el-col>
  433. </el-row>
  434. </el-col>
  435. <!-- 宜宾特殊需求,可配置开关 是否开启是否市州互转 -->
  436. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" v-if="AppConfigInfo.isTranspondCity">
  437. <el-row>
  438. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12">
  439. <el-form-item
  440. label="是否市州互转"
  441. prop="transpond"
  442. :rules="[{ required: true, message: '请选择是否市州互转', trigger: 'change' }]"
  443. >
  444. <el-select v-model="state.ruleForm.transpond" placeholder="请选择是否市州互转" class="w100" @change="changeTranspond">
  445. <el-option :key="true" label="是" :value="true" />
  446. <el-option :key="false" label="否" :value="false" />
  447. </el-select>
  448. </el-form-item>
  449. </el-col>
  450. <!-- 必填,若“是否市州互转”为“是”,则展示选择市州选择框 -->
  451. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="12" v-if="state.ruleForm.transpond">
  452. <el-form-item
  453. label=""
  454. prop="transpondCityObj"
  455. label-width="10px"
  456. :rules="[{ required: true, message: '请选择互转市州', trigger: 'change' }]"
  457. >
  458. <el-select
  459. v-model="state.ruleForm.transpondCityObj"
  460. placeholder="请选择互转市州"
  461. class="w100"
  462. value-key="dicDataValue"
  463. @change="(val:any) => {
  464. state.ruleForm.transpondCityId = val?.id ?? null;
  465. state.ruleForm.transpondCityValue = val?.dicDataValue ?? null;
  466. state.ruleForm.transpondCityName = val?.dicDataName ?? null;
  467. }"
  468. >
  469. <el-option v-for="item in state.transpondCity" :key="item.dicDataValue" :label="item.dicDataName" :value="item" />
  470. </el-select>
  471. </el-form-item>
  472. </el-col>
  473. </el-row>
  474. </el-col>
  475. <!-- 宜宾特殊需求,可配置开关 -->
  476. <!-- <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  477. <el-form-item
  478. label="是否行政执法工单"
  479. label-width="140px"
  480. prop="isEnforcementOrder"
  481. :rules="[{ required: true, message: '请选择是否行政执法工单', trigger: 'change' }]"
  482. >
  483. <el-radio-group v-model="state.ruleForm.isEnforcementOrder">
  484. <el-radio :label="true">是</el-radio>
  485. <el-radio :label="false">否</el-radio>
  486. </el-radio-group>
  487. </el-form-item>
  488. </el-col>-->
  489. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  490. <el-form-item label="工单标题" prop="title" :rules="[{ required: true, message: '请填写工单标题', trigger: 'blur' }]">
  491. <el-input v-model="state.ruleForm.title" placeholder="请填写工单标题" clearable @input="inputTitle"> </el-input>
  492. </el-form-item>
  493. </el-col>
  494. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  495. <el-form-item label="受理内容" prop="content" :rules="[{ required: true, message: '请填写受理内容', trigger: 'blur' }]">
  496. <common-advice
  497. @chooseAdvice="chooseAdvice"
  498. v-model="state.ruleForm.content"
  499. placeholder="请填写受理内容"
  500. :loading="state.formLoading"
  501. :commonEnum="commonEnum.Seat"
  502. modal
  503. />
  504. </el-form-item>
  505. </el-col>
  506. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  507. <el-form-item label="附件" prop="files" :rules="[{ required: false, message: '请填写诉求内容', trigger: 'change' }]">
  508. <annex-list :businessId="state.orderId" classify="受理上传" v-model="state.ruleForm.files" v-model:format="filesFormat" />
  509. </el-form-item>
  510. </el-col>
  511. <el-col :xs="24" :sm="12" :md="24" :lg="24" :xl="24">
  512. <el-form-item>
  513. <el-button class="default-button" @click="onCancel"> 取消 </el-button>
  514. <el-button class="default-button" @click="save(ruleFormRef)" :loading="buttonLoading"> 保存 </el-button>
  515. <el-button type="primary" @click="submit(ruleFormRef)" :loading="buttonLoading" v-if="canHandle"> 办理 </el-button>
  516. </el-form-item>
  517. </el-col>
  518. </el-row>
  519. </el-form>
  520. </el-card>
  521. </el-scrollbar>
  522. </el-col>
  523. <!-- 右侧内容 -->
  524. <el-col :span="6" class="right-content h100">
  525. <el-scrollbar class="h100">
  526. <el-card shadow="never">
  527. <el-tabs v-model="rightActive" @tab-change="handleRight" stretch>
  528. <el-tab-pane label="历史工单" name="history">
  529. <history-order
  530. :ruleForm="state.ruleForm"
  531. :orderId="state.orderId"
  532. @handleSelectionChange="handleSelectionChange"
  533. ref="historyOrderRef"
  534. />
  535. </el-tab-pane>
  536. <el-tab-pane label="重复性事件" name="repeat">
  537. <repeat-event ref="repeatEventRef" @orderAddRepeat="orderAddRepeat" :repeatIds="state.ruleForm.repeatableEventDetails" />
  538. </el-tab-pane>
  539. <el-tab-pane label="知识库" name="knowledge">
  540. <Knowledge ref="knowledgeRef" />
  541. </el-tab-pane>
  542. </el-tabs>
  543. </el-card>
  544. <el-card shadow="never">
  545. <el-tabs v-model="rightBottomActive" @tab-change="handleRightBottom" stretch>
  546. <el-tab-pane label="话术导航" name="navigation">
  547. <script-navigation />
  548. </el-tab-pane>
  549. <el-tab-pane label="市民画像" name="draw">
  550. <citizen-portrait :orderInfo="state.ruleForm" ref="citizenPortraitRef" />
  551. </el-tab-pane>
  552. </el-tabs>
  553. </el-card>
  554. </el-scrollbar>
  555. </el-col>
  556. </el-row>
  557. <!-- 拓展表单 -->
  558. <expand-form ref="ExpandFormRef" @saveExpandForm="saveExpandForm" :orderDetail="state.ruleForm" :extra="extra" />
  559. <!-- 历史工单 -->
  560. <order-history ref="HistoryOrderRef" @saveSelect="saveSelect" />
  561. <!-- 流程审批 -->
  562. <process-audit ref="processAuditRef" @orderProcessSuccess="orderProcessSuccess" />
  563. <!-- 地图选点 -->
  564. <map-dialog ref="mapDialogRef" @confirm="selectMap" />
  565. <!-- 企业搜索 -->
  566. <company-search ref="companySearchRef" @selectCompany="selectCompany" />
  567. </div>
  568. </template>
  569. <script setup lang="ts" name="orderAccept">
  570. import { computed, defineAsyncComponent, onMounted, reactive, ref, watch } from 'vue';
  571. import type { FormInstance } from 'element-plus';
  572. import { ElMessage, ElMessageBox, ElNotification } from 'element-plus';
  573. import { storeToRefs } from 'pinia';
  574. import { useRoute, useRouter } from 'vue-router';
  575. import { useTelStatus } from '@/stores/telStatus';
  576. import { useAppConfig } from '@/stores/appConfig';
  577. import { throttle, transformFile } from '@/utils/tools';
  578. import { commonEnum } from '@/utils/constants';
  579. import { orderAdd, orderBaseDataAdd, orderBaseExt, orderDetail, orderEdit } from '@/api/business/order';
  580. import { useUserInfo } from '@/stores/userInfo';
  581. import { treeArea } from '@/api/auxiliary/area';
  582. import mittBus from '@/utils/mitt';
  583. import { orderRepeatEvent } from '@/api/business/repeatEvent';
  584. import { removeDuplicate } from '@/utils/arrayOperation';
  585. // 引入组件
  586. const VoiceAssistant = defineAsyncComponent(() => import('@/views/todo/seats/accept/Voice-assistant.vue')); // 语音助手
  587. const Knowledge = defineAsyncComponent(() => import('@/views/todo/seats/accept/Knowledge.vue')); // 知识库
  588. const HistoryOrder = defineAsyncComponent(() => import('@/views/todo/seats/accept/History.vue')); // 历史工单
  589. const RepeatEvent = defineAsyncComponent(() => import('@/views/todo/seats/accept/Repeat-event.vue')); // 重复事件
  590. const CitizenPortrait = defineAsyncComponent(() => import('@/views/todo/seats/accept/Citizen-portrait.vue')); // 市民坏画像
  591. const ExpandForm = defineAsyncComponent(() => import('@/views/todo/seats/accept/Expand-form.vue')); // 拓展表单
  592. const OrderHistory = defineAsyncComponent(() => import('@/views/business/order/components/Order-history.vue')); // 历史工单弹窗列表
  593. const CommonAdvice = defineAsyncComponent(() => import('@/components/CommonAdvice/index.vue')); // 常用意见
  594. const AnnexList = defineAsyncComponent(() => import('@/components/AnnexList/index.vue')); // 附件列表
  595. const ProcessAudit = defineAsyncComponent(() => import('@/components/ProcessAudit/index.vue')); // 流程审批
  596. const MapDialog = defineAsyncComponent(() => import('@/views/todo/seats/accept/Map-Dialog.vue')); // 地图定位
  597. const CompanySearch = defineAsyncComponent(() => import('@/views/todo/seats/accept/Company-search.vue')); // 企业搜索
  598. const HotSpotSelect = defineAsyncComponent(() => import('@/components/Hotspot/index.vue')); // 选择热点
  599. const EventSelect = defineAsyncComponent(() => import('@/components/Hotspot/event.vue')); // 选择事件
  600. const RealTimeQuality = defineAsyncComponent(() => import('@/views/todo/seats/accept/Real-time-quality.vue')); // 实时质检
  601. const ScriptNavigation = defineAsyncComponent(() => import('@/views/todo/seats/accept/Script-navigation.vue')); // 话术导航
  602. const CallSummary = defineAsyncComponent(() => import('@/views/todo/seats/accept/Call-summary.vue')); // 呼叫小结
  603. // 定义变量内容
  604. const state = reactive<any>({
  605. createBy: 'manual', // 工单创建方式 默认手动创建 tel:来电弹单 letter:互联网来信 默认表示手动创建
  606. ruleForm: {
  607. sourceChannel: null, // 来源频道
  608. sourceChannelCode: null, //来源频道code
  609. transferPhone: null, // 转接来源
  610. fromPhone: null, // 来电号码
  611. acceptorName: null, // 员工姓名
  612. acceptorStaffNo: null, // 员工工号
  613. fromName: null, // 来电人姓名
  614. fromGender: 1, // 来电人性别 默认先生
  615. identityType: 1, // 来电/信人身份 默认市民
  616. licenceType: null, // 证件类型
  617. licenceTypeCode: null, // 证件类型code
  618. licenceNo: null, // 证件号码
  619. ageRange: null, // 年龄段
  620. ageRangeCode: null, // 年龄段code
  621. contact: null, // 联系电话
  622. isSecret: false, // 是否保密 默认false
  623. acceptSms: false, // 是否接收短信 默认false
  624. enterpriseName: null, // 企业名称
  625. zhuanBanMingCheng: null, // 专班名称
  626. no: null, // 工单编码
  627. title: null, // 工单标题
  628. acceptType: null, // 受理类型
  629. acceptTypeCode: null, // 受理类型code
  630. emergencyLevel: 1, // 紧急程度 默认一般
  631. hotspotId: '', // 热点分类
  632. eventCategoryId: '', // 事件分类
  633. incidentTime: null, // 事发时间
  634. incidentPurpose: null, // 事件目的
  635. areaCode: '511500', // 区域编码
  636. city: '宜宾市', // 市
  637. street: null, // 街道
  638. isRepeat: 'false', // 是否重复工单 默认否
  639. pushType: null, // 推送类型
  640. pushTypeCode: null, // 推送类型code
  641. content: '', // 工单内容
  642. duplicateIds: [], //重复工单id
  643. duplicateTitle: null, // 重复工单标题
  644. callAddress: null, // 来电归属地
  645. repeatableEventDetails: [], //重复性事件
  646. orderExtension: null, // 拓展信息
  647. transpond: false, // 是否市州互转
  648. isEnforcementOrder: false, // 是否行政执法工单
  649. focusOnEventsArr: [], // 重点关注事项
  650. focusOnEvents: null, // 重点关注事项 字符串
  651. isFormalistWorkOrder: false, // 是否形式主义工单
  652. isSensitiveWorkOrders: false, // 是否敏感类工单
  653. isUrgent: false, // 是否紧急工单
  654. },
  655. formLoading: false, // 表单加载状态
  656. hotspotExternal: [], // 热点分类外部数据
  657. eventCategoryExternal: [], // 事件分类外部数据
  658. acceptTypeOptions: [], // 受理类型
  659. channelOptions: [], // 来源频道
  660. emergencyLevelOptions: [], // 紧急程度
  661. genderOptions: [], // 性别
  662. identityTypeOptions: [], //来电人身份
  663. licenceTypeOptions: [], // 证件类型
  664. ageRangeOptions: [], // 年龄段
  665. pushTypeOptions: [], //推送分类
  666. areaOptions: [], //省市区
  667. transpondCity: [],
  668. repeatOptions: [
  669. //是否重复
  670. {
  671. value: '是',
  672. key: 'true',
  673. },
  674. {
  675. value: '否',
  676. key: 'false',
  677. },
  678. ],
  679. focusOnEvents: [], // 重点关注事项
  680. orderId: null, // 工单id
  681. orgData: [],
  682. });
  683. const useTelStatusStore = useTelStatus(); // 来电弹屏
  684. const { telStatusInfo } = storeToRefs(useTelStatusStore); // 来电弹屏信息
  685. const storesUserInfo = useUserInfo(); // 用户信息
  686. const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
  687. const appConfigStore = useAppConfig();
  688. const { AppConfigInfo } = storeToRefs(appConfigStore); // 系统配置信息
  689. state.ruleForm.acceptorName = userInfos.value.name; // 员工姓名
  690. state.ruleForm.acceptorStaffNo = userInfos.value.staffNo; // 员工工号
  691. const route = useRoute(); // 路由
  692. const router = useRouter(); // 路由
  693. const voiceType = ref('全部');
  694. // 选择坐席还是市民通话内容
  695. const voiceAssistantRef = ref<RefType>();
  696. const changeVoiceType = () => {
  697. voiceAssistantRef.value.filterMessage(voiceType.value);
  698. };
  699. const leftTopActive = ref('realtime');
  700. // 切换工单小结和实时质检
  701. const callSummaryRef = ref<RefType>();
  702. const handleLeftTop = (val: string) => {
  703. if (val === 'summary') {
  704. setTimeout(() => {
  705. callSummaryRef.value.getRecognize();
  706. }, 300);
  707. }
  708. };
  709. // 选择企业
  710. const companySearchRef = ref<RefType>();
  711. const handleSelect = () => {
  712. companySearchRef.value.openDialog();
  713. };
  714. // 选择企业
  715. const selectCompany = (row: any) => {
  716. state.ruleForm.enterpriseName = row.enterpriseName;
  717. state.ruleForm.enterpriseCode = row.enterpriseCode;
  718. state.ruleForm.zhuanBanMingCheng = row.specialTeamName;
  719. state.ruleForm.zhuanBanCode = row.specialTeamCode;
  720. };
  721. // 证件号码验证
  722. const licenceNoPattern = computed(() => {
  723. switch (state.ruleForm.licenceTypeCode) {
  724. case '10': // 身份证
  725. return /^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/;
  726. default: //默认只允许数字字母
  727. return /^[A-Za-z0-9]+$/;
  728. }
  729. });
  730. // 选择事件分类
  731. const chooseEvent = (val: any) => {
  732. state.ruleForm.eventCategoryName = val?.eventName; // 事件分类名称
  733. state.ruleForm.eventCategorySpliceName = val?.eventFullName; // 事件分类拼接名称
  734. state.ruleForm.eventCategoryExternal = val?.externalArr?.join(',') ?? ''; // 事件分类id
  735. };
  736. // 选择热点分类
  737. const knowledgeRef = ref<RefType>();
  738. const chooseHotSpot = (val: any) => {
  739. state.ruleForm.hotspotSpliceName = val?.hotSpotFullName; // 热点分类拼接名称
  740. state.ruleForm.hotspotName = val?.hotSpotName; // 热点分类名称
  741. state.ruleForm.hotspotCode = val?.provinceCode; // 热点分类code
  742. state.ruleForm.hotspotExternal = val?.externalArr?.join(',') ?? ''; // 热点分类默认展开项
  743. rightActive.value = 'knowledge';
  744. knowledgeRef.value.querySearch(state.ruleForm.hotspotName);
  745. };
  746. // 获取事发地址
  747. const areaRef = ref<RefType>();
  748. const changeArea = () => {
  749. const currentNode = areaRef.value.getCheckedNodes();
  750. // 判断数组长度
  751. if (currentNode[0].pathLabels.length <= 4) {
  752. state.ruleForm.city = currentNode[0].pathLabels[0] ?? ''; // 市
  753. state.ruleForm.county = currentNode[0].pathLabels[1] ?? ''; // 区
  754. state.ruleForm.town = currentNode[0].pathLabels[2] ?? ''; // 地区
  755. } else {
  756. // 如果数组长度大于4
  757. state.ruleForm.city = currentNode[0].pathLabels[0] ?? ''; // 市
  758. state.ruleForm.county = currentNode[0].pathLabels[1] ?? ''; // 区
  759. state.ruleForm.town = currentNode[0].pathLabels[2] ?? ''; // 地区
  760. state.ruleForm.areaText = currentNode[0].pathLabels.slice(3).join('') ?? ''; // 地区
  761. console.log(state.ruleForm.areaText);
  762. }
  763. };
  764. // 根据热点和事发地址去查询重复性事件 是否展示重复性事件
  765. const repeatEventRef = ref<RefType>();
  766. const showRepeatEvent = ref<boolean>(false);
  767. const stopWatch = watch([() => state.ruleForm.hotspotSpliceName, () => state.ruleForm.address], (value) => {
  768. if (value[0] && value[1]) {
  769. orderRepeatEvent({ hotspotSpliceName: value[0], address: value[1] }).then((res: any) => {
  770. if (res.result) {
  771. showRepeatEvent.value = true;
  772. repeatEventRef.value.queryList();
  773. } else {
  774. showRepeatEvent.value = false;
  775. }
  776. });
  777. } else {
  778. showRepeatEvent.value = false;
  779. }
  780. });
  781. stopWatch();
  782. // 地图选点
  783. const mapDialogRef = ref<RefType>();
  784. const selectLocation = () => {
  785. const location = {
  786. longitude: state.ruleForm.longitude,
  787. latitude: state.ruleForm.latitude,
  788. adcode: state.ruleForm.areaCode,
  789. formattedAddress: state.ruleForm.street,
  790. };
  791. mapDialogRef.value.openDialog(location);
  792. };
  793. // 地图选点
  794. const ruleFormRef = ref<RefType>();
  795. const selectMap = (location: any) => {
  796. ruleFormRef.value.resetFields('areaCode');
  797. state.ruleForm.longitude = location.longitude;
  798. state.ruleForm.latitude = location.latitude;
  799. state.ruleForm.areaCode = location.adcode;
  800. state.ruleForm.street = location.formattedAddress;
  801. state.ruleForm.address = location.formattedAddress;
  802. };
  803. // 将当前工单添加到重复性事件中
  804. const repeatableEventDetails = ref<EmptyArrayType>([]);
  805. const orderAddRepeat = (row: any) => {
  806. if (route.params.id) {
  807. //编辑
  808. if (row.isDeleted) {
  809. //如果是添加
  810. repeatableEventDetails.value.push({
  811. repeatableId: row.id,
  812. isDeleted: false,
  813. });
  814. repeatableEventDetails.value = removeDuplicate([...repeatableEventDetails.value, ...state.ruleForm.repeatableEventDetails], 'repeatableId');
  815. } else {
  816. // 移除
  817. repeatableEventDetails.value = removeDuplicate([...repeatableEventDetails.value, ...state.ruleForm.repeatableEventDetails], 'repeatableId');
  818. repeatableEventDetails.value = repeatableEventDetails.value.map((item: any) => {
  819. if (item.repeatableId === row.id) {
  820. return {
  821. ...item,
  822. isDeleted: !item.isDeleted,
  823. };
  824. }
  825. return item;
  826. });
  827. }
  828. } else {
  829. // 添加
  830. if (row.isDeleted) {
  831. //如果是添加
  832. repeatableEventDetails.value.push({
  833. repeatableId: row.id,
  834. });
  835. repeatableEventDetails.value = removeDuplicate(repeatableEventDetails.value, 'repeatableId');
  836. } else {
  837. // 移除
  838. repeatableEventDetails.value = repeatableEventDetails.value.filter((item: any) => item.repeatableId !== row.id);
  839. }
  840. }
  841. };
  842. // 查看重复事件
  843. const onRepeatEvent = () => {
  844. rightActive.value = 'repeat';
  845. };
  846. // 选择是否重复
  847. const isRepeatChange = (val: string) => {
  848. if (val === 'false') clearRepeat();
  849. };
  850. // 清除重复件
  851. const clearRepeat = () => {
  852. ElMessageBox.confirm(`确认要清除选择的重复工单?`, '提示', {
  853. confirmButtonText: '确认',
  854. cancelButtonText: '取消',
  855. type: 'warning',
  856. draggable: true,
  857. cancelButtonClass: 'default-button',
  858. autofocus: false,
  859. })
  860. .then(() => {
  861. historyOrderRef.value.clearRepeat();
  862. setTimeout(() => {
  863. state.ruleForm.duplicateTitle = null;
  864. state.ruleForm.duplicateIds = [];
  865. }, 0);
  866. })
  867. .catch(() => {
  868. state.ruleForm.isRepeat = 'true';
  869. });
  870. };
  871. // 选择重复件
  872. const HistoryOrderRef = ref<RefType>();
  873. const selectRepeat = () => {
  874. HistoryOrderRef.value.openDialog(state.ruleForm);
  875. };
  876. // 弹窗确定选择重复件
  877. const saveSelect = (row: any) => {
  878. historyOrderRef.value.clearRepeat();
  879. state.ruleForm.duplicateIds = row.map((item: any) => item.id);
  880. state.ruleForm.duplicateTitle = '已选择';
  881. historyOrderRef.value.dialogConfirmRepeat(row);
  882. HistoryOrderRef.value.closeDialog();
  883. };
  884. // 选择是否市州互转
  885. const changeTranspond = (val: any) => {
  886. if (!val) {
  887. ElMessageBox.confirm(`确认要清除选择的互转市州?`, '提示', {
  888. confirmButtonText: '确认',
  889. cancelButtonText: '取消',
  890. type: 'warning',
  891. draggable: true,
  892. cancelButtonClass: 'default-button',
  893. autofocus: false,
  894. })
  895. .then(() => {
  896. setTimeout(() => {
  897. state.ruleForm.transpondCityValue = null;
  898. state.ruleForm.transpondCityName = null;
  899. state.ruleForm.transpondCityId = null;
  900. state.ruleForm.transpondCityObj = null;
  901. }, 0);
  902. })
  903. .catch(() => {
  904. state.ruleForm.transpond = true;
  905. });
  906. }
  907. };
  908. // 右侧选择历史工单
  909. const handleSelectionChange = (row: any) => {
  910. if (row && row.length) {
  911. state.ruleForm.duplicateIds = row.map((item: any) => item.id);
  912. state.ruleForm.duplicateTitle = '已选择';
  913. } else {
  914. state.ruleForm.duplicateIds = [];
  915. state.ruleForm.duplicateTitle = null;
  916. }
  917. };
  918. const historyOrderRef = ref<RefType>(); // 历史工单组件
  919. const citizenPortraitRef = ref<RefType>(); // 市民画像组件
  920. // 查询历史工单 和市民画像
  921. const searchHistory = () => {
  922. historyOrderRef.value.searchHistory();
  923. citizenPortraitRef.value.getCitizen();
  924. rightBottomActive.value = 'draw';
  925. };
  926. // 填写来电人姓名时根据填写内容自动选择性别
  927. const inputName = (val: string) => {
  928. if (val.includes('先生')) {
  929. state.ruleForm.fromGender = 1;
  930. } else if (val.includes('女士')) {
  931. state.ruleForm.fromGender = 0;
  932. }
  933. };
  934. // 填写标题时根据填写内容自动选择受理类型
  935. const inputTitle = (val: string) => {
  936. if (!state.ruleForm.acceptType) {
  937. const item = state.acceptTypeOptions.find((item: any) => item.dicDataName === val);
  938. if (item) {
  939. state.ruleForm.acceptTypeObj = item;
  940. state.ruleForm.acceptType = item.dicDataName;
  941. state.ruleForm.acceptTypeCode = item.dicDataValue;
  942. }
  943. }
  944. };
  945. const rightActive = ref<string>('history'); // 右侧顶部Tab
  946. const handleRight = () => {};
  947. const rightBottomActive = ref<string>('navigation'); // 右侧底部Tab
  948. const handleRightBottom = () => {};
  949. // 打开拓展表单
  950. const ExpandFormRef = ref<RefType>();
  951. const showExpandForm = () => {
  952. ExpandFormRef.value.openDialog();
  953. };
  954. // 拓展表单保存
  955. const saveExpandForm = (val: any) => {
  956. state.ruleForm.orderExtension = val;
  957. };
  958. // 选择重点关注事项
  959. const changeFocusEvent = (val: string[]) => {
  960. if (val.includes('0')) {
  961. // 紧急工单
  962. state.ruleForm.emergencyLevel = 2; // 紧急程度调整为紧急
  963. state.ruleForm.emergencyLevelText = '紧急';
  964. state.ruleForm.isUrgent = true; // 紧急工单
  965. } else {
  966. state.ruleForm.emergencyLevel = 1; // 默认一般
  967. state.ruleForm.emergencyLevelText = '一般';
  968. state.ruleForm.isUrgent = false;
  969. }
  970. state.ruleForm.isFormalistWorkOrder = val.includes('1'); // 是否形式主义工单
  971. state.ruleForm.isSensitiveWorkOrders = val.includes('3'); // 是否敏感类工单
  972. state.ruleForm.isEnforcementOrder = val.includes('2'); // 是否行政执法类工单
  973. state.ruleForm.focusOnEvents = val.join(',');
  974. console.log(
  975. `是否紧急工单:${val.includes('0')},是否行政执法类类工单:${val.includes('2')},是否形式主义工单:${val.includes('1')},是否敏感类工单:${val.includes(
  976. '3'
  977. )}`
  978. );
  979. };
  980. // 删除不必要的属性
  981. const deleteUnnecessaryProperties = (obj: any) => {
  982. const propertiesToDelete = ['ageRangeObj', 'pushTypeObj', 'licenceTypeObj', 'channel', 'acceptTypeObj', 'transpondCity'];
  983. propertiesToDelete.forEach((prop) => Reflect.deleteProperty(obj, prop));
  984. };
  985. const filesFormat = ref<EmptyArrayType>([]); // 附件列表格式化
  986. // 是否打开拓展表单
  987. const shouldOpenDialog = (obj: any) =>
  988. !ExpandFormRef.value.state.validated &&
  989. obj.orderExtension &&
  990. obj.orderExtension.orderTypeCode &&
  991. ['scjgjts,scjgjjb'].includes(obj.orderExtension.orderTypeCode);
  992. const buttonLoading = ref<boolean>(false);
  993. // 保存
  994. const save = throttle((formEl: FormInstance | undefined) => {
  995. if (!formEl) return;
  996. formEl.validate((valid: boolean) => {
  997. if (!valid) return;
  998. buttonLoading.value = true;
  999. let orderDetail = {
  1000. ...state.ruleForm,
  1001. repeatableEventDetails: repeatableEventDetails.value,
  1002. files: filesFormat.value,
  1003. };
  1004. deleteUnnecessaryProperties(orderDetail);
  1005. const operation = state.orderId ? orderEdit : orderAdd;
  1006. const addOrderAndNavigate = () => {
  1007. operation(orderDetail)
  1008. .then(() => {
  1009. buttonLoading.value = false;
  1010. ElMessage.success('操作成功');
  1011. orderProcessSuccess();
  1012. })
  1013. .catch(() => {
  1014. buttonLoading.value = false;
  1015. });
  1016. };
  1017. if (shouldOpenDialog(orderDetail)) {
  1018. ExpandFormRef.value.openDialog(true);
  1019. } else {
  1020. addOrderAndNavigate();
  1021. }
  1022. });
  1023. }, 300);
  1024. // 选择来点人身份如果是企业 推送分类自动选择助企纾困
  1025. const selectIdentity = (val: number) => {
  1026. if (val === 2) {
  1027. state.ruleForm.pushTypeObj = state.pushTypeOptions.find((item: any) => item.dicDataValue === '8'); // 助企纾困
  1028. state.ruleForm.pushType = state.ruleForm.pushTypeObj.dicDataName;
  1029. state.ruleForm.pushTypeCode = state.ruleForm.pushTypeObj.dicDataValue;
  1030. }
  1031. };
  1032. // 是否可以办理(如果有流程id 并且当前账号可以办理 则可以办理 没有流程ID都可以办理)
  1033. const canHandle = computed(() => {
  1034. if (!state.ruleForm?.workflowId) {
  1035. // 没有流程ID表示发起流程
  1036. return true;
  1037. } else {
  1038. // 有流程ID表示已经发起流程 判断当前账号是否可以办理
  1039. return state.ruleForm?.canHandle;
  1040. }
  1041. });
  1042. // 流程审批
  1043. const processAuditRef = ref<RefType>();
  1044. const processOrder = (orderDetail: any) => {
  1045. buttonLoading.value = false;
  1046. if (orderDetail.workflowId) {
  1047. // 如果已经有流程id 说明已经发起过流程 先更新工单数据 直接调用工单办理
  1048. orderEdit(orderDetail).then(() => {
  1049. const params = {
  1050. id: orderDetail.workflowId,
  1051. processType: '工单办理',
  1052. orderDetail,
  1053. extra: {
  1054. dialogTitle: '工单办理',
  1055. inputPlaceholder: '办理意见',
  1056. annexName: '办理附件',
  1057. },
  1058. };
  1059. processAuditRef.value.openDialog(params);
  1060. });
  1061. } else {
  1062. // 如果没有流程id 说明没有发起过流程 调用工单受理
  1063. const params = {
  1064. id: state.orderId,
  1065. processType: '工单受理',
  1066. extra: {
  1067. dialogTitle: '工单受理',
  1068. inputPlaceholder: '办理意见',
  1069. annexName: '办理附件',
  1070. },
  1071. orderDetail,
  1072. };
  1073. processAuditRef.value.openDialog(params);
  1074. }
  1075. };
  1076. const handleForm = (orderDetail: any) => {
  1077. if (orderDetail.orderExtension?.orderTypeCode) {
  1078. if (ExpandFormRef.value.state.validated) {
  1079. processOrder(orderDetail);
  1080. } else {
  1081. ExpandFormRef.value.openDialog(true);
  1082. buttonLoading.value = false;
  1083. }
  1084. } else {
  1085. processOrder(orderDetail);
  1086. }
  1087. };
  1088. // 提交
  1089. const submit = throttle((formEl: FormInstance | undefined) => {
  1090. if (!formEl) return;
  1091. formEl.validate((valid: boolean) => {
  1092. if (!valid) return;
  1093. buttonLoading.value = true;
  1094. const orderDetail = {
  1095. ...state.ruleForm,
  1096. repeatableEventDetails: repeatableEventDetails.value,
  1097. files: filesFormat.value,
  1098. };
  1099. deleteUnnecessaryProperties(orderDetail);
  1100. handleForm(orderDetail);
  1101. });
  1102. }, 300);
  1103. // 选中常用意见
  1104. const chooseAdvice = (item: any) => {
  1105. state.ruleForm.content += item.content;
  1106. };
  1107. // 流程提交成功
  1108. const orderProcessSuccess = () => {
  1109. mittBus.emit('clearCache', 'todoSeats');
  1110. // mittBus.emit('clearCache', ['order', 'todoSeats', 'todoOrder', 'todoCenter', 'callLog']);
  1111. mittBus.emit('clearCachePage', ['order', 'todoOrder', 'todoCenter', 'callLog']);
  1112. // 关闭当前 tagsView
  1113. mittBus.emit('onCurrentContextmenuClick', Object.assign({}, { contextMenuClickId: 1, ...route }));
  1114. };
  1115. // 取消
  1116. const onCancel = () => {
  1117. orderProcessSuccess();
  1118. };
  1119. // 一建填单
  1120. const orderOverwrite = (val: any) => {
  1121. if (val.id_card) {
  1122. // 身份证号
  1123. state.ruleForm.licenceTypeCode = '10';
  1124. state.ruleForm.licenceType = '身份证';
  1125. state.ruleForm.licenceNo = val.id_card;
  1126. }
  1127. state.ruleForm.fromName = val.name ? val.name : state.ruleForm.fromName; // 来电人姓名
  1128. state.ruleForm.street = val.address ? val.address : state.ruleForm.street; // 详细地址
  1129. state.ruleForm.enterpriseName = val.company_name ? val.company_name : state.ruleForm.enterpriseName; // 企业名称
  1130. state.ruleForm.incidentPurpose = val.event_purpose ? val.event_purpose : state.ruleForm.incidentPurpose; // 事件目的
  1131. state.ruleForm.title = val.record_title ? val.record_title : state.ruleForm.title; // 工单标题
  1132. state.ruleForm.content = val.appeal_detatls ? val.appeal_detatls : state.ruleForm.content; // 受理内容
  1133. ElNotification({
  1134. title: '提示',
  1135. message: '一键填单成功',
  1136. type: 'success',
  1137. });
  1138. console.log(val, '工单重写');
  1139. };
  1140. // 加载基础数据
  1141. const loadBaseData = async () => {
  1142. try {
  1143. const res = await orderBaseDataAdd();
  1144. state.acceptTypeOptions = res.result?.acceptTypeOptions ?? [];
  1145. state.channelOptions = res.result?.channelOptions ?? [];
  1146. state.emergencyLevelOptions = res.result?.emergencyLevelOptions ?? [];
  1147. state.genderOptions = res.result?.genderOptions ?? [];
  1148. state.identityTypeOptions = res.result?.identityTypeOptions ?? [];
  1149. orderTypeOptions.value = res.result?.orderTypeOptions ?? [];
  1150. state.pushTypeOptions = res.result?.pushTypeOptions ?? [];
  1151. state.licenceTypeOptions = res.result?.licenceTypeOptions ?? [];
  1152. state.ageRangeOptions = res.result?.ageRangeOptions ?? [];
  1153. state.transpondCity = res.result?.transpondCity ?? [];
  1154. state.focusOnEvents = res.result?.focusOnEvents ?? [];
  1155. } catch (error) {
  1156. console.log(error);
  1157. }
  1158. };
  1159. // 如果是修改加载表单内容
  1160. const historyParams = history.state;
  1161. const loadForm = async () => {
  1162. state.formLoading = true;
  1163. // historyParams.createBy createBy 代表来源 tel:来电弹单 letter:互联网来信 默认表示手动创建
  1164. if (historyParams.createBy) {
  1165. state.createBy = historyParams.createBy;
  1166. if (historyParams.createBy === 'tel') {
  1167. //通话
  1168. state.ruleForm.sourceChannel = '电话'; //电话
  1169. state.ruleForm.sourceChannelCode = 'RGDH'; //电话
  1170. state.ruleForm.fromPhone = historyParams.fromTel; // 来电号码
  1171. state.ruleForm.contact = historyParams.fromTel; // 联系电话
  1172. state.ruleForm.callId = historyParams.telGuid; // 通话id
  1173. state.ruleForm.transferPhone = historyParams.transfer; // 转接来源
  1174. state.ruleForm.callAddress = historyParams.telArea; // 来电归属地
  1175. state.ruleForm.channel = {
  1176. // 来源渠道
  1177. dicDataValue: state.ruleForm.sourceChannelCode,
  1178. dicDataName: state.ruleForm.sourceChannel,
  1179. };
  1180. state.ruleForm.identityType = historyParams.identityType ? parseInt(historyParams.identityType) : 1; // 按键接收(1:市民 2:企业 3:智能应答)
  1181. }
  1182. }
  1183. if (route.params.id) {
  1184. // 如果 有id
  1185. state.orderId = route.params.id;
  1186. const response = await orderDetail(route.params.id);
  1187. // 如果获取到id 调用查询详情
  1188. state.ruleForm = response.result;
  1189. state.ruleForm.files = transformFile(response.result.files);
  1190. if (response.result.duplicateIds && response.result.duplicateIds.length) {
  1191. // 是否重复
  1192. state.ruleForm.isRepeat = 'true';
  1193. state.ruleForm.duplicateTitle = '已选择';
  1194. } else {
  1195. state.ruleForm.isRepeat = 'false';
  1196. }
  1197. if (state.ruleForm.focusOnEvents) {
  1198. state.ruleForm.focusOnEventsArr = response.result.focusOnEvents.split(',');
  1199. }
  1200. state.ruleForm.channel = {
  1201. // 来源渠道
  1202. dicDataValue: state.ruleForm.sourceChannelCode,
  1203. dicDataName: state.ruleForm.sourceChannel,
  1204. };
  1205. if (state.ruleForm.hotspotExternal) {
  1206. //热点分类默认展开
  1207. state.hotspotExternal = state.ruleForm.hotspotExternal.split(',');
  1208. }
  1209. if (state.ruleForm.eventCategoryExternal) {
  1210. //热点分类默认展开
  1211. state.eventCategoryExternal = state.ruleForm.eventCategoryExternal.split(',');
  1212. }
  1213. state.ruleForm.ageRangeObj = {
  1214. // 年龄段
  1215. dicDataValue: state.ruleForm.ageRangeCode,
  1216. dicDataName: state.ruleForm.ageRange,
  1217. };
  1218. state.ruleForm.licenceTypeObj = {
  1219. // 证件类型
  1220. dicDataValue: state.ruleForm.licenceTypeCode,
  1221. dicDataName: state.ruleForm.licenceType,
  1222. };
  1223. state.ruleForm.acceptTypeObj = {
  1224. // 受理类型
  1225. dicDataValue: state.ruleForm.acceptTypeCode,
  1226. dicDataName: state.ruleForm.acceptType,
  1227. };
  1228. state.ruleForm.pushTypeObj = {
  1229. // 推送分类
  1230. dicDataValue: state.ruleForm.pushTypeCode,
  1231. dicDataName: state.ruleForm.pushType,
  1232. };
  1233. state.ruleForm.transpondCityObj = {
  1234. // 市州互转
  1235. dicDataValue: state.ruleForm.transpondCityValue,
  1236. dicDataName: state.ruleForm.transpondCityName,
  1237. };
  1238. state.formLoading = false;
  1239. } else {
  1240. state.formLoading = false;
  1241. }
  1242. };
  1243. // 加载省市区
  1244. const addressLoading = ref<boolean>(false);
  1245. const loadAddress = async () => {
  1246. addressLoading.value = true;
  1247. try {
  1248. const area = await treeArea();
  1249. state.areaOptions = area.result ?? []; //省市区数据
  1250. addressLoading.value = false;
  1251. } catch (error) {
  1252. console.log(error);
  1253. } finally {
  1254. addressLoading.value = false;
  1255. }
  1256. };
  1257. // 加载扩展信息
  1258. const orderTypeOptions = ref<EmptyObjectType>([]); // 工单类型
  1259. // 拓展信息
  1260. const extra = ref<any>({
  1261. ext: {},
  1262. area: {},
  1263. orderTypeOptions: [],
  1264. });
  1265. const extraLoading = ref<boolean>(false);
  1266. const loadExtra = async () => {
  1267. extraLoading.value = true;
  1268. try {
  1269. const ext = await orderBaseExt(); // 扩展信息
  1270. extra.value = { ext: { ...ext.result, orderTypeOptions: orderTypeOptions.value, area: state.areaOptions } }; //补充信息
  1271. } catch (error) {
  1272. console.log(error);
  1273. } finally {
  1274. extraLoading.value = false;
  1275. }
  1276. };
  1277. loadBaseData();
  1278. loadForm();
  1279. onMounted(async () => {
  1280. await loadAddress();
  1281. await loadExtra();
  1282. });
  1283. </script>