boilerDetail.vue 71 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040
  1. <template>
  2. <div class="app-container">
  3. <!-- 受检单位基本信息 -->
  4. <ContentWrap title="受检单位基本信息" v-if="unitData.id">
  5. <div class="mb-[5px]">
  6. <el-button class="mb-[10px]" type="primary" @click="handleUnitCodeFn(unitData.id)">工商信息</el-button>
  7. <el-descriptions :column="3" border class="flex-1">
  8. <el-descriptions-item label="单位名称">{{ unitData.name || '-' }}</el-descriptions-item>
  9. <el-descriptions-item label="登记状态">{{ unitData.regstateCn || '-' }}</el-descriptions-item>
  10. <el-descriptions-item label="市场主体类型">{{ unitData.enterpriseType || '-' }}</el-descriptions-item>
  11. <el-descriptions-item label="单位地址">{{ unitData.addr || '-' }}</el-descriptions-item>
  12. </el-descriptions>
  13. </div>
  14. </ContentWrap>
  15. <unitContainerForm ref="unitContainerFormRef" />
  16. <!-- 受检信息表单 -->
  17. <ContentWrap title="受检信息">
  18. <el-form :model="formData" :rules="formRules" ref="formRef" label-width="120px" class="p-3">
  19. <!-- <div class="check-info-label-title">受理单位</div> -->
  20. <div class="check-info-label-title">单位信息 </div>
  21. <el-row class="form-group" :gutter="24">
  22. <el-col :span="8">
  23. <!-- 申请单位名称 unitName -->
  24. <el-form-item label="申请单位名称" prop="unitName" class="unit-form-item">
  25. <el-input v-if="useInputUnitName" v-model="formData.unitName.name" placeholder="请输入单位名称" :maxlength="50" />
  26. <CustomLargeListSelect
  27. v-else
  28. v-model:modelValue="formData.unitName"
  29. :fetchFunc="getUnitNewList"
  30. label-key="name"
  31. value-key="id"
  32. searchKeyProp="name"
  33. @change="handleChangeUnit"
  34. />
  35. <el-button type="primary" link @click="() => useInputUnitName = !useInputUnitName">{{useInputUnitName ? '选择单位' : '手动输入'}}</el-button>
  36. </el-form-item>
  37. </el-col>
  38. <el-col :span="8">
  39. <!-- 统一社会信用代码 socialCreditCode -->
  40. <el-form-item label="统一社会信用代码" prop="socialCreditCode" label-width="120px">
  41. <el-input v-model="formData.socialCreditCode" placeholder="请输入统一社会信用代码" :maxlength="50"/>
  42. </el-form-item>
  43. </el-col>
  44. <el-col :span="8">
  45. <!-- 申请单位地址 unitAddress -->
  46. <el-form-item label="申请单位地址" prop="unitAddress" label-width="120px">
  47. <el-input v-model="formData.unitAddress" placeholder="请输入申请单位地址" :maxlength="50"/>
  48. </el-form-item>
  49. </el-col>
  50. <el-col :span="8">
  51. <!-- 邮政编码 zipCode -->
  52. <el-form-item label="申请单位邮政编码" prop="zipCode">
  53. <el-input v-model="formData.zipCode" placeholder="请输入申请单位邮政编码" :maxlength="50"/>
  54. </el-form-item>
  55. </el-col>
  56. <el-col :span="8">
  57. <el-form-item label="检验性质" prop="checkType" label-width="120px">
  58. <el-select disabled v-model="formData.checkType" placeholder="请选择检验性质" clearable>
  59. <el-option
  60. v-for="(item, key) in checkStatusMap"
  61. :key="key"
  62. :label="item"
  63. :value="key"
  64. />
  65. </el-select>
  66. </el-form-item>
  67. </el-col>
  68. <!-- <el-col :span="8">
  69. <el-form-item label="检验性质" prop="checkType" label-width="120px">
  70. <el-select v-model="formData.checkType" placeholder="请选择检验性质" clearable disabled>
  71. <el-option
  72. v-for="(item, key) in checkStatusMap"
  73. :key="key"
  74. :label="item"
  75. :value="key"
  76. />
  77. </el-select>
  78. </el-form-item>
  79. </el-col> -->
  80. </el-row>
  81. <!-- <div class="check-info-label-title">使用单位</div> -->
  82. <el-row class="form-group" :gutter="24">
  83. <el-col :span="8">
  84. <!-- 使用单位名称 useUnitName -->
  85. <el-form-item label="使用单位名称" prop="useUnitName" class="unit-form-item">
  86. <el-input v-if="useInputUseUnitName" v-model="formData.useUnitName.name" placeholder="请输入使用单位名称" :maxlength="50" @blur="handleChangeUseUnitInput" @keyup.enter="handleChangeUseUnitInput" />
  87. <CustomLargeListSelect
  88. v-else
  89. v-model:modelValue="formData.useUnitName"
  90. :fetchFunc="getUnitNewList"
  91. label-key="name"
  92. value-key="id"
  93. searchKeyProp="name"
  94. @change="handleChangeUseUnit"
  95. />
  96. <el-button type="primary" link @click="() => useInputUseUnitName = !useInputUseUnitName">{{useInputUseUnitName ? '选择单位' : '手动输入'}}</el-button>
  97. </el-form-item>
  98. </el-col>
  99. <el-col :span="8">
  100. <!-- 统一社会信用代码 -->
  101. <el-form-item label="统一社会信用代码" prop="useUnitSocialCreditCode" label-width="120px">
  102. <el-input v-model="formData.useUnitSocialCreditCode" placeholder="请输入统一社会信用代码" :maxlength="50"/>
  103. </el-form-item>
  104. </el-col>
  105. <el-col :span="8">
  106. <!-- 使用单位地址 useUnitAddress -->
  107. <el-form-item label="使用单位地址" prop="useUnitAddress" label-width="120px">
  108. <el-input v-model="formData.useUnitAddress" placeholder="请输入使用单位地址" :maxlength="50"/>
  109. </el-form-item>
  110. </el-col>
  111. <el-col :span="8">
  112. <!-- 邮政编码 useUnitZipcode -->
  113. <el-form-item label="使用邮政编码" prop="useUnitZipcode">
  114. <el-input v-model="formData.useUnitZipcode" placeholder="请输入使用邮政编码" :maxlength="50"/>
  115. </el-form-item>
  116. </el-col>
  117. <el-col :span="8">
  118. <!-- 单位联系人 useUnitContact -->
  119. <el-form-item label="单位联系人" prop="useUnitContact" label-width="120px">
  120. <el-input v-model="formData.useUnitContact" placeholder="请输入单位联系人" :maxlength="50"/>
  121. </el-form-item>
  122. </el-col>
  123. <el-col :span="8">
  124. <!-- 联系人电话 useUnitPhone -->
  125. <el-form-item label="联系人电话" prop="useUnitPhone" label-width="120px">
  126. <el-input v-model="formData.useUnitPhone" placeholder="请输入联系人电话" :maxlength="11"/>
  127. </el-form-item>
  128. </el-col>
  129. </el-row>
  130. <div class="check-info-label-title">联系人信息</div>
  131. <el-row class="form-group" :gutter="24">
  132. <el-col :span="8">
  133. <!-- 约检联系人 unitContact -->
  134. <el-form-item label="约检联系人" prop="unitContact">
  135. <el-input v-model="formData.unitContact" placeholder="请输入约检联系人" :maxlength="50"/>
  136. </el-form-item>
  137. </el-col>
  138. <el-col :span="8">
  139. <!-- 约检联系人电话unitPhone -->
  140. <el-form-item label="联系人电话" prop="unitPhone" label-width="120px">
  141. <el-input v-model="formData.unitPhone" placeholder="请输入约检联系人电话" :maxlength="11"/>
  142. </el-form-item>
  143. </el-col>
  144. <el-col :span="8">
  145. <!-- 约检联系人电话email -->
  146. <el-form-item label="联系人邮箱" prop="email" label-width="120px">
  147. <el-input v-model="formData.email" placeholder="请输入约检联系人邮箱"/>
  148. </el-form-item>
  149. </el-col>
  150. <el-col :span="8">
  151. <!-- 电子报告接收人 recipient -->
  152. <el-form-item label="电子报告接收人" prop="recipient" label-width="120px">
  153. <el-input v-model="formData.recipient" placeholder="请输入电子报告接收人" :maxlength="50"/>
  154. </el-form-item>
  155. </el-col>
  156. <el-col :span="8">
  157. <!-- 接收人电话 recipientPhone -->
  158. <el-form-item label="接收人电话" prop="recipientPhone">
  159. <el-input v-model="formData.recipientPhone" placeholder="请输入接收人电话" :maxlength="11"/>
  160. </el-form-item>
  161. </el-col>
  162. <el-col :span="8">
  163. <el-form-item label="接收人邮箱" prop="recipientEmail">
  164. <el-input v-model="formData.recipientEmail" placeholder="请输入接收人邮箱"/>
  165. </el-form-item>
  166. </el-col>
  167. <el-col :span="8">
  168. <el-form-item label="缴费联系人" prop="payerContactName" label-width="120px">
  169. <el-input v-model="formData.payerContactName" placeholder="请输入缴费联系人" :maxlength="50"/>
  170. </el-form-item>
  171. </el-col>
  172. <el-col :span="8">
  173. <!-- 接收人电话 payerContact -->
  174. <el-form-item label="缴费人电话" prop="payerContact">
  175. <el-input v-model="formData.payerContact" placeholder="请输入缴费人电话" :maxlength="11"/>
  176. </el-form-item>
  177. </el-col>
  178. <el-col :span="8">
  179. <el-form-item label="缴费人邮箱" prop="payerMail">
  180. <el-input v-model="formData.payerMail" placeholder="请输入缴费人邮箱"/>
  181. </el-form-item>
  182. </el-col>
  183. </el-row>
  184. <div class="check-info-label-title">受理信息</div>
  185. <el-row class="form-group" :gutter="24">
  186. <el-col :span="8">
  187. <!-- 检验部门 deptId -->
  188. <el-form-item label="检验部门" prop="deptId">
  189. <!-- <el-input v-model="formData.deptId" placeholder="请输入检验部门"/> -->
  190. <DeptSelect
  191. v-model="formData.deptId"
  192. placeholder="请选择部门"
  193. clearable
  194. />
  195. </el-form-item>
  196. </el-col>
  197. <el-col :span="8">
  198. <!-- 联系电话 deptPhone -->
  199. <el-form-item label="联系电话" prop="deptPhone" label-width="120px">
  200. <el-input v-model="formData.deptPhone" placeholder="请输入联系电话" :maxlength="20"/>
  201. </el-form-item>
  202. </el-col>
  203. <el-col :span="8">
  204. <!-- 约检时间 appointmentDate -->
  205. <el-form-item label="约检时间" prop="appointmentDate" label-width="120px">
  206. <el-date-picker
  207. v-model="formData.appointmentDate"
  208. type="date"
  209. value-format="YYYY-MM-DD"
  210. placeholder="请选择约检时间"
  211. :disabled-date="disabledDate"
  212. />
  213. </el-form-item>
  214. </el-col>
  215. <el-col :span="24">
  216. <!-- 检验员 teamList -->
  217. <el-form-item label="检验员" prop="teamList">
  218. <!-- <CheckerSelect-->
  219. <!-- ref="checkerSelectRef"-->
  220. <!-- v-model="selectedCheckers"-->
  221. <!-- :dept-id="userStore.getUser.deptId?.toString() || '1'"-->
  222. <!-- :disabled="false"-->
  223. <!-- :has-data="true"-->
  224. <!-- empty-text="暂无检验员数据"-->
  225. <!-- :multiple="true"-->
  226. <!-- @change="handleCheckerChange"-->
  227. <!-- />-->
  228. <div v-if="formattedCheckers.length > 0" class="selected-checkers">
  229. <el-tag
  230. v-for="checker in formattedCheckers"
  231. :key="checker.id"
  232. effect="plain"
  233. class="mr-8px mb-8px"
  234. >
  235. {{ checker.label }}
  236. </el-tag>
  237. </div>
  238. <span v-else>-</span>
  239. </el-form-item>
  240. </el-col>
  241. </el-row>
  242. <div class="check-info-label-title">异常信息</div>
  243. <el-row class="m-b-20px">
  244. <el-button v-if="!exceptionInfo.id" type="primary" @click="addExceptionInfo">添加异常单</el-button>
  245. <el-button v-else type="primary" @click="deleteExceptionInfo">删除异常单</el-button>
  246. </el-row>
  247. <el-row v-if="exceptionInfo.id" class="form-group" :gutter="24">
  248. <el-col :span="8">
  249. <el-form-item label="有效日期调整原因" prop="effectiveDateAdjustReason">
  250. <el-input v-model="exceptionInfo.effectiveDateAdjustReason" placeholder="请输入有效日期调整原因"/>
  251. </el-form-item>
  252. </el-col>
  253. <el-col :span="8">
  254. <el-form-item label="受理建议" prop="acceptSuggeston">
  255. <el-input v-model="exceptionInfo.acceptSuggeston" placeholder="请输入受理建议"/>
  256. </el-form-item>
  257. </el-col>
  258. <el-col :span="8">
  259. <el-form-item label="调整有效日期" prop="adjustEffectiveDate">
  260. <el-date-picker
  261. v-model="exceptionInfo.adjustEffectiveDate"
  262. type="date"
  263. value-format="YYYY-MM-DD"
  264. placeholder="请选择调整有效日期"
  265. />
  266. </el-form-item>
  267. </el-col>
  268. <el-col :span="12">
  269. <el-form-item label="情况说明" prop="descrition">
  270. <component :is="getExceptionItem('descrition', 'descritionAttach')" />
  271. </el-form-item>
  272. </el-col>
  273. <el-col :span="12">
  274. <el-form-item label="重启表" prop="restartTable">
  275. <component :is="getExceptionItem('restartTable', 'restartTableAttach')" />
  276. </el-form-item>
  277. </el-col>
  278. <el-col :span="12">
  279. <el-form-item label="指令书" prop="instrustionBook">
  280. <component :is="getExceptionItem('instrustionBook', 'instrustionBookAttach')" />
  281. </el-form-item>
  282. </el-col>
  283. <el-col :span="12">
  284. <el-form-item label="受理回执" prop="acceptReceipt">
  285. <component :is="getExceptionItem('acceptReceipt', 'acceptReceiptAttach')" />
  286. </el-form-item>
  287. </el-col>
  288. <el-col :span="12">
  289. <el-form-item label="其他" prop="other">
  290. <component :is="getExceptionItem('other', 'otherAttach')" />
  291. </el-form-item>
  292. </el-col>
  293. <el-col :span="12">
  294. <el-form-item label="提前检验申请函" prop="earlyCheckApply">
  295. <component :is="getExceptionItem('earlyCheckApply', 'earlyCheckApplyAttach')" />
  296. </el-form-item>
  297. </el-col>
  298. </el-row>
  299. <div class="check-info-label-title">检验收费</div>
  300. <el-row class="form-group" :gutter="24">
  301. <el-col :span="24">
  302. <!-- 定期检查&超年限检查 -->
  303. <el-form-item label="检验性质" prop="checkType" label-width="120px">
  304. <el-select disabled v-model="formData.checkType" placeholder="请选择检验性质" clearable class="!w-120px">
  305. <el-option
  306. v-for="(item, key) in checkStatusMap"
  307. :key="key"
  308. :label="item"
  309. :value="key"
  310. />
  311. </el-select>
  312. </el-form-item>
  313. <!-- 收费性质 feeNature -->
  314. <el-form-item prop="feeNature" >
  315. <template #label>
  316. <div class="flex flex-col text-right">
  317. <span>收费性质</span>
  318. <span>(行政事业收费)</span>
  319. </div>
  320. </template>
  321. <el-radio-group v-model="formData.feeNature">
  322. <el-radio v-for="(item, key) in PressureFeeNatureMap" :key="key" :value="key" :label="item"/>
  323. </el-radio-group>
  324. </el-form-item>
  325. </el-col>
  326. <el-col :span="24">
  327. <!-- 收费形式 feeType -->
  328. <el-form-item label="收费形式" prop="feeType">
  329. <el-radio-group v-model="formData.feeType">
  330. <el-radio label="100">非合同收费</el-radio>
  331. </el-radio-group>
  332. </el-form-item>
  333. </el-col>
  334. <el-col :span="24">
  335. <!-- 收费金额 actualAmount -->
  336. <!-- <el-form-item label="收费金额" prop="actualAmount" class="actualAmountFormItem">
  337. <el-input-number
  338. :controls="false"
  339. v-model="formData.actualAmount"
  340. placeholder="请输入收费金额"
  341. :min="0"
  342. />
  343. <div style="padding-left: 8px;">大写({{numberToChinese(formData.actualAmount)}})含税</div>
  344. </el-form-item>-->
  345. <div class="flex items-center gap-32 ml-40px text-14px">
  346. <span>应收法定金额: {{ formData.shouldAmount }}</span>
  347. <span>服务收费金额:{{ formData.serviceAmount }}</span>
  348. <span>免征费用: {{ formData.reduceFee }}</span>
  349. </div>
  350. </el-col>
  351. <!-- <el-col :span="24">
  352. &lt;!&ndash; 年度检查 &ndash;&gt;
  353. <el-form-item label="" prop="feeDate" label-width="30" v-if="orderDetail?.checkType == 200">
  354. <div class="feeDate_box">
  355. 甲方在本服务单签订之日起
  356. <el-input-number :controls="false" v-model="formData.feeDate" placeholder="请输入" :maxlength="50"/>
  357. 日内一次性支付。
  358. </div>
  359. </el-form-item>
  360. </el-col>-->
  361. </el-row>
  362. </el-form>
  363. </ContentWrap>
  364. <!-- 设备清单 -->
  365. <ContentWrap title="设备信息">
  366. <!-- 搜索工作栏 -->
  367. <ContentWrap>
  368. <el-form
  369. :model="equipQueryParams"
  370. ref="equipQueryFormRef"
  371. :inline="true"
  372. label-width="80px"
  373. >
  374. <!-- 基本信息查询部分 -->
  375. <div class="flex flex-wrap items-start gap-x-2">
  376. <el-form-item label="设备代码" prop="equipCode">
  377. <el-input
  378. v-model="equipQueryParams.equipCode"
  379. placeholder="请输入设备注册代码"
  380. clearable
  381. @keyup.enter="handleEquipQuery"
  382. class="!w-240px"
  383. />
  384. </el-form-item>
  385. <el-form-item label="部门" prop="relateDepartment">
  386. <DeptSelect
  387. v-model="equipQueryParams.relateDepartment"
  388. placeholder="请选择部门"
  389. clearable
  390. class="!w-240px"
  391. />
  392. </el-form-item>
  393. <el-form-item label="使用状态" prop="useStatus">
  394. <el-select
  395. v-model="equipQueryParams.useStatus"
  396. placeholder="选择使用状态"
  397. clearable
  398. multiple
  399. collapse-tags
  400. collapse-tags-tooltip
  401. class="!w-240px"
  402. >
  403. <el-option
  404. v-for="dict in getStrDictOptions(DICT_TYPE.SYSTEM_EQUIP_BOILER_STATUS)"
  405. :key="dict.value"
  406. :label="dict.label"
  407. :value="dict.value"
  408. />
  409. </el-select>
  410. </el-form-item>
  411. <el-form-item label="临检时间" prop="nextDate">
  412. <div class="flex items-center gap-x-2">
  413. <el-select v-model="datePickerType" class="!w-[90px]">
  414. <el-option label="时间段" value="daterange" />
  415. <el-option label="月份" value="month" />
  416. </el-select>
  417. <el-date-picker
  418. v-if="datePickerType === 'daterange'"
  419. v-model="daterange"
  420. type="daterange"
  421. value-format="YYYY-MM-DD"
  422. start-placeholder="开始日期"
  423. end-placeholder="结束日期"
  424. class="!w-[210px]"
  425. @change="handleDateChange"
  426. />
  427. <el-date-picker
  428. v-else
  429. v-model="month"
  430. type="month"
  431. value-format="YYYY-MM"
  432. placeholder="选择月份"
  433. class="!w-[140px]"
  434. @change="handleMonthChange"
  435. />
  436. </div>
  437. </el-form-item>
  438. </div>
  439. <!-- 区域和时间查询部分 -->
  440. <div class="flex flex-wrap items-start gap-x-2">
  441. <el-form-item label="区域" prop="equipDistrict">
  442. <AreaSelect
  443. v-model="equipQueryParams.equipDistrict"
  444. placeholder="请选择区域"
  445. class="!w-[240px]"
  446. multiple
  447. collapse-tags
  448. collapse-tags-tooltip
  449. :clearable="true"
  450. @clear="handleAreaClear"
  451. @change="handleAreaChange"
  452. />
  453. </el-form-item>
  454. <el-form-item label="街道" prop="equipStreet">
  455. <StreetSelect
  456. v-model="equipQueryParams.equipStreet"
  457. :district-ids="equipQueryParams.equipDistrict"
  458. placeholder="请选择街道"
  459. class="!w-[240px]"
  460. multiple
  461. collapse-tags
  462. collapse-tags-tooltip
  463. :clearable="true"
  464. @clear="handleStreetClear"
  465. @change="handleStreetChange"
  466. />
  467. </el-form-item>
  468. </div>
  469. <!-- 容器相关查询条件 -->
  470. <div class="">
  471. <el-form-item label="锅炉归类" prop="typeList" class="mb-2">
  472. <div class="flex items-center flex-1">
  473. <el-checkbox-group
  474. v-model="equipQueryParams.typeList"
  475. class="flex flex-wrap gap-2"
  476. >
  477. <el-checkbox
  478. v-for="dict in boilerTypeOptions"
  479. :key="dict.value"
  480. :label="dict.label"
  481. :value="dict.value"
  482. />
  483. </el-checkbox-group>
  484. </div>
  485. </el-form-item>
  486. </div>
  487. <!-- 操作按钮 -->
  488. <div class="flex justify-center">
  489. <el-form-item class="!mb-0">
  490. <el-button @click="handleEquipQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
  491. <el-button @click="resetEquipQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
  492. <!-- 删除设备 -->
  493. <el-button type="danger" :disabled="selectedEquips.length === 0" @click="handleRejectEquip">
  494. <Icon icon="ep:failed" class="mr-5px" /> 拒绝约检
  495. </el-button>
  496. <el-button type="primary" @click="handleAddEquip"><Icon icon="ep:plus" class="mr-5px" /> 添加设备</el-button>
  497. <el-button type="primary" @click="handleBatchEditFn" :disabled="selectedEquips.length === 0">
  498. <Icon icon="ep:edit" class="mr-5px" /> 批量修改约检联系人
  499. </el-button>
  500. <el-button type="primary" @click="handleBatchEditLocationFn" :disabled="selectedEquips.length === 0">
  501. <Icon icon="ep:edit" class="mr-5px" /> 批量修改地址
  502. </el-button>
  503. </el-form-item>
  504. </div>
  505. </el-form>
  506. </ContentWrap>
  507. <!-- 设备列表 -->
  508. <ContentWrap>
  509. <el-table
  510. v-loading="equipLoading"
  511. :data="equipList"
  512. stripe
  513. @selection-change="handleEquipSelectionChange"
  514. @sort-change="handleEquipSortChange"
  515. >
  516. <el-table-column type="selection" width="30" />
  517. <el-table-column label="区域" align="center" prop="equipDistrictName" sortable="custom" min-width="120" />
  518. <el-table-column label="街道" align="center" prop="equipStreetName" sortable="custom" min-width="120" />
  519. <el-table-column label="设备注册代码" align="center" prop="equipCode" min-width="190">
  520. <template #default="{ row }">
  521. {{ row.equipCode }}
  522. <dict-tag :type="DICT_TYPE.SYSTEM_EQUIP_BOILER_STATUS" :value="row.status" />
  523. </template>
  524. </el-table-column>
  525. <el-table-column label="是否租借" align="center" prop="isRent" min-width="80">
  526. <template #default="{ row }">
  527. {{ row.isRent ? '是' : '否' }}
  528. </template>
  529. </el-table-column>
  530. <el-table-column label="使用证编号" align="center" prop="useRegisterNo" min-width="120" />
  531. <el-table-column label="出厂编号" align="center" prop="factoryCode" min-width="120" />
  532. <el-table-column label="约检联系人" align="center" prop="contact" min-width="120" />
  533. <el-table-column label="约检联系人电话" align="center" prop="contactPhone" min-width="140" />
  534. <el-table-column label="蒸发量" align="center" prop="maxContinueEvapor" min-width="80" />
  535. <el-table-column label="型号" align="center" prop="boilerModel" min-width="120" />
  536. <!-- <el-table-column label="吨位" align="center" prop="tonnage" min-width="120" />-->
  537. </el-table>
  538. <!-- 分页 -->
  539. <Pagination
  540. :total="equipTotal"
  541. v-model:page="equipQueryParams.pageNo"
  542. v-model:limit="equipQueryParams.pageSize"
  543. @pagination="handleEquipQuery"
  544. />
  545. </ContentWrap>
  546. </ContentWrap>
  547. <!-- 添加设备弹窗 -->
  548. <AddEquipDialog
  549. v-model:visible="addEquipVisible"
  550. type=""
  551. :target-id="orderDetail?.id || ''"
  552. :unit-code="orderDetail?.unitCode || ''"
  553. :unit-name="orderDetail?.unitName || ''"
  554. @success="handleAddEquipSuccess"
  555. />
  556. <!-- 拒绝约检弹窗 -->
  557. <el-dialog
  558. v-model="rejectDialogVisible"
  559. title="拒绝约检"
  560. width="600px"
  561. destroy-on-close
  562. :close-on-click-modal="false"
  563. >
  564. <div class="mb-4">
  565. <div v-for="equip in selectedEquips" :key="equip.id" class="mb-2">
  566. 设备注册代码:{{ equip.equipCode }}
  567. </div>
  568. </div>
  569. <div class="mb-4">
  570. 检验性质:{{ orderDetail?.checkType ? allCheckTypeMap[orderDetail.equipMainType][orderDetail.checkType] : '' }}
  571. </div>
  572. <div class="mb-4 flex flex-start items-center">
  573. <div class="!w-80px">拒绝原因:</div>
  574. <el-select v-model="rejectForm.reasonDict" placeholder="请选择拒绝原因" @change="() => {rejectForm.reason = ''}">
  575. <el-option
  576. v-for="dict in getStrDictOptions('refuseInspectedCategory')"
  577. :key="dict.value"
  578. :label="dict.label"
  579. :value="dict.value"
  580. />
  581. </el-select>
  582. </div>
  583. <div class="mb-4" v-if="rejectForm.reasonDict == '5'">
  584. <div class="mb-2">说明:</div>
  585. <el-input
  586. v-model.trim="rejectForm.reason"
  587. type="textarea"
  588. :rows="4"
  589. placeholder="请输入"
  590. resize="none"
  591. :maxlength="100"
  592. show-word-limit
  593. />
  594. </div>
  595. <template #footer>
  596. <div class="flex justify-end items-center">
  597. <!-- <el-button type="primary" :loading="rejectLoading" @click="handleRejectConfirm(200)">上报拒检</el-button> -->
  598. <!-- <el-button v-if="orderDetail?.checkType === 100 || orderDetail?.checkType === 300" type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>-->
  599. <el-button type="primary" :loading="rejectLoading" @click="handleRejectConfirm(100)">上报市局</el-button>
  600. <!-- <el-button v-else type="primary" :loading="rejectLoading" @click="handleRejectConfirm(200)">上报拒检</el-button>-->
  601. <el-button type="warning" :loading="rejectLoading" @click="handleRejectConfirm(300)">无需上报</el-button>
  602. <el-button @click="rejectDialogVisible = false">取消</el-button>
  603. </div>
  604. </template>
  605. </el-dialog>
  606. <!-- 页面底部按钮 -->
  607. <div class="flex justify-center pb-4">
  608. <el-button @click="handleClose" :loading="loading">关闭</el-button>
  609. <el-button v-if="!route.query.id || orderDetail?.createAcceptOrder === false" type="primary" :loading="loading" @click="handleGenerateAcceptance">
  610. 生产任务单
  611. </el-button>
  612. <el-button type="primary" @click="handleSave" :loading="loading">保存</el-button>
  613. </div>
  614. <batchEditForm ref="batchEditFormRef" @success="()=>handleEquipQuery(true)"/>
  615. <EquipContainerForm ref="EquipContainerFormRef" />
  616. <FileUploadModal ref="fileUploadModalRef" @success="handleFileUploadSuccess" />
  617. <!-- 批量修改地址弹窗 -->
  618. <el-dialog v-model="batchEditLocationVisible" title="批量修改地址" width="500px" :close-on-click-modal="false">
  619. <el-form ref="batchEditLocationFormRef" :model="batchEditLocationFormData" :rules="batchEditLocationFormRules" label-width="140px">
  620. <el-form-item label="设备所在行政区" prop="equipDistrict">
  621. <AreaSelect v-model="batchEditLocationFormData.equipDistrict" :areaType="batchEditLocationFormData.areaType" @area-type-change="changeArea" @change="changeAddress" placeholder="请选择设备所在行政区" />
  622. </el-form-item>
  623. <el-form-item label="设备所在街道" prop="equipStreet">
  624. <StreetSelect v-model="batchEditLocationFormData.equipStreet" :district-ids="[batchEditLocationFormData.equipDistrict]" placeholder="请选择设备所在街道" />
  625. </el-form-item>
  626. </el-form>
  627. <template #footer>
  628. <el-button :loading="batchEditLocationLoading" @click="batchEditLocationVisible = false">取消</el-button>
  629. <el-button type="primary" :loading="batchEditLocationLoading" @click="batchEditLocationSubmitForm">批量修改</el-button>
  630. </template>
  631. </el-dialog>
  632. </div>
  633. </template>
  634. <script setup lang="tsx">
  635. import { ref, onMounted, computed, watch, nextTick } from 'vue'
  636. import { useRoute, useRouter } from 'vue-router'
  637. import { ElMessage, ElMessageBox } from 'element-plus'
  638. import batchEditForm from '../planNew/components/batchEditForm.vue'
  639. import { BoilerAppointmentConfirmOrderApi, BoilerAppointmentConfirmOrderVO } from '@/api/pressure2/appointmentconfirmorder'
  640. import { EquipBoilerSchedulingEquipVO } from '@/api/pressure2/equipboilerscheduling'
  641. import { EquipBoilerSchedulingApi } from '@/api/pressure2/equipboilerscheduling'
  642. import dayjs from 'dayjs'
  643. import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
  644. import DeptSelect from '../../pressure2/equipboilerscheduling/components/DeptSelect.vue'
  645. import AreaSelect from '../../system/equipcontainer/components/AreaSelect.vue'
  646. import StreetSelect from '../../system/equipcontainer/components/StreetSelect.vue'
  647. import AddEquipDialog from '../schedule/components/AddEquipDialog.vue'
  648. import { formatArrayDate } from '@/utils/formatTime'
  649. import EquipContainerForm from '@/components/EquipContainerForm/index.vue'
  650. import { useTagsViewStore } from '@/store/modules/tagsView'
  651. import {
  652. PressureCheckTypeMap,
  653. PressureFeeTypeMap,
  654. PressureFeeNatureMap,
  655. PressureFeeNature,
  656. allCheckTypeMap
  657. } from '@/utils/constants'
  658. import { useEmitt } from '@/hooks/web/useEmitt'
  659. import { getUnitNewList, getUnitContacts } from '@/api/laboratory/unit'
  660. import { getUnitInfo, UpdateUnitVO } from '@/api/laboratory/unit'
  661. import unitContainerForm from '@/components/unitContainerForm/index.vue'
  662. import { numberToChinese } from '@/utils/formatter'
  663. import FileUploadModal from './components/ImportFile.vue'
  664. import { buildFileUrl } from '@/utils'
  665. import { Icon } from '@/components/Icon'
  666. import { cloneDeep } from 'lodash-es'
  667. import { useUserStoreWithOut } from '@/store/modules/user'
  668. import { type CheckerItem } from '@/views/pressure2/components/CheckerSelect'
  669. import { getDept } from '@/api/system/dept'
  670. import { EquipBoilerApi } from '@/api/pressure2/equipboiler'
  671. const { emitter } = useEmitt()
  672. const route = useRoute()
  673. const router = useRouter()
  674. const tagsViewStore = useTagsViewStore()
  675. const userStore = useUserStoreWithOut()
  676. const batchEditFormRef = ref()
  677. const batchEditLocationVisible = ref(false)
  678. const batchEditLocationLoading = ref(false)
  679. const batchEditLocationFormRef = ref()
  680. const batchEditLocationFormData = ref({
  681. areaType: '',
  682. equipDistrict: '',
  683. equipStreet: '',
  684. })
  685. const batchEditLocationFormRules = {
  686. equipDistrict: [{ required: true, message: '请选择设备所在行政区', trigger: 'change' }],
  687. equipStreet: [{ required: true, message: '请选择设备所在街道', trigger: 'change' }],
  688. }
  689. const orderDetail = ref<BoilerAppointmentConfirmOrderVO>()
  690. const checkTypeMap = PressureCheckTypeMap
  691. const boilerTypeOptions = getStrDictOptions(DICT_TYPE.SYSTEM_EQUIP_BOILER_TYPE)
  692. const unitData = ref<UpdateUnitVO>({} as UpdateUnitVO)
  693. const unitContainerFormRef = ref<InstanceType<typeof unitContainerForm>>()
  694. const getUnitDetail = async (unitId: string) => {
  695. try {
  696. const res = await getUnitInfo({ id: unitId })
  697. unitData.value = res
  698. } catch (error) {
  699. console.error('获取单位详情失败:', error)
  700. }
  701. }
  702. const handleUnitCodeFn = (id) => {
  703. if (!id) { return ElMessage.warning('该单位信息异常!') }
  704. unitContainerFormRef.value?.open(id)
  705. }
  706. const formData = ref<Record<string,any>>({
  707. checkType: '', //检验性质
  708. appointmentDate: '',
  709. teamList: [] as string[],
  710. unitName: {
  711. name: '',
  712. id: ''
  713. },
  714. deptName: '',
  715. equipDistrict: undefined as number | undefined,
  716. equipDistrictName: '',
  717. equipStreet: '',
  718. equipStreetName: '',
  719. unitContact: '',
  720. unitCode: '',
  721. unitContactDept: '',
  722. unitAddress: '',
  723. unitPhone: '',
  724. zipCode: '',
  725. mobile: '',
  726. remark: '',
  727. email: '',
  728. isAttach: false,
  729. sendType: '100',
  730. vehicle: '100',
  731. feeType: '100',
  732. acceptType: '100',
  733. actualAmount: 0,
  734. serviceAmount: 0,
  735. shouldAmount: 0,
  736. reduceFee: 0,
  737. planMaker: '',
  738. deptId: '',
  739. operator: '',
  740. areaDisplay: '',
  741. socialCreditCode: '',
  742. recipient: '',
  743. recipientPhone: '',
  744. recipientEmail: '',
  745. useUnitName: {
  746. name: '',
  747. id: ''
  748. },
  749. useUnitId: '',
  750. useUnitSocialCreditCode: '',
  751. useUnitAddress: '',
  752. useUnitZipcode: '',
  753. useUnitContact: '',
  754. useUnitPhone: '',
  755. deptPhone: '',
  756. feeNature: '',
  757. feeDate: 0,
  758. descritionFile: [],
  759. })
  760. const checkStatusMap = {
  761. '100': '内部检验',
  762. '200': '外部检验',
  763. '300': '耐压检验',
  764. }
  765. const loading = ref(false)
  766. // 检验员选择相关
  767. const selectedCheckers = ref<CheckerItem[]>([])
  768. const checkerSelectRef = ref()
  769. const EquipContainerFormRef = ref<InstanceType<typeof EquipContainerForm>>()
  770. // 记录每个区域下已选择的街道
  771. const areaStreetMap = ref(new Map<number, number[]>())
  772. // 设备查询相关
  773. const equipQueryParams = ref({
  774. pageNo: 1,
  775. pageSize: 50,
  776. equipDistrict: undefined as number[] | undefined,
  777. equipStreet: undefined as number[] | undefined,
  778. equipCode: '',
  779. productNo: '',
  780. relateDepartment: '' as string | number | undefined,
  781. typeList: [] as string[],
  782. nextDate: [] as string[],
  783. useStatus: [] as string[],
  784. })
  785. const equipQueryFormRef = ref()
  786. const equipLoading = ref(false)
  787. const equipList = ref<EquipBoilerSchedulingEquipVO[]>([])
  788. // 选中的设备
  789. const selectedEquips = ref<EquipBoilerSchedulingEquipVO[]>([])
  790. const equipTotal = ref(0)
  791. const equipCategoryOptions = getStrDictOptions(DICT_TYPE.SYSTEM_EQUIP_CONTAINER_EQUIP_CATEGORY)
  792. const containerTypeOptions = getStrDictOptions(DICT_TYPE.SYSTEM_EQUIP_CONTAINER_EQUIP_TYPE)
  793. // 临检时间相关
  794. const datePickerType = ref<'daterange' | 'month'>('month')
  795. const daterange = ref<string[]>([])
  796. const month = ref<string>('')
  797. // 添加设备相关
  798. const addEquipVisible = ref(false)
  799. // 拒绝约检相关
  800. const rejectDialogVisible = ref(false)
  801. const rejectLoading = ref(false)
  802. const rejectForm = ref({
  803. reason: '',
  804. reasonDict: ''
  805. })
  806. const formRef = ref() // 表单引用
  807. /** 约检确认详情 */
  808. defineOptions({ name: 'OrderConfirmDetail' })
  809. // 表单验证规则
  810. const formRules = {
  811. // unitContact: [
  812. // { required: true, message: '请输入单位联系人', trigger: 'blur' }
  813. // ],
  814. // unitPhone: [
  815. // { required: true, message: '请输入单位联系电话', trigger: 'blur' },
  816. // ],
  817. // mobile: [
  818. // { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
  819. // ],
  820. email: [
  821. { pattern: /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/, message: '请输入正确的邮箱', trigger: 'blur' }
  822. ],
  823. // unitPhone: [
  824. // { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
  825. // ],
  826. // recipientPhone: [
  827. // { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
  828. // ],
  829. recipientEmail: [
  830. { pattern: /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/, message: '请输入正确的邮箱', trigger: 'blur' }
  831. ],
  832. payerContact: [
  833. { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
  834. ],
  835. payerMail: [
  836. { pattern: /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/, message: '请输入正确的邮箱', trigger: 'blur' }
  837. ],
  838. sendType: [
  839. { required: true, message: '请选择送达方式', trigger: 'blur' }
  840. ],
  841. // feeType: [
  842. // { required: true, message: '请选择收费类型', trigger: 'blur' }
  843. // ],
  844. acceptType: [
  845. { required: true, message: '请选择受理方式', trigger: 'blur' }
  846. ],
  847. vehicle: [
  848. { required: true, message: '请选择交通工具', trigger: 'blur' }
  849. ],
  850. checkType: [
  851. { required: true, message: '请选择检验性质', trigger: 'blur' }
  852. ],
  853. deptId: [
  854. { required: true, message: '请选择检验部门', trigger: 'change' }
  855. ]
  856. }
  857. // 区域显示属性,与formData.areaDisplay分离
  858. const areaDisplay = computed(() => {
  859. const district = formData.value.equipDistrictName || ''
  860. const street = formData.value.equipStreetName || ''
  861. if (district && street) {
  862. return `${district}-${street}`
  863. }
  864. return district
  865. })
  866. // 获取约检详情
  867. const getDetail = async () => {
  868. const id = route.query?.id as string
  869. if (!id) return
  870. loading.value = true
  871. try {
  872. const res = await BoilerAppointmentConfirmOrderApi.getAppointmentConfirmOrder(id);
  873. let { unitCode, payerContact, payerContactName, payerMail, email } = res;
  874. orderDetail.value = res || {};
  875. // 更新表单数据
  876. formData.value = {
  877. ...formData.value,
  878. checkType: `${orderDetail.value?.checkType }`,
  879. appointmentDate: formatArrayDate(orderDetail.value?.appointmentDate || []),
  880. unitName: {
  881. name: orderDetail.value?.unitName || '',
  882. id: ''
  883. },
  884. useUnitName: {
  885. name: orderDetail.value?.useUnitName || '',
  886. id: orderDetail.value?.useUnitId || ''
  887. },
  888. useUnitId: orderDetail.value?.useUnitId || '',
  889. deptName: orderDetail.value?.deptName || '',
  890. equipDistrict: orderDetail.value?.equipDistrict ? Number(orderDetail.value.equipDistrict) : undefined,
  891. equipDistrictName: orderDetail.value?.equipDistrictName || '',
  892. unitContact: orderDetail.value?.unitContact || '',
  893. unitCode,
  894. unitAddress: orderDetail.value?.unitAddress || '',
  895. unitPhone: orderDetail.value?.unitPhone || '',
  896. zipCode: orderDetail.value?.zipCode || '',
  897. mobile: orderDetail.value?.mobile || '',
  898. remark: orderDetail.value?.remark || '',
  899. // email: orderDetail.value?.email || '',
  900. isAttach: orderDetail.value?.isAttach || false,
  901. sendType: String(orderDetail.value?.sendType || 100),
  902. vehicle: String(orderDetail.value?.vehicle || 100),
  903. feeType: String(orderDetail.value?.feeType || 100),
  904. acceptType: String(orderDetail.value?.acceptType || 100),
  905. actualAmount: orderDetail.value?.actualAmount || 0,
  906. serviceAmount: orderDetail.value?.serviceAmount || 0,
  907. shouldAmount: orderDetail.value?.shouldAmount || 0,
  908. reduceFee: orderDetail.value?.reduceFee || 0,
  909. deptId: orderDetail.value?.deptId || '',
  910. operator: orderDetail.value?.operator || '',
  911. equipStreetName: orderDetail.value?.equipStreetName || '',
  912. areaDisplay: areaDisplay.value,
  913. socialCreditCode: orderDetail.value?.socialCreditCode,
  914. recipient: orderDetail.value?.recipient,
  915. recipientPhone: orderDetail.value?.recipientPhone,
  916. recipientEmail: orderDetail.value?.recipientEmail,
  917. useUnitSocialCreditCode: orderDetail.value?.useUnitSocialCreditCode,
  918. useUnitAddress: orderDetail.value?.useUnitAddress,
  919. useUnitZipcode: orderDetail.value?.useUnitZipcode,
  920. useUnitContact: orderDetail.value?.useUnitContact,
  921. useUnitPhone: orderDetail.value?.useUnitPhone,
  922. deptPhone: orderDetail.value?.deptPhone,
  923. feeNature: `${orderDetail.value?.feeNature}`,
  924. feeDate: orderDetail.value?.feeDate || 0,
  925. payerContact,
  926. payerContactName,
  927. payerMail,
  928. email,
  929. status: orderDetail.value?.status || 100,
  930. }
  931. // 更新异常信息数据
  932. // 更新检验员数据
  933. const orderExceptionRespVO = res.orderExceptionRespVO
  934. if(orderExceptionRespVO){
  935. exceptionInfo.value = {
  936. ...orderExceptionRespVO,
  937. adjustEffectiveDate: orderExceptionRespVO.adjustEffectiveDate ? dayjs(orderExceptionRespVO.adjustEffectiveDate.join('-')).format('YYYY-MM-DD') : '',
  938. }
  939. }
  940. console.log(exceptionInfo.value, 'exceptionInfo')
  941. const teamList: CheckerItem[] = orderDetail.value?.teamList?.flatMap((team: any) => {
  942. const teamMembers: CheckerItem[] = []
  943. // 处理组长
  944. if (team.leaders && team.leaders.length > 0) {
  945. team.leaders.forEach((leader: any) => {
  946. if (leader) {
  947. teamMembers.push({
  948. groupTeamId: team.groupTeamId,
  949. memberId: leader.id,
  950. leaderId: leader.id,
  951. member: leader,
  952. isLeader: true
  953. })
  954. }
  955. })
  956. }
  957. // 处理组员
  958. if (team.members && team.members.length > 0) {
  959. team.members.forEach((member: any) => {
  960. if (member) {
  961. teamMembers.push({
  962. groupTeamId: team.groupTeamId,
  963. memberId: member.id,
  964. leaderId: team.leaders?.[0]?.id || '',
  965. member: member,
  966. isLeader: false
  967. })
  968. }
  969. })
  970. }
  971. return teamMembers
  972. }) || []
  973. if (teamList.length > 0) {
  974. selectedCheckers.value = teamList
  975. formData.value.teamList = teamList
  976. }
  977. // 加载检验员列表(默认当前登录人的部门)
  978. const deptId = userStore.getUser.deptId?.toString()
  979. if (deptId) {
  980. await nextTick()
  981. checkerSelectRef.value?.getCheckerList(deptId)
  982. }
  983. // 加载单位详细信息
  984. if (orderDetail.value?.useUnitId) {
  985. await getUnitDetail(orderDetail.value.useUnitId)
  986. }
  987. } catch (error) {
  988. console.error('获取计划详情失败:', error)
  989. ElMessage.error('获取计划详情失败')
  990. router.back()
  991. } finally {
  992. loading.value = false
  993. }
  994. }
  995. /** 处理检验员变化 */
  996. const handleCheckerChange = (checkers: CheckerItem[]) => {
  997. selectedCheckers.value = checkers
  998. // 同步更新 formData.value.teamList
  999. formData.value.teamList = checkers
  1000. }
  1001. /** 禁用日期 */
  1002. const disabledDate = (time: Date) => {
  1003. // 获取所有设备的最早检验日期
  1004. const dates = equipList.value.map(item => {
  1005. if (orderDetail.value?.checkType === 100) {
  1006. return item.nextCheckDate ? formatArrayDate(item.nextCheckDate) : null
  1007. } else if (orderDetail.value?.checkType === 200) {
  1008. return item.nextYearCheckDate ? formatArrayDate(item.nextYearCheckDate) : null
  1009. } else {
  1010. return item.nextExpiredCheckDate ? formatArrayDate(item.nextExpiredCheckDate) : null
  1011. }
  1012. }).filter(Boolean) as any
  1013. // 如果没有有效日期,则禁用过去的日期
  1014. if (dates.length === 0) {
  1015. return time.getTime() < dayjs().startOf('day').valueOf()
  1016. }
  1017. // 找到最早的检验日期
  1018. const earliestDate = new Date(Math.min(...dates.map(date => new Date(date).getTime())))
  1019. // 禁用早于最早检验日期的日期
  1020. return time.getTime() > earliestDate.getTime()
  1021. }
  1022. // 设备查询相关
  1023. const handleEquipQuery = async (isUpdateContact: boolean = false) => {
  1024. equipLoading.value = true
  1025. try {
  1026. const params = {
  1027. pageNo: equipQueryParams.value.pageNo,
  1028. pageSize: equipQueryParams.value.pageSize,
  1029. orderId: orderDetail.value?.id,
  1030. equipCode: equipQueryParams.value.equipCode,
  1031. productNo: equipQueryParams.value.productNo,
  1032. relateDepartment: equipQueryParams.value.relateDepartment,
  1033. equipDistrict: equipQueryParams.value.equipDistrict,
  1034. equipStreet: equipQueryParams.value.equipStreet,
  1035. typeList: equipQueryParams.value.typeList || [],
  1036. nextDate: equipQueryParams.value.nextDate || [],
  1037. useStatus: equipQueryParams.value.useStatus && equipQueryParams.value.useStatus.length > 0
  1038. ? equipQueryParams.value.useStatus.map((item) => +item)
  1039. : [],
  1040. unitName: formData.value.useUnitName.name,
  1041. }
  1042. // 移除空值
  1043. Object.keys(params).forEach(key => {
  1044. if (params[key] === '' || params[key] === undefined || params[key] === null) {
  1045. delete params[key]
  1046. }
  1047. // 处理空数组
  1048. if (Array.isArray(params[key]) && params[key].length === 0) {
  1049. delete params[key]
  1050. }
  1051. })
  1052. // 调用后端API获取数据
  1053. const res = await BoilerAppointmentConfirmOrderApi.getAppointmentConfirmOrderEquipmentList(params)
  1054. equipList.value = res.list
  1055. equipTotal.value = res.total
  1056. // 批量修改约检联系人后,申请单位约检联系人与手机号,报告接收人与手机号同步修改。若使用单位与申请单位一致时,也需进行同步修改
  1057. if(isUpdateContact && equipList.value.length > 0){
  1058. const { contact, contactPhone } = equipList.value[0]
  1059. formData.value.unitContact = contact
  1060. formData.value.unitPhone = contactPhone
  1061. formData.value.recipient = contact
  1062. formData.value.recipientPhone = contactPhone
  1063. if(formData.value.unitName.name === formData.value.useUnitName.name){
  1064. formData.value.useUnitContact = contact
  1065. formData.value.useUnitPhone = contactPhone
  1066. }
  1067. try {
  1068. // 组装提交数据
  1069. const submitData = {
  1070. id: orderDetail.value?.id,
  1071. unitContact: formData.value.unitContact,
  1072. unitPhone: formData.value.unitPhone,
  1073. recipient: formData.value.recipient,
  1074. recipientPhone: formData.value.recipientPhone,
  1075. useUnitContact: formData.value.useUnitContact,
  1076. useUnitPhone: formData.value.useUnitPhone,
  1077. }
  1078. await BoilerAppointmentConfirmOrderApi.saveAcceptOrder(submitData)
  1079. } catch (error) {
  1080. ElMessage.error('提交失败')
  1081. }
  1082. }
  1083. } finally {
  1084. equipLoading.value = false
  1085. }
  1086. }
  1087. const handleEquipCodeFn = (id?: number) => {
  1088. EquipContainerFormRef.value.open(id)
  1089. }
  1090. const resetEquipQuery = () => {
  1091. // 重置查询参数
  1092. equipQueryParams.value = {
  1093. pageNo: 1,
  1094. pageSize: 50,
  1095. equipDistrict: undefined,
  1096. equipStreet: undefined,
  1097. equipCode: '',
  1098. productNo: '',
  1099. relateDepartment: '',
  1100. typeList: [],
  1101. nextDate: [],
  1102. useStatus: [],
  1103. }
  1104. // 重置区域-街道映射
  1105. areaStreetMap.value.clear()
  1106. // 重置日期相关字段
  1107. daterange.value = []
  1108. month.value = ''
  1109. datePickerType.value = 'month'
  1110. // 重新查询数据
  1111. handleEquipQuery()
  1112. }
  1113. const handleEquipSelectionChange = (selection) => {
  1114. // 实现设备选择逻辑
  1115. selectedEquips.value = selection
  1116. }
  1117. const handleEquipSortChange = (sort) => {
  1118. // 实现设备排序逻辑
  1119. }
  1120. /** 处理区域变化 */
  1121. const handleAreaChange = (areas: number[]) => {
  1122. // 获取移除的区域(通过比较之前的区域列表和现在的区域列表)
  1123. const prevAreas = Array.from(areaStreetMap.value.keys())
  1124. const removedAreas = prevAreas.filter(area => !areas.includes(area))
  1125. // 移除取消选择的区域下的街道
  1126. if (removedAreas.length > 0) {
  1127. const currentStreets = equipQueryParams.value.equipStreet || []
  1128. removedAreas.forEach(areaId => {
  1129. const streetsToRemove = areaStreetMap.value.get(areaId) || []
  1130. // 从当前选中的街道中移除这些街道
  1131. equipQueryParams.value.equipStreet = currentStreets.filter(
  1132. streetId => !streetsToRemove.includes(streetId)
  1133. )
  1134. // 从映射中移除该区域
  1135. areaStreetMap.value.delete(areaId)
  1136. })
  1137. }
  1138. }
  1139. /** 处理区域清空 */
  1140. const handleAreaClear = () => {
  1141. // 清空所有选中的街道
  1142. equipQueryParams.value.equipStreet = []
  1143. // 清空区域-街道映射
  1144. areaStreetMap.value.clear()
  1145. }
  1146. /** 处理街道变化 */
  1147. const handleStreetChange = (streets: number[], areaId: number) => {
  1148. // 更新区域-街道映射
  1149. if (equipQueryParams.value.equipDistrict?.includes(areaId)) {
  1150. areaStreetMap.value.set(areaId, streets)
  1151. }
  1152. }
  1153. /** 处理街道清空 */
  1154. const handleStreetClear = () => {
  1155. // 清空所有区域下的街道选择
  1156. areaStreetMap.value.clear()
  1157. }
  1158. /** 处理日期范围变化 */
  1159. const handleDateChange = (val: [string, string] | null) => {
  1160. daterange.value = val || []
  1161. equipQueryParams.value.nextDate = val
  1162. ? [
  1163. dayjs(val[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss'),
  1164. dayjs(val[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
  1165. ]
  1166. : []
  1167. }
  1168. /** 处理月份变化 */
  1169. const handleMonthChange = (val: string | null) => {
  1170. if (!val) {
  1171. equipQueryParams.value.nextDate = []
  1172. return
  1173. }
  1174. const date = dayjs(val)
  1175. equipQueryParams.value.nextDate = [
  1176. date.startOf('month').format('YYYY-MM-DD HH:mm:ss'),
  1177. date.endOf('month').format('YYYY-MM-DD HH:mm:ss')
  1178. ]
  1179. month.value = val
  1180. }
  1181. // 监听日期类型变化
  1182. watch(datePickerType, (newVal) => {
  1183. // 清空日期相关字段
  1184. daterange.value = []
  1185. month.value = ''
  1186. equipQueryParams.value.nextDate = []
  1187. })
  1188. /** 拒绝约检 */
  1189. const handleRejectEquip = async () => {
  1190. if (selectedEquips.value.length === 0) {
  1191. ElMessage.warning('请选择要拒绝约检的设备')
  1192. return
  1193. }
  1194. rejectForm.value.reasonDict = ''
  1195. rejectForm.value.reason = ''
  1196. rejectDialogVisible.value = true
  1197. }
  1198. /** 处理批量修改 */
  1199. const handleBatchEditFn = () => {
  1200. if (selectedEquips.value.length === 0) {
  1201. ElMessage.warning('请至少选择一条设备数据')
  1202. return
  1203. }
  1204. batchEditFormRef.value.open(selectedEquips.value, '1')
  1205. }
  1206. /** 批量修改地址 */
  1207. const handleBatchEditLocationFn = () => {
  1208. if (selectedEquips.value.length === 0) {
  1209. ElMessage.warning('请先选择设备')
  1210. return
  1211. }
  1212. const firstEquip = selectedEquips.value[0]
  1213. batchEditLocationFormData.value.areaType = firstEquip.areaType || ''
  1214. batchEditLocationFormData.value.equipDistrict = firstEquip.equipDistrict || ''
  1215. batchEditLocationFormData.value.equipStreet = firstEquip.equipStreet || ''
  1216. batchEditLocationVisible.value = true
  1217. }
  1218. const changeArea = (areaType: 'all' | 'gz') => {
  1219. batchEditLocationFormData.value.areaType = areaType
  1220. }
  1221. const changeAddress = () => {
  1222. batchEditLocationFormData.value.equipStreet = null as any
  1223. setTimeout(() => {
  1224. batchEditLocationFormRef.value?.clearValidate(['equipStreet'])
  1225. }, 0)
  1226. }
  1227. const batchEditLocationSubmitForm = async () => {
  1228. if (!batchEditLocationFormRef.value) return
  1229. const valid = await batchEditLocationFormRef.value.validate()
  1230. if (!valid) return
  1231. batchEditLocationLoading.value = true
  1232. try {
  1233. const data = {
  1234. ...batchEditLocationFormData.value,
  1235. ids: selectedEquips.value.map((item: any) => item.id)
  1236. }
  1237. await EquipBoilerSchedulingApi.batchUpdateDistrict(data)
  1238. ElMessage.success('修改成功')
  1239. handleEquipQuery()
  1240. batchEditLocationVisible.value = false
  1241. } catch {
  1242. ElMessage.error('修改失败')
  1243. } finally {
  1244. batchEditLocationLoading.value = false
  1245. }
  1246. }
  1247. /** 确认拒绝约检 */
  1248. const handleRejectConfirm = async (type) => {
  1249. if (!rejectForm.value.reasonDict) {
  1250. ElMessage.warning('请选择拒绝原因')
  1251. return
  1252. }
  1253. if (rejectForm.value.reasonDict == '5' && !rejectForm.value.reason) {
  1254. ElMessage.warning('请输入说明')
  1255. return
  1256. }
  1257. const equipIds = selectedEquips.value.map(e => e.id)
  1258. const submitData = {
  1259. equipIds,
  1260. orderId: orderDetail.value?.id,
  1261. type,
  1262. reasonDict: rejectForm.value.reasonDict,
  1263. reason: rejectForm.value.reason,
  1264. orderNo: orderDetail.value?.appointmentNo,
  1265. checkType: orderDetail.value?.checkType
  1266. }
  1267. let alertText = ''
  1268. switch(type) {
  1269. case 100:
  1270. alertText = '上报市局'
  1271. break
  1272. case 200:
  1273. alertText = '拒绝约检'
  1274. break
  1275. case 300:
  1276. alertText = '无需上报'
  1277. break
  1278. default:
  1279. alertText = ''
  1280. }
  1281. rejectLoading.value = true
  1282. try {
  1283. // 调用api
  1284. const res = await BoilerAppointmentConfirmOrderApi.refuseAppointmentConfirmOrder(submitData)
  1285. ElMessage.success(alertText + '操作成功')
  1286. rejectLoading.value = false
  1287. // 提交成功后重置表单和关闭对话框
  1288. rejectForm.value.reason = ''
  1289. rejectForm.value.reasonDict = ''
  1290. rejectDialogVisible.value = false
  1291. handleEquipQuery() // 刷新设备列表
  1292. } catch (e) {
  1293. rejectLoading.value = false
  1294. ElMessage.error(alertText + '操作失败')
  1295. }
  1296. }
  1297. /** 添加设备 */
  1298. const handleAddEquip = () => {
  1299. addEquipVisible.value = true
  1300. }
  1301. /** 添加设备成功 */
  1302. const handleAddEquipSuccess = (selectedEquips) => {
  1303. ElMessage.success('添加设备成功')
  1304. // 更新设备列表
  1305. handleEquipQuery()
  1306. }
  1307. /** 生成受理单 */
  1308. const handleGenerateAcceptance = () => {
  1309. console.log('开始验证表单', formRef.value)
  1310. // 表单验证
  1311. if (!formRef.value) {
  1312. ElMessage.warning('表单引用获取失败')
  1313. return
  1314. }
  1315. // 手动触发表单验证
  1316. formRef.value.validate((valid, fields) => {
  1317. if (!valid) {
  1318. ElMessage.warning('请完善必填信息')
  1319. console.log('验证失败的字段:', fields)
  1320. return
  1321. }
  1322. // 检查排期时间和检验员
  1323. if (!formData.value.appointmentDate) {
  1324. ElMessage.warning('请选择约检时间')
  1325. return
  1326. }
  1327. if(!equipList.value.length){
  1328. ElMessage.warning('请添加设备')
  1329. return
  1330. }
  1331. // 二次确认
  1332. ElMessageBox.confirm(
  1333. '确认要生成受理单吗?提交后将无法修改。',
  1334. '操作确认',
  1335. {
  1336. confirmButtonText: '确认',
  1337. cancelButtonText: '取消',
  1338. type: 'warning'
  1339. }
  1340. ).then(async () => {
  1341. if(exceptionInfo.value.id){
  1342. await handleSaveException()
  1343. }
  1344. // 确认后提交
  1345. submitAcceptance()
  1346. }).catch(() => {
  1347. // 用户取消操作
  1348. console.log('用户取消操作')
  1349. })
  1350. })
  1351. }
  1352. /** 提交受理单 */
  1353. const submitAcceptance = async () => {
  1354. try {
  1355. let { unitCode='' } = formData.value;
  1356. loading.value = true
  1357. // 组装提交数据
  1358. const submitData: Record<string, any> = {
  1359. id: orderDetail.value?.id,
  1360. ...formData.value,
  1361. appointmentDate: formData.value.appointmentDate,
  1362. unitName: formData.value?.unitName?.name,
  1363. unitAddress: formData.value?.unitAddress,
  1364. unitCode,
  1365. unitContact: formData.value.unitContact,
  1366. unitContactDept: formData.value.unitContactDept,
  1367. unitPhone: formData.value.unitPhone,
  1368. equipDistrict: orderDetail.value?.equipDistrict,
  1369. equipStreet: orderDetail.value?.equipStreet,
  1370. zipCode: formData.value.zipCode,
  1371. checkType: orderDetail.value?.checkType,
  1372. equipType: orderDetail.value?.equipType,
  1373. equipMainType: orderDetail.value?.equipMainType,
  1374. deptId: orderDetail.value?.deptId,
  1375. email: formData.value.email,
  1376. mobile: formData.value.mobile,
  1377. remark: formData.value.remark,
  1378. isAttach: formData.value.isAttach,
  1379. sendType: formData.value.sendType,
  1380. vehicle: formData.value.vehicle,
  1381. feeType: formData.value.feeType,
  1382. acceptType: formData.value.acceptType,
  1383. actualAmount: formData.value.actualAmount,
  1384. serviceAmount: formData.value.serviceAmount,
  1385. shouldAmount: formData.value.shouldAmount,
  1386. reduceFee: formData.value.reduceFee,
  1387. useUnitName: formData.value?.useUnitName?.name,
  1388. useUnitId: formData.value?.useUnitName?.id,
  1389. teamList: selectedCheckers.value.reduce((acc, checker) => {
  1390. const existingTeam = acc.find(team => team.groupTeamId === checker.groupTeamId)
  1391. if (existingTeam) {
  1392. if (checker.isLeader) {
  1393. existingTeam.leaderId = checker.memberId
  1394. } else {
  1395. existingTeam.userIds.push(checker.memberId)
  1396. }
  1397. } else {
  1398. acc.push({
  1399. groupTeamId: checker.groupTeamId,
  1400. leaderId: checker.isLeader ? checker.memberId : '',
  1401. userIds: checker.isLeader ? [] : [checker.memberId]
  1402. })
  1403. }
  1404. return acc
  1405. }, []),
  1406. equipIds: equipList.value.map(e => e.id),
  1407. }
  1408. if(exceptionInfo.value.id){
  1409. submitData.boilerOrderExceptionSaveReqVO = cloneDeep({
  1410. ...exceptionInfo.value,
  1411. adjustEffectiveDate: unref(exceptionInfo).adjustEffectiveDate && unref(exceptionInfo).adjustEffectiveDate.split('-').map(item=>Number(item)),
  1412. })
  1413. }
  1414. // console.log('submitData:', submitData);
  1415. // 调用API提交受理单
  1416. await BoilerAppointmentConfirmOrderApi.submitAppointmentConfirmOrder(submitData);
  1417. emitter.emit('refresh-list')
  1418. ElMessage.success('受理单生成成功')
  1419. handleClose()
  1420. } catch (error) {
  1421. console.error('生成受理单失败:', error)
  1422. ElMessage.error('生成受理单失败')
  1423. } finally {
  1424. loading.value = false
  1425. }
  1426. }
  1427. /** 保存约检单 */
  1428. const handleSave = () => {
  1429. // console.log('开始验证表单', formRef.value)
  1430. // 表单验证
  1431. if (!formRef.value) return ElMessage.warning('表单引用获取失败')
  1432. // 手动触发表单验证
  1433. formRef.value.validate((valid, fields) => {
  1434. if (!valid) return ElMessage.warning('请完善必填信息')
  1435. // 检查排期时间
  1436. if (!formData.value.appointmentDate) return ElMessage.warning('请选择约检时间')
  1437. // 二次确认
  1438. ElMessageBox.confirm(
  1439. '确认保存吗?',
  1440. '操作确认',
  1441. {
  1442. confirmButtonText: '确认',
  1443. cancelButtonText: '取消',
  1444. type: 'warning'
  1445. }
  1446. ).then(async () => {
  1447. if(exceptionInfo.value.id){
  1448. await handleSaveException()
  1449. }
  1450. saveAcceptance()
  1451. })
  1452. })
  1453. }
  1454. const saveAcceptance = async () => {
  1455. try {
  1456. loading.value = true
  1457. // 组装提交数据
  1458. let submitData = {
  1459. id: orderDetail.value?.id,
  1460. ...formData.value,
  1461. equipType: orderDetail.value?.equipType,
  1462. equipNum: orderDetail.value?.equipNum,
  1463. unitName: orderDetail.value?.unitName?.name,
  1464. warningDay: orderDetail.value?.warningDay,
  1465. useUnitName: formData.value?.useUnitName?.name,
  1466. useUnitId: formData.value?.useUnitName?.id,
  1467. teamList: formData.value.teamList.reduce((acc: any[], item: any) => {
  1468. const existingGroup = acc.find(
  1469. group => group.groupTeamId === item.groupTeamId
  1470. );
  1471. if (existingGroup) {
  1472. // 避免重复添加相同的 userId,且不添加 leaderId
  1473. if (!item.isLeader && !existingGroup.userIds.includes(item.memberId)) {
  1474. existingGroup.userIds.push(item.memberId);
  1475. }
  1476. } else {
  1477. acc.push({
  1478. groupTeamId: item.groupTeamId,
  1479. leaderId: item.isLeader ? item.memberId : '',
  1480. userIds: item.isLeader ? [] : [item.memberId]
  1481. });
  1482. }
  1483. return acc;
  1484. }, [])
  1485. }
  1486. // 调用API保存
  1487. const res2 = await BoilerAppointmentConfirmOrderApi.saveAcceptOrder(submitData)
  1488. if(res2) {
  1489. ElMessage.success('保存成功')
  1490. emitter.emit('refresh-list')
  1491. handleClose()
  1492. }
  1493. } catch (error) {
  1494. ElMessage.error('保存失败')
  1495. } finally {
  1496. loading.value = false
  1497. }
  1498. }
  1499. // 手动输入单位
  1500. const useInputUseUnitName = ref(false)
  1501. const useInputUnitName = ref(false)
  1502. // 清空与单位相关字段的函数
  1503. const clearUnitFields = () => {
  1504. formData.value.unitName.name = ''
  1505. formData.value.socialCreditCode = ''
  1506. formData.value.unitAddress = ''
  1507. formData.value.unitContact = ''
  1508. formData.value.unitPhone = ''
  1509. formData.value.recipient = ''
  1510. formData.value.recipientPhone = ''
  1511. }
  1512. // 监听 useInputUnitName 变化
  1513. watch(useInputUnitName, (newValue) => {
  1514. if (newValue) {
  1515. clearUnitFields()
  1516. }
  1517. })
  1518. // 清空与使用单位相关的字段
  1519. const clearUseUnitFields = () => {
  1520. formData.value.useUnitName.name = ''
  1521. formData.value.useUnitSocialCreditCode = ''
  1522. formData.value.useUnitAddress = ''
  1523. formData.value.useUnitZipcode = ''
  1524. formData.value.useUnitContact = ''
  1525. formData.value.useUnitPhone = ''
  1526. }
  1527. // 监听 useInputUseUnitName 变化
  1528. watch(useInputUseUnitName, (newValue) => {
  1529. if (newValue) {
  1530. clearUseUnitFields()
  1531. }
  1532. })
  1533. // 申请单位名称 change
  1534. const handleChangeUnit = async (unitInfo:any) => {
  1535. formData.value.socialCreditCode = unitInfo.socialCreditCode;
  1536. formData.value.unitAddress = unitInfo.addr
  1537. formData.value.zipCode = unitInfo.post
  1538. formData.value.useUnitId = unitInfo.id
  1539. if(orderDetail.value?.checkType != 200){
  1540. formData.value.feeNature = unitInfo.isExempt === '1' ? `${PressureFeeNature.SMZFC}` : `${PressureFeeNature.BSMZFC}`
  1541. }
  1542. // 获取单位默认联系人
  1543. const {list: unitDefaultContact} = await getUnitContacts({
  1544. pageNo: 1,
  1545. pageSize: 10,
  1546. unitId: unitInfo.id,
  1547. isDefault: '1'
  1548. })
  1549. if(unitDefaultContact && unitDefaultContact?.length > 0) {
  1550. formData.value.unitContact = unitDefaultContact[0].contactName
  1551. formData.value.unitPhone = unitDefaultContact[0].contactPhone
  1552. formData.value.recipient = unitDefaultContact[0].contactName
  1553. formData.value.recipientPhone = unitDefaultContact[0].contactPhone
  1554. }
  1555. }
  1556. // 使用单位名称 change
  1557. const handleChangeUseUnit = async (unitInfo:any) => {
  1558. console.log('使用单位名称 change:', unitInfo)
  1559. formData.value.useUnitSocialCreditCode = unitInfo.socialCreditCode;
  1560. formData.value.useUnitAddress = unitInfo.addr
  1561. formData.value.useUnitZipcode = unitInfo.post
  1562. // 获取单位默认联系人
  1563. const {list: unitDefaultContact} = await getUnitContacts({
  1564. pageNo: 1,
  1565. pageSize: 10,
  1566. unitId: unitInfo.id,
  1567. isDefault: '1'
  1568. })
  1569. if(unitDefaultContact && unitDefaultContact?.length > 0) {
  1570. formData.value.useUnitContact = unitDefaultContact[0].contactName
  1571. formData.value.useUnitPhone = unitDefaultContact[0].contactPhone
  1572. }
  1573. await handleEquipQuery()
  1574. }
  1575. // 使用单位名称input框失焦 & 回车按钮进行查询
  1576. const handleChangeUseUnitInput = () => {
  1577. handleEquipQuery()
  1578. }
  1579. /** 关闭 */
  1580. const handleClose = () => {
  1581. tagsViewStore.closeSelectedTag(route)
  1582. router.push({
  1583. name: 'OrderConfirm',
  1584. })
  1585. }
  1586. // 监听表单区域相关字段变化,更新areaDisplay
  1587. watch([() => formData.value.equipDistrictName, () => formData.value.equipStreetName], () => {
  1588. formData.value.areaDisplay = areaDisplay.value
  1589. })
  1590. const exceptionInfo = ref<Record<string, any>>({})
  1591. const getExceptionItem = (field: string, fieldAttr: string)=>{
  1592. const fileUrl = exceptionInfo.value[fieldAttr] && buildFileUrl(exceptionInfo.value[fieldAttr])
  1593. const fileName = exceptionInfo.value[field]
  1594. if(fileUrl) {
  1595. return (
  1596. <>
  1597. <div class="flex items-center w-full p-l-10px p-r-10px hover:bg-gray-100 rounded-6px">
  1598. {/* <el-tooltip content={fileName}> */}
  1599. <span class="flex-1 text-ellipsis overflow-hidden whitespace-nowrap">{fileName}</span>
  1600. {/* </el-tooltip> */}
  1601. <div class="ml-10px">
  1602. <el-link href={fileUrl} underline={false} download target="_blank" type="primary">下载</el-link>
  1603. </div>
  1604. <div class="ml-10px">
  1605. <el-button link type="danger" onClick={()=>handleRemove(field, fieldAttr)}>删除</el-button>
  1606. </div>
  1607. </div>
  1608. </>
  1609. )
  1610. } else {
  1611. return (
  1612. <el-button type="primary" onClick={()=>handleOpenFileUploadModal(field, fieldAttr)}>
  1613. <Icon icon="ep:upload-filled" />
  1614. <span>附件上传</span>
  1615. </el-button>
  1616. )
  1617. }
  1618. }
  1619. const addExceptionInfo = () => {
  1620. const orderId = formData.value.id || route.query?.id;
  1621. if(!orderId) {
  1622. // ElMessage.error('请先保存订单')
  1623. return
  1624. }
  1625. BoilerAppointmentConfirmOrderApi.createExceptionInfo({
  1626. orderId: formData.value.id || route.query?.id,
  1627. orderType: 100,
  1628. }).then((res) => {
  1629. if(res) {
  1630. ElMessage.success('生成成功')
  1631. handleGetExceptionInfo(res)
  1632. }
  1633. }).catch((error)=>{
  1634. ElMessage.error(error)
  1635. })
  1636. }
  1637. const deleteExceptionInfo = () => {
  1638. ElMessageBox.confirm('确定删除异常单吗?', '提示', {
  1639. confirmButtonText: '确定',
  1640. cancelButtonText: '取消',
  1641. type: 'warning',
  1642. }).then(() => {
  1643. BoilerAppointmentConfirmOrderApi.deleteExceptionInfo(exceptionInfo.value.id).then(res=>{
  1644. if(res) {
  1645. ElMessage.success('删除成功')
  1646. exceptionInfo.value = {}
  1647. }
  1648. })
  1649. }).catch(() => {
  1650. // 取消删除
  1651. });
  1652. }
  1653. // 更新异常信息
  1654. const handleSaveException=()=>{
  1655. return new Promise((resolve, reject)=>{
  1656. const { adjustEffectiveDate } = unref(exceptionInfo)
  1657. const params = {
  1658. ...exceptionInfo.value,
  1659. adjustEffectiveDate: adjustEffectiveDate && adjustEffectiveDate.split('-').map(item=>Number(item)),
  1660. }
  1661. BoilerAppointmentConfirmOrderApi.updateExceptionInfo(params).then(res=>{
  1662. resolve(res)
  1663. }).catch((error)=>{
  1664. reject(error)
  1665. })
  1666. })
  1667. }
  1668. const getExceptionInfoList = () => {
  1669. BoilerAppointmentConfirmOrderApi.getExceptionInfoList({
  1670. orderId: formData.value.id || route.query?.id,
  1671. }).then(res=>{
  1672. console.log('getExceptionInfoList:',res)
  1673. })
  1674. }
  1675. const handleGetExceptionInfo = (id: string) => {
  1676. BoilerAppointmentConfirmOrderApi.getExceptionInfo(id).then((res) => {
  1677. if(res) exceptionInfo.value = {
  1678. ...res,
  1679. adjustEffectiveDate: res.adjustEffectiveDate?.join('-')
  1680. }
  1681. }).catch((error)=>{
  1682. console.log(error, '-----error--->')
  1683. ElMessage.error(error)
  1684. })
  1685. }
  1686. const fileUploadModalRef = ref<InstanceType<typeof FileUploadModal>>();
  1687. const currentUploadMap = reactive({
  1688. field: '',
  1689. fieldAttr: '',
  1690. })
  1691. const handleOpenFileUploadModal = (type: string, attach: string) => {
  1692. currentUploadMap.field = type
  1693. currentUploadMap.fieldAttr = attach
  1694. fileUploadModalRef.value?.open()
  1695. }
  1696. const handleFileUploadSuccess = (fileInfo:{fileName: string, fileUrl: string}) => {
  1697. exceptionInfo.value[currentUploadMap.field] = fileInfo.fileName
  1698. exceptionInfo.value[currentUploadMap.fieldAttr] = fileInfo.fileUrl
  1699. console.log('handleFileUploadSuccess:', exceptionInfo.value)
  1700. }
  1701. const handleRemove = (type: string, attach: string) => {
  1702. exceptionInfo.value[type] = ''
  1703. exceptionInfo.value[attach] = ''
  1704. }
  1705. const formattedCheckers = computed(() => {
  1706. const teamList = formData.value.teamList
  1707. console.log("teamList",teamList)
  1708. if (!teamList || !Array.isArray(teamList) || teamList.length === 0) return []
  1709. const result: { id: string; label: string }[] = []
  1710. teamList.forEach((team: any, teamIndex: number) => {
  1711. if (team.isLeader) {
  1712. result.push({
  1713. id: `leader-${team.member.id || teamIndex}`,
  1714. label: `组长: ${team.member.nickname || ''}`
  1715. })
  1716. }else{
  1717. result.push({
  1718. id: `member-${team.member.id || teamIndex}`,
  1719. label: `${team.member.nickname || ''}`
  1720. })
  1721. }
  1722. })
  1723. return result
  1724. })
  1725. const fillNullOrEmptyValWithDefaultVal = (obj, key, defaultValue) => {
  1726. if(obj[key] == null) {
  1727. obj[key] = defaultValue
  1728. return
  1729. }
  1730. if(typeof obj[key] === 'string' && obj[key] === '') {
  1731. obj[key] = defaultValue
  1732. }
  1733. }
  1734. const fillDefaultVal = async () => {
  1735. const [equipBoiler, dept] = await Promise.all([
  1736. EquipBoilerApi.getEquipBoiler(equipList.value[0].id),
  1737. getDept(formData.value.deptId)
  1738. ])
  1739. if(equipBoiler) {
  1740. fillNullOrEmptyValWithDefaultVal(formData.value, 'unitContact', equipBoiler?.contact || '')
  1741. fillNullOrEmptyValWithDefaultVal(formData.value, 'unitPhone', equipBoiler?.contactPhone || '')
  1742. fillNullOrEmptyValWithDefaultVal(formData.value, 'email', equipBoiler?.contactEmail || '')
  1743. // fillNullOrEmptyValWithDefaultVal(formData.value, 'recipient', equipBoiler?.recipient || '')
  1744. // fillNullOrEmptyValWithDefaultVal(formData.value, 'recipientPhone', equipBoiler?.recipientPhone || '')
  1745. // fillNullOrEmptyValWithDefaultVal(formData.value, 'recipientEmail', equipBoiler?.recipientEmail || '')
  1746. // fillNullOrEmptyValWithDefaultVal(formData.value, 'payerContactName', equipBoiler?.payment || '')
  1747. // fillNullOrEmptyValWithDefaultVal(formData.value, 'payerContact', equipBoiler?.paymentPhone || '')
  1748. // fillNullOrEmptyValWithDefaultVal(formData.value, 'payerMail', equipBoiler?.paymentEmail || '')
  1749. }
  1750. if(dept) {
  1751. fillNullOrEmptyValWithDefaultVal(formData.value, 'deptPhone', dept?.phone || '')
  1752. }
  1753. }
  1754. // 页面加载时获取详情
  1755. onMounted(async () => {
  1756. await getDetail()
  1757. if(route.query?.id) {
  1758. await handleEquipQuery()
  1759. // await handleGetExceptionInfo('eb9a57fe2ed98a45e1a892aef4cc13f0')
  1760. }
  1761. await fillDefaultVal()
  1762. })
  1763. </script>
  1764. <style lang="scss" scoped>
  1765. .form-group {
  1766. &:not(:last-child) {
  1767. margin-bottom: 16px;
  1768. }
  1769. &-title {
  1770. color: #606266;
  1771. font-size: 13px;
  1772. font-weight: 500;
  1773. margin-bottom: 0;
  1774. }
  1775. }
  1776. .p-3 {
  1777. padding-top: 0;
  1778. }
  1779. .check-info-label-title {
  1780. width: 100%;
  1781. line-height: 32px;
  1782. display: flex;
  1783. align-items: center;
  1784. margin-bottom: 12px;
  1785. &::before {
  1786. content: '';
  1787. display: inline-block;
  1788. width: 4px;
  1789. height: 16px;
  1790. background: var(--el-color-primary);
  1791. margin-right: 8px;
  1792. }
  1793. }
  1794. .feeDate_box {
  1795. color: #606266;
  1796. :deep(.el-input-number) {
  1797. width: 120px !important;
  1798. }
  1799. }
  1800. .unit-form-item {
  1801. :deep(.el-form-item__content) {
  1802. display: flex;
  1803. align-items: center;
  1804. flex-wrap: nowrap;
  1805. .el-button {
  1806. margin-left: 8px;
  1807. }
  1808. }
  1809. }
  1810. .unit-name {
  1811. display: flex;
  1812. align-items: center;
  1813. padding: 0 0 8px;
  1814. .label {
  1815. width: 90px;
  1816. color: #606266;
  1817. font-size: 13px;
  1818. text-align: right;
  1819. padding-right: 12px;
  1820. }
  1821. .value {
  1822. flex: 1;
  1823. font-size: 14px;
  1824. color: #303133;
  1825. }
  1826. }
  1827. :deep(.el-form) {
  1828. .el-form-item {
  1829. margin-bottom: 12px;
  1830. align-items: center;
  1831. &__label {
  1832. height: auto;
  1833. font-size: 13px;
  1834. line-height: 20px;
  1835. color: #606266;
  1836. padding-right: 8px;
  1837. }
  1838. .el-date-editor.el-input, .el-input-number {
  1839. width: 100%;
  1840. .el-input__inner {
  1841. text-align: left;
  1842. }
  1843. }
  1844. &.actualAmountFormItem {
  1845. .el-form-item__content {
  1846. display: flex;
  1847. .el-input-number {
  1848. width: 300px;
  1849. }
  1850. }
  1851. }
  1852. }
  1853. }
  1854. .reject-dialog {
  1855. :deep(.el-dialog__header) {
  1856. margin: 0;
  1857. padding: 16px 20px;
  1858. border-bottom: 1px solid #dcdfe6;
  1859. }
  1860. :deep(.el-dialog__body) {
  1861. padding: 20px;
  1862. }
  1863. .reject-content {
  1864. .equip-list {
  1865. margin-bottom: 20px;
  1866. color: #606266;
  1867. line-height: 1.6;
  1868. }
  1869. .check-type {
  1870. color: #606266;
  1871. }
  1872. .reject-reason {
  1873. .reason-label {
  1874. color: #606266;
  1875. }
  1876. :deep(.el-textarea__inner) {
  1877. background-color: #f5f7fa;
  1878. border-color: #e4e7ed;
  1879. &:focus {
  1880. background-color: #fff;
  1881. }
  1882. }
  1883. }
  1884. }
  1885. .reject-footer {
  1886. margin-top: 20px;
  1887. display: flex;
  1888. align-items: center;
  1889. justify-content: space-between;
  1890. .time-tag {
  1891. :deep(.el-tag) {
  1892. height: 32px;
  1893. line-height: 30px;
  1894. font-size: 16px;
  1895. padding: 0 12px;
  1896. }
  1897. }
  1898. .action-buttons {
  1899. .el-button + .el-button {
  1900. margin-left: 12px;
  1901. }
  1902. }
  1903. }
  1904. }
  1905. </style>