pipeDetail.vue 69 KB

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