pipeDetail.vue 82 KB

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