pipeDetail.vue 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304
  1. <template>
  2. <!-- 受检单位基本信息 - 始终展开 -->
  3. <div class="plan-section mb-4">
  4. <div class="section-title">
  5. <span>受检单位基本信息</span>
  6. </div>
  7. <div class="mb-[5px]">
  8. <el-button type="primary" @click="handleUnitCodeFn(unitInfo.id)">工商信息</el-button>
  9. <el-descriptions :column="3" border class="flex-1 mt-[10px]">
  10. <el-descriptions-item label="单位名称">{{ unitInfo.name || '-' }}</el-descriptions-item>
  11. <el-descriptions-item label="登记状态">{{ unitInfo.regstateCn || '-' }}</el-descriptions-item>
  12. <el-descriptions-item label="市场主体类型">{{ unitInfo.enterpriseType || '-' }}</el-descriptions-item>
  13. <el-descriptions-item label="单位地址">{{ unitInfo.addr || '-' }}</el-descriptions-item>
  14. </el-descriptions>
  15. </div>
  16. </div>
  17. <div class="plan-section mb-4">
  18. <div class="section-title">
  19. <span>设备信息</span>
  20. </div>
  21. <!-- 搜索工作栏 -->
  22. <ContentWrap>
  23. <section class="flex gap-2">
  24. <el-form
  25. class="flex-1"
  26. :model="queryParams"
  27. ref="queryFormRef"
  28. :inline="true"
  29. label-width="135px"
  30. >
  31. <!-- 基本信息查询部分 -->
  32. <el-row :gutter="24">
  33. <el-col :span="8">
  34. <el-form-item class="!w-full !mr-0px" label="区域" prop="equipDistrict">
  35. <AreaSelect
  36. v-model="queryParams.equipDistrict"
  37. placeholder="请选择区域"
  38. class="!w-full area-select"
  39. multiple
  40. collapse-tags
  41. collapse-tags-tooltip
  42. :clearable="true"
  43. :area-type="queryParams.areaType"
  44. @clear="handleAreaClear"
  45. @change="handleAreaChange"
  46. />
  47. </el-form-item>
  48. </el-col>
  49. <el-col :span="8">
  50. <el-form-item class="!w-full !mr-0px" label="街道" prop="equipStreet">
  51. <StreetSelect
  52. v-model="queryParams.equipStreet"
  53. :district-ids="queryParams.equipDistrict"
  54. placeholder="请选择街道"
  55. multiple
  56. collapse-tags
  57. collapse-tags-tooltip
  58. :clearable="true"
  59. @clear="handleStreetClear"
  60. @change="handleStreetChange"
  61. />
  62. </el-form-item>
  63. </el-col>
  64. <!-- <el-col :span="8">-->
  65. <!-- <el-form-item class="!w-full !mr-0px" label="设备注册代码" prop="equipCode">-->
  66. <!-- <el-input-->
  67. <!-- v-model="queryParams.equipCode"-->
  68. <!-- placeholder="请输入设备注册代码"-->
  69. <!-- clearable-->
  70. <!-- @keyup.enter="handleQuery"-->
  71. <!-- />-->
  72. <!-- </el-form-item>-->
  73. <!-- </el-col>-->
  74. <!-- <el-col :span="8">
  75. <el-form-item
  76. class="!w-full !mr-0px"
  77. label="社会统一信用代码"
  78. prop="socialCreditCode"
  79. >
  80. <el-input
  81. class="!w-full"
  82. v-model="queryParams.socialCreditCode"
  83. placeholder="请输入社会统一信用代码"
  84. clearable
  85. />
  86. </el-form-item>
  87. </el-col> -->
  88. <!-- <el-col :span="8">
  89. <el-form-item class="!w-full !mr-0px" label="使用证编号" prop="useCertCode">
  90. <el-input
  91. class="!w-full"
  92. v-model="queryParams.useCertCode"
  93. placeholder="请输入使用证编号"
  94. clearable
  95. />
  96. </el-form-item>
  97. </el-col> -->
  98. <ElCollapseTransition v-if="isSearchExpanded">
  99. <el-col :span="8">
  100. <el-form-item class="!w-full !mr-0px" label="临检时间" prop="checkDate">
  101. <div class="w-full flex gap-10px">
  102. <el-select v-model="datePickerType" class="!w-[100px]">
  103. <el-option label="时间段" value="daterange" />
  104. <el-option label="月份" value="month" />
  105. </el-select>
  106. <el-date-picker
  107. v-if="datePickerType === 'daterange'"
  108. v-model="daterange"
  109. type="daterange"
  110. value-format="YYYY-MM-DD HH:mm:ss"
  111. start-placeholder="开始日期"
  112. end-placeholder="结束日期"
  113. class="flex-1"
  114. />
  115. <!-- @change="handleDateChange" -->
  116. <el-date-picker
  117. v-else
  118. v-model="month"
  119. type="month"
  120. value-format="YYYY-MM"
  121. placeholder="选择月份"
  122. class="flex-1"
  123. />
  124. <!-- @change="handleMonthChange" -->
  125. </div>
  126. </el-form-item>
  127. </el-col>
  128. </ElCollapseTransition>
  129. <ElCollapseTransition v-if="isSearchExpanded">
  130. <el-col :span="8">
  131. <el-form-item class="!w-full !mr-0px" label="部门" prop="relateDepartment">
  132. <DeptSelect
  133. class="!w-full"
  134. v-model="queryParams.relateDepartment"
  135. placeholder="请选择部门"
  136. clearable
  137. />
  138. </el-form-item>
  139. </el-col>
  140. </ElCollapseTransition>
  141. <ElCollapseTransition v-if="isSearchExpanded">
  142. <el-col :span="8">
  143. <el-form-item class="!w-full !mr-0px" label="使用状态" prop="useStatus">
  144. <el-select
  145. v-model="queryParams.useStatus"
  146. placeholder="选择使用状态"
  147. clearable
  148. collapse-tags
  149. collapse-tags-tooltip
  150. >
  151. <el-option
  152. v-for="dict in getStrDictOptions(DICT_TYPE.PIPE_USE_STATUS)"
  153. :key="dict.value"
  154. :label="dict.label"
  155. :value="dict.value"
  156. />
  157. </el-select>
  158. </el-form-item>
  159. </el-col>
  160. </ElCollapseTransition>
  161. <ElCollapseTransition v-if="isSearchExpanded">
  162. <el-col :span="12">
  163. <el-form-item class="!w-full !mr-0px" label="管道归类" prop="typeList">
  164. <el-checkbox-group
  165. v-model="queryParams.typeList"
  166. class="flex flex-wrap gap-2"
  167. @change="handleTypeListChange"
  168. >
  169. <el-checkbox
  170. v-for="dict in containerTypeOptions"
  171. :key="dict.value"
  172. :label="dict.label"
  173. :value="dict.value"
  174. />
  175. </el-checkbox-group>
  176. </el-form-item>
  177. </el-col>
  178. </ElCollapseTransition>
  179. </el-row>
  180. </el-form>
  181. <div class="flex-[0_0_260px] flex items-start">
  182. <!-- 操作按钮 -->
  183. <el-button type="primary" @click="handleQuery">
  184. <Icon icon="ep:search" class="mr-5px" /> 搜索
  185. </el-button>
  186. <el-button @click="resetQuery">
  187. <Icon icon="ep:refresh" class="mr-5px" /> 重置
  188. </el-button>
  189. <el-button link class="!h-[32px] flex" @click="isSearchExpanded = !isSearchExpanded">
  190. <el-icon>
  191. <ArrowUp v-if="isSearchExpanded" />
  192. <ArrowDown v-else />
  193. </el-icon>
  194. {{ isSearchExpanded ? '收起' : '展开' }}
  195. </el-button>
  196. </div>
  197. </section>
  198. </ContentWrap>
  199. <!-- 列表 -->
  200. <ContentWrap>
  201. <el-row class="mb-2">
  202. <!-- <el-button
  203. type="primary"
  204. @click="() => handleBatchSchedule('regular')"
  205. :disabled="selectedRows.length === 0"
  206. >
  207. <Icon icon="ep:calendar" class="mr-5px" /> 定期约检
  208. </el-button>
  209. <el-button
  210. type="primary"
  211. @click="() => handleBatchSchedule('year')"
  212. :disabled="selectedRows.length === 0"
  213. >
  214. <Icon icon="ep:calendar" class="mr-5px" /> 年度约检
  215. </el-button>
  216. <el-button
  217. type="primary"
  218. @click="() => handleBatchSchedule('expired')"
  219. :disabled="selectedRows.length === 0"
  220. >
  221. <Icon icon="ep:calendar" class="mr-5px" /> 超年限约检
  222. </el-button>
  223. <el-button
  224. type="primary"
  225. @click="() => handleBatchSchedule('')"
  226. :disabled="selectedRows.length === 0"
  227. >
  228. <Icon icon="ep:calendar" class="mr-5px" /> 批量排期
  229. </el-button>-->
  230. <el-button
  231. type="primary"
  232. @click="handleBatchSchedule"
  233. :disabled="selectedRows.length === 0"
  234. >约检
  235. </el-button>
  236. <el-button type="primary" @click="handleBatchEditFn" :disabled="selectedRows.length === 0">
  237. <Icon icon="ep:edit" class="mr-5px" /> 批量修改约检联系人
  238. </el-button>
  239. <el-button type="primary" @click="handleBatchEditLocationFn" :disabled="selectedRows.length === 0">
  240. <Icon icon="ep:edit" class="mr-5px" /> 批量修改地址
  241. </el-button>
  242. <el-button type="primary" @click="() => handleToRoute('AcceptOrder1')">约检单</el-button>
  243. <el-button type="primary" @click="() => handleToRoute('TaskOrder')">任务单</el-button>
  244. </el-row>
  245. <el-table
  246. v-loading="loading"
  247. ref="mainTableRef"
  248. :data="list"
  249. border
  250. @selection-change="handleSelectionChange"
  251. @sort-change="handleSortChange"
  252. :row-key="(row) => row.id"
  253. :row-class-name="getMainRowClassName"
  254. @row-click="handleMainRowClick"
  255. @expand-change="handleExpandChange"
  256. :expand-row-keys="expandRowKeys"
  257. >
  258. <el-table-column type="selection" width="50" fixed="left"/>
  259. <el-table-column type="expand">
  260. <template #default="props">
  261. <div class="ml-15px mr-15px">
  262. <el-table
  263. :data="props.row.pipes" border
  264. :header-cell-style="{background: '#f5f7fa', color: '#606266'}"
  265. :ref="(el) => setDetailTableRef(el, props.row.id)"
  266. @selection-change="(selection) => handleDetailSelectionChange(selection, props.row)"
  267. :row-class-name="getRowClassName"
  268. class="inner-table"
  269. @row-click="handleRowClick"
  270. >
  271. <el-table-column type="selection" width="50" fixed="left"/>
  272. <el-table-column type="index" label="序号" width="60" align="center" :index="indexMethod1" />
  273. <el-table-column label="注册代码" prop="pipeRegCode" min-width="120" show-overflow-tooltip/>
  274. <el-table-column label="管道名称" prop="pipeName" min-width="120" show-overflow-tooltip/>
  275. <el-table-column label="管道编号" prop="pipeNo" min-width="120" show-overflow-tooltip/>
  276. <el-table-column label="管道级别" prop="pipeLevel" min-width="120" show-overflow-tooltip/>
  277. <el-table-column label="管道品种" prop="pipeType" min-width="120" show-overflow-tooltip/>
  278. <el-table-column label="长度" prop="pipeLength" min-width="100" show-overflow-tooltip/>
  279. <el-table-column label="管道材质" prop="pipeMaterial" min-width="120" show-overflow-tooltip/>
  280. <el-table-column label="材料标准" prop="materialStandard" min-width="120" show-overflow-tooltip/>
  281. <el-table-column label="定期安全状况等级" prop="legalSafetyStatusLevel" min-width="130" show-overflow-tooltip/>
  282. <el-table-column label="年度安全状况等级" prop="yearSafetyStatusLevel" min-width="130" show-overflow-tooltip/>
  283. <el-table-column label="下次定期检验" prop="nextLegalCheckDate" align="center" min-width="160" show-overflow-tooltip>
  284. <template #default="{ row }">
  285. <div>
  286. <div v-if="row.nextLegalCheckDate">
  287. <span
  288. class="text-xs">{{
  289. formatDate(row.nextLegalCheckDate, 'YYYY-MM-DD')
  290. }}</span>
  291. <div v-if="row.planLegalCheckDate" class="text-xs text-[#2D5FBD]">
  292. (排期时间:{{ row.planLegalCheckDate }})
  293. </div>
  294. </div>
  295. <span v-else>-</span>
  296. </div>
  297. </template>
  298. </el-table-column>
  299. <el-table-column label="下次年度检查" prop="nextYearCheckDate" align="center" min-width="160"
  300. show-overflow-tooltip>
  301. <template #default="{ row }">
  302. <div>
  303. <div v-if="row.nextYearCheckDate">
  304. <span
  305. class="text-xs">{{
  306. formatDate(row.nextYearCheckDate, 'YYYY-MM-DD')
  307. }}</span>
  308. <div v-if="row.planYearCheckDate" class="text-xs text-[#2D5FBD]">
  309. (排期时间:{{ row.planYearCheckDate }})
  310. </div>
  311. </div>
  312. <span v-else>-</span>
  313. </div>
  314. </template>
  315. </el-table-column>
  316. </el-table>
  317. </div>
  318. </template>
  319. </el-table-column>
  320. <el-table-column type="index" label="序号" width="60" align="center" :index="indexMethod" />
  321. <el-table-column
  322. label="工程号"
  323. align="center"
  324. prop="projectNo"
  325. min-width="120"
  326. >
  327. <template #default="{ row }">
  328. <div
  329. v-if="row.projectNo"
  330. class="cursor-pointer"
  331. @click.stop="toggleExpand(row)"
  332. >
  333. <div class="flex items-center justify-center gap-1 schedule-link">
  334. <span class="text-xs color-blue">{{row.projectNo}}</span>
  335. </div>
  336. </div>
  337. </template>
  338. </el-table-column>
  339. <el-table-column label="工程名称"
  340. align="center"
  341. prop="projectName"
  342. min-width="120"
  343. show-overflow-tooltip
  344. />
  345. <el-table-column
  346. label="下次定期检验"
  347. align="center"
  348. prop="nextLegalCheckDate"
  349. min-width="140"
  350. sortable="custom"
  351. >
  352. <template #default="{ row }">
  353. <div
  354. v-if="row.nextLegalCheckDate"
  355. >
  356. <!-- class="cursor-pointer">-->
  357. <!-- @click="handleSingleSchedule(row, 'year')" > -->
  358. <!-- <div class="flex items-center justify-center gap-1 schedule-link">-->
  359. <div class="flex items-center justify-center gap-1">
  360. <span class="schedule-date-link" @click.stop="handleSchedule(row,'100')">{{formatDate(row.nextLegalCheckDate, 'YYYY-MM-DD')}}</span>
  361. <!-- <Icon icon="ep:calendar" class="text-xs" />-->
  362. </div>
  363. <!-- <div v-if="row.yearRefuseReasonDict || row.yearRefuseReason" class="text-xs text-red-500 mt-1">
  364. (拒绝检验:{{
  365. getRefuseResonText(row.yearRefuseReasonDict, row.yearRefuseReason)
  366. }})
  367. </div>
  368. <div v-else-if="row.yearAcceptDate" class="text-xs text-[#3D9E5F] mt-1">
  369. (已受理:{{ formatArrayDate(row.yearAcceptDate) }})
  370. </div>
  371. <div v-else-if="row.yearAppointmentDate" class="text-xs text-[#FF9A3D] mt-1">
  372. (待约检:{{ formatArrayDate(row.yearAppointmentDate) }})
  373. </div>-->
  374. <div v-if="row.planLegalCheckDate" class="text-xs text-[#2D5FBD] mt-1">
  375. (排期时间:{{ row.planLegalCheckDate }})
  376. </div>
  377. </div>
  378. <span v-else>-</span>
  379. </template>
  380. </el-table-column>
  381. <el-table-column
  382. label="下次年度检查"
  383. align="center"
  384. prop="nextYearCheckDate"
  385. min-width="150"
  386. sortable="custom"
  387. >
  388. <template #default="{ row }">
  389. <div
  390. v-if="row.nextYearCheckDate"
  391. >
  392. <!-- class="cursor-pointer"> -->
  393. <!-- @click="handleSingleSchedule(row, 'expired')" > -->
  394. <!-- <div class="flex items-center justify-center gap-1 schedule-link">-->
  395. <div class="flex items-center justify-center gap-1">
  396. <span class="schedule-date-link" @click.stop="handleSchedule(row,'200')">{{ formatDate(row.nextYearCheckDate, 'YYYY-MM-DD') }}</span>
  397. <!-- <Icon icon="ep:calendar" class="text-xs" />-->
  398. </div>
  399. <!-- <div v-if="row.expiredReasonDict || row.expiredRefuseReason" class="text-xs text-red-500 mt-1">-->
  400. <!-- (拒绝检验:{{-->
  401. <!-- getRefuseResonText(row.expiredReasonDict, row.expiredRefuseReason)-->
  402. <!-- }})-->
  403. <!-- </div>-->
  404. <!-- <div v-else-if="row.expiredAcceptDate" class="text-xs text-[#3D9E5F] mt-1">-->
  405. <!-- (已受理:{{ formatArrayDate(row.expiredAcceptDate) }})-->
  406. <!-- </div>-->
  407. <!-- <div v-else-if="row.expiredAppointmentDate" class="text-xs text-[#FF9A3D] mt-1">-->
  408. <!-- (待约检:{{ formatArrayDate(row.expiredAppointmentDate) }})-->
  409. <!-- </div>-->
  410. <div v-if="row.planYearCheckDate" class="text-xs text-[#2D5FBD] mt-1">
  411. (排期时间:{{ row.planYearCheckDate }})
  412. </div>
  413. </div>
  414. <span v-else>-</span>
  415. </template>
  416. </el-table-column>
  417. <el-table-column
  418. label="关联部门"
  419. align="center"
  420. prop="relationDeptName"
  421. min-width="120"
  422. show-overflow-tooltip
  423. />
  424. <!-- 区域 -->
  425. <el-table-column
  426. label="区域/街道"
  427. align="center"
  428. prop="pipeStreet"
  429. min-width="120"
  430. show-overflow-tooltip
  431. >
  432. <template #default="{ row }">
  433. <span class="text-xs">{{ row.equipStreetName ?? row.equipDistrictName}}</span>
  434. </template>
  435. </el-table-column>
  436. <!-- 管道类别 -->
  437. <el-table-column label="管道类别" align="center" prop="pipeCategory">
  438. <template #default="scope">
  439. {{ containerTypeOptions.find(i => i.value == scope.row.pipeCategory)?.label }}
  440. </template>
  441. </el-table-column>
  442. <el-table-column
  443. label="约检联系人"
  444. align="center"
  445. prop="contact"
  446. min-width="120"
  447. show-overflow-tooltip
  448. />
  449. <el-table-column
  450. label="约检联系人电话"
  451. align="center"
  452. prop="contactPhone"
  453. min-width="140"
  454. show-overflow-tooltip
  455. />
  456. </el-table>
  457. <!-- 分页 -->
  458. <Pagination
  459. :total="total"
  460. v-model:page="queryParams.pageNo"
  461. v-model:limit="queryParams.pageSize"
  462. @pagination="handleQuery"
  463. />
  464. </ContentWrap>
  465. </div>
  466. <!-- 约检弹窗 -->
  467. <!-- <PlanScheduleEquipPipeDialog-->
  468. <!-- ref="planScheduleEquipPipeDialogRef"-->
  469. <!-- :source="200"-->
  470. <!-- :equip-list="selectedRows"-->
  471. <!-- :equip-detail-list="selectedDetailRows"-->
  472. <!-- :unitInfo="unitInfo"-->
  473. <!-- @success="handleScheduleSuccess"-->
  474. <!-- />-->
  475. <PipePlanScheduleDialog
  476. ref="planScheduleEquipPipeDialogRef"
  477. :selected-rows="selectedRows"
  478. :selected-pipe-rows="selectedDetailRows"
  479. :selected-legal-list="selectedLegalList"
  480. :selected-year-list="selectedYearList"
  481. :source="'pressure'"
  482. @success="handleScheduleSuccess"
  483. />
  484. <PipeBatchEditForm ref="formRef" @success="handleScheduleSuccess" />
  485. <!-- 批量修改地址弹窗 -->
  486. <Dialog v-model="batchEditLocationVisible" title="批量修改地址">
  487. <el-form
  488. ref="batchEditLocationFormRef"
  489. v-loading="formLoading"
  490. :model="batchEditLocationFormData"
  491. :rules="batchEditLocationFormRules"
  492. label-width="140px"
  493. >
  494. <el-form-item label="设备所在行政区" prop="equipDistrict">
  495. <AreaSelect
  496. v-model="batchEditLocationFormData.equipDistrict"
  497. :areaType="batchEditLocationFormData.areaType"
  498. @area-type-change="changeArea"
  499. @change="changeAddress"
  500. placeholder="请选择设备所在行政区"
  501. />
  502. </el-form-item>
  503. <el-form-item label="设备所在街道" prop="equipStreet">
  504. <StreetSelect
  505. v-model="batchEditLocationFormData.equipStreet"
  506. :district-ids="[batchEditLocationFormData.equipDistrict]"
  507. placeholder="请选择设备所在街道"
  508. />
  509. </el-form-item>
  510. </el-form>
  511. <template #footer>
  512. <el-button :disabled="formLoading" type="primary" @click="batchEditLocationSubmitForm">批量修改</el-button>
  513. <el-button @click="batchEditLocationVisible = false">取 消</el-button>
  514. </template>
  515. </Dialog>
  516. <unitContainerForm ref="unitContainerFormRef" />
  517. </template>
  518. <script setup lang="ts" name="PlanNewDetail">
  519. import {DICT_TYPE, getStrDictOptions, StringDictDataType} from '@/utils/dict'
  520. import {useMessage} from '@/hooks/web/useMessage'
  521. import {PlanNewPageVO} from '@/api/pressure/planScheduling'
  522. import AreaSelect from '../../system/equipcontainer/components/AreaSelect.vue'
  523. import StreetSelect from '../../system/equipcontainer/components/StreetSelect.vue'
  524. import DeptSelect from './components/DeptSelect.vue'
  525. import dayjs from 'dayjs'
  526. import {useUserStore} from '@/store/modules/user'
  527. import {formatArrayDate, formatDate} from '@/utils/formatTime'
  528. import PipeBatchEditForm from './components/PipeBatchEditForm.vue'
  529. import {cloneDeep} from 'lodash-es'
  530. import {isEmpty} from '@/utils/is'
  531. import {useRouter} from 'vue-router'
  532. import {usePlanNewStore} from '@/store/modules/planNew'
  533. import {ArrowDown, ArrowUp} from '@element-plus/icons-vue'
  534. import {EquipBoilerSchedulingEquipVO} from "@/api/pressure2/equipboilerscheduling";
  535. import {
  536. PipeEquipmentApi,
  537. PipeEquipmentDetailVO,
  538. PipeEquipmentVO
  539. } from "@/api/pressure2/pipeequipment";
  540. import PlanScheduleEquipPipeDialog
  541. from "./components/PlanScheduleEquipPipeDialog.vue";
  542. import {EquipPipeSchedulingApi, PipePlanSchedulingVO} from "@/api/pressure2/pipescheduling";
  543. import PlanScheduleBoilerDialog
  544. from "@/views/pressure2/planNew/components/PlanScheduleEquipBoilerDialog.vue";
  545. import {ref} from "vue";
  546. import PipePlanScheduleDialog
  547. from "@/views/pressure2/pipescheduling/components/PipePlanScheduleDialog.vue";
  548. import unitContainerForm from '@/components/unitContainerForm/index.vue'
  549. import { getUnitInfo, UpdateUnitVO } from '@/api/laboratory/unit'
  550. const router = useRouter()
  551. const props = defineProps({
  552. source: {
  553. type: String as PropType<string>,
  554. default: 'pressure'
  555. }
  556. })
  557. const currentDefaultYear = [
  558. dayjs().startOf('year').format('YYYY-MM-DD HH:mm:ss'),
  559. dayjs().endOf('year').format('YYYY-MM-DD HH:mm:ss')
  560. ]
  561. const message = useMessage()
  562. const userStore = useUserStore()
  563. const datePickerType = ref<'daterange' | 'month'>('month') // 修改时间选择类型定义
  564. const daterange = ref<string[]>([]) // 日期选择值
  565. const month = ref<string>('') // 月份选择值
  566. const areaStreetMap = ref(new Map<number, number[]>()) // 记录每个区域下已选择的街道
  567. const selectedLegalList = ref([])
  568. const selectedYearList = ref([])
  569. const loading = ref(false) // 列表的加载中
  570. const equipIds = ref<string[]>([]) // 设备ID列表
  571. const list = ref<PipeEquipmentVO[]>([]) // 列表的数据
  572. const total = ref(0) // 列表的总页数
  573. const selectedRows = ref<PipeEquipmentVO[]>([]) // 选中的行
  574. const selectedDetailRows = ref<PipeEquipmentDetailVO[]>([]) // 选中的行
  575. const planScheduleEquipPipeDialogRef = ref<InstanceType<typeof PlanScheduleEquipPipeDialog>>() // 计划排期弹窗引用
  576. const selectedTypeList = ref<StringDictDataType[]>([]) // 选中的容器归类
  577. const formRef = ref()
  578. const formLoading = ref(false) // 表单加载中
  579. const batchEditLocationVisible = ref(false)
  580. const batchEditLocationFormRef = ref()
  581. const batchEditLocationFormData = ref({
  582. areaType: '',
  583. equipDistrict: '', // 设备所在行政区
  584. equipStreet: '', // 设备所在街道
  585. })
  586. const batchEditLocationFormRules = reactive({
  587. equipDistrict: [{ required: true, message: '请选择设备所在行政区', trigger: 'change' }],
  588. equipStreet: [{ required: true, message: '请选择设备所在街道', trigger: 'change' }],
  589. })
  590. // 单位基本信息(通过API获取完整单位信息)
  591. const unitInfo = ref<UpdateUnitVO>({} as UpdateUnitVO)
  592. const unitContainerFormRef = ref<InstanceType<typeof unitContainerForm>>()
  593. const equipTypeMap = {
  594. 1: '容器'
  595. }
  596. const mainTableRef = ref()
  597. // 拒绝原因
  598. const refuseInspectedCategoryOptions = getStrDictOptions('refuseInspectedCategory')
  599. const getRefuseResonText = (dictCode: string, value: string) => {
  600. const resonObj = refuseInspectedCategoryOptions.find((item) => item.value === dictCode)
  601. return value || resonObj?.label || dictCode
  602. }
  603. const queryParams = ref<Recordable>({
  604. pageNo: 1,
  605. pageSize: 20,
  606. equipCode: undefined as string | undefined,
  607. productNo: undefined as string | undefined,
  608. relateDepartment: undefined as string | string[] | undefined,
  609. equipDistrict: undefined as number[] | undefined,
  610. equipStreet: undefined as number[] | undefined,
  611. typeList: [] as string[],
  612. nextDate: [] as string[],
  613. useStatus: '',
  614. areaType: 'all' as 'all' | 'gz'
  615. })
  616. const queryFormRef = ref() // 搜索的表单
  617. // 添加容器类型字典选项变量
  618. const containerTypeOptions = getStrDictOptions(DICT_TYPE.PIPE_TYPE)
  619. // 单条/批量排期相关
  620. const currentEquip = ref<PipeEquipmentVO>()
  621. const currentCheckType = ref<scheduleType>('')
  622. const expandedRowsCache = ref<Map<string, { pipes: any[], selectedIds: Set<string> }>>(new Map())
  623. // 标志位:防止展开时恢复选中状态触发 handleDetailSelectionChange 覆盖缓存
  624. const isRestoringSelection = ref(false)
  625. // 存储所有子表引用的对象
  626. const detailTableRefs = ref<Record<string, any>>({})
  627. const setDetailTableRef = (el: any, parentId: string) => {
  628. if (el) {
  629. detailTableRefs.value[parentId] = el;
  630. }
  631. }
  632. const getDetailTableRef = (parentId: string) => {
  633. return detailTableRefs.value[parentId];
  634. }
  635. const getMainRowClassName = ({row}) => {
  636. const isSelected = mainTableRef.value?.getSelectionRows().some((item) =>
  637. item.id === row.id
  638. )
  639. return isSelected ? 'selected-row' : ''
  640. }
  641. const getRowClassName = ({row}) => {
  642. // 找到当前行所在的分组,从 Map 中获取对应的表格实例
  643. const tableRef = getDetailTableRef(row.equipPipeId)
  644. if (tableRef) {
  645. const isSelected = tableRef.getSelectionRows().some((item) =>
  646. item.id === row.id
  647. )
  648. return isSelected ? 'selected-row' : ''
  649. }
  650. return ''
  651. }
  652. /** 处理行点击勾选 */
  653. const handleMainRowClick = (row) => {
  654. mainTableRef.value?.toggleRowSelection(row)
  655. }
  656. const handleRowClick = (row, event, column) => {
  657. // 如果点击的是选择列,不处理
  658. if (column.type === 'selection') {
  659. return
  660. }
  661. // 找到当前行所在的分组,从 Map 中获取对应的表格实例
  662. const tableRef = getDetailTableRef(row.equipPipeId)
  663. if (tableRef && tableRef.toggleRowSelection) {
  664. tableRef.toggleRowSelection(row)
  665. }
  666. }
  667. const handleExpandChange = (row, expandedRows: any[]) => {
  668. const rowId = row.id
  669. const isExpanded = expandedRows.some((r) => r.id === rowId)
  670. if (isExpanded) {
  671. // 展开时,从缓存中恢复或初始化
  672. if (!expandedRowsCache.value.has(rowId)) {
  673. // 首次展开,初始化缓存
  674. expandedRowsCache.value.set(rowId, {
  675. pipes: row.pipes || [],
  676. selectedIds: new Set<string>()
  677. })
  678. }
  679. // 恢复选中状态
  680. nextTick(() => {
  681. const cache = expandedRowsCache.value.get(rowId)
  682. const tableRef = getDetailTableRef(rowId)
  683. if (cache && tableRef && cache.pipes.length > 0) {
  684. // 设置标志位,防止触发 handleDetailSelectionChange
  685. isRestoringSelection.value = true
  686. cache.pipes.forEach((pipe) => {
  687. if (cache.selectedIds.has(pipe.id)) {
  688. tableRef.toggleRowSelection(pipe, true)
  689. }
  690. })
  691. // 恢复完成后,延迟重置标志位
  692. nextTick(() => {
  693. isRestoringSelection.value = false
  694. })
  695. }
  696. })
  697. } else {
  698. // 收起时,保存当前选中状态
  699. const tableRef = getDetailTableRef(rowId)
  700. if (tableRef) {
  701. const currentSelection = tableRef.getSelectionRows()
  702. const selectedIds = new Set(currentSelection.map((item: any) => item.id))
  703. expandedRowsCache.value.set(rowId, {
  704. pipes: row.pipes || [],
  705. selectedIds: selectedIds
  706. })
  707. }
  708. }
  709. // 更新展开的行 key 列表
  710. expandRowKeys.value = expandedRows.map((r) => r.id)
  711. }
  712. /** 打开弹窗 */
  713. const getUnitDetail = async (unitId: string) => {
  714. try {
  715. const res = await getUnitInfo({id: unitId})
  716. unitInfo.value = res
  717. } catch (error) {
  718. console.error('获取单位详情失败:', error)
  719. }
  720. }
  721. const open = async (row: PlanNewPageVO) => {
  722. equipIds.value = [...new Set([row.equipIds, row.yearEquipIds, row.expiredEquipIds])]
  723. .filter((id) => id) // 过滤掉 null、undefined、空字符串
  724. .join(',')
  725. .split(',')
  726. row.unitId && await getUnitDetail(row.unitId)
  727. // 初始化查询参数
  728. queryParams.value = {
  729. ...queryParams.value,
  730. unitCode: row.unitCode,
  731. unitName: row.unitName || '',
  732. unitId: row.unitId || '',
  733. }
  734. // 查询设备列表
  735. await handleQuery()
  736. }
  737. const indexMethod = (index: number) => {
  738. return index + 1
  739. }
  740. const indexMethod1 = (index: number) => {
  741. return index + 1
  742. }
  743. /**获取查询参数 */
  744. const getQueryParams = () => {
  745. const params = cloneDeep({
  746. scene: 0,
  747. pageNo: queryParams.value.pageNo,
  748. pageSize: queryParams.value.pageSize,
  749. unitCode: queryParams.value.unitCode,
  750. // unitName: queryParams.value.unitName,
  751. unitId: queryParams.value.unitId,
  752. // equipIds: equipIds.value,
  753. equipCode: queryParams.value.equipCode,
  754. relateDepartment: queryParams.value.relateDepartment,
  755. productNo: queryParams.value.productNo,
  756. equipDistrict: queryParams.value.equipDistrict,
  757. equipStreet: queryParams.value.equipStreet,
  758. pipeCategory: queryParams.value.typeList?.length === 1 ? queryParams.value.typeList[0] : undefined,
  759. pipeCategorys: queryParams.value.typeList || [],
  760. typeList: queryParams.value.typeList || [],
  761. nextDate: (queryParams.value.nextDate || []).map((item) => dayjs(item).valueOf()),
  762. useStatus: queryParams.value.useStatus ? [+queryParams.value.useStatus] : []
  763. })
  764. if (datePickerType.value === 'daterange') {
  765. params.nextDate = daterange.value ? daterange.value.map((item) => dayjs(item).valueOf()) : []
  766. } else if (datePickerType.value === 'month') {
  767. params.nextDate = month.value
  768. ? [dayjs(month.value).startOf('month').valueOf(), dayjs(month.value).endOf('month').valueOf()]
  769. : []
  770. }
  771. // 移除空值
  772. Object.keys(params).forEach((key) => {
  773. if (isEmpty(params[key])) {
  774. delete params[key]
  775. }
  776. })
  777. return params
  778. }
  779. const isSearchExpanded = ref(false)
  780. /** 搜索按钮操作 */
  781. const handleQuery = async () => {
  782. loading.value = true
  783. try {
  784. // 关闭所有已展开的行
  785. // expandRows.value.forEach(row => {
  786. // tableRef.value?.toggleRowExpansion(row, false)
  787. // })
  788. // 清空展开行记录
  789. expandRowKeys.value = []
  790. expandRows.value = []
  791. selectedRows.value = []
  792. selectedDetailRows.value = []
  793. const params = getQueryParams()
  794. // 调用后端API获取数据
  795. const res = await EquipPipeSchedulingApi.getPlanSchedulingPipesList(params)
  796. console.log(res)
  797. list.value = res.list
  798. total.value = res.total
  799. } finally {
  800. loading.value = false
  801. }
  802. }
  803. /** 重置按钮操作 */
  804. const resetQuery = () => {
  805. queryFormRef.value.resetFields()
  806. // 重置页码
  807. queryParams.value.pageNo = 1
  808. // 清空选中的容器归类对象
  809. selectedTypeList.value = []
  810. // 重置日期值
  811. datePickerType.value = 'daterange'
  812. // daterange.value = [dayjs().startOf('year').format('YYYY-MM-DD HH:mm:ss'), dayjs().endOf('year').format('YYYY-MM-DD HH:mm:ss')]
  813. daterange.value = []
  814. month.value = ''
  815. // 重新查询
  816. handleQuery()
  817. }
  818. /** 处理子表选择变化 */
  819. const handleDetailSelectionChange = (selection: any[], mainRow: any) => {
  820. // 如果正在恢复选中状态,不更新缓存(避免展开时 toggleRowSelection 触发此函数覆盖缓存)
  821. if (isRestoringSelection.value) {
  822. return
  823. }
  824. const rowId = mainRow.id
  825. // 更新缓存中的选中状态(如果缓存不存在则创建)
  826. if (!expandedRowsCache.value.has(rowId)) {
  827. // 如果该行还未展开,初始化缓存
  828. expandedRowsCache.value.set(rowId, {
  829. pipes: mainRow.pipes || [],
  830. selectedIds: new Set<string>()
  831. })
  832. }
  833. const cache = expandedRowsCache.value.get(rowId)!
  834. cache.selectedIds = new Set(selection.map((item: any) => item.id))
  835. // 更新全局选中的子表数据
  836. selectedDetailRows.value = selectedDetailRows.value.filter((item) => item.equipPipeId !== mainRow.id)
  837. selectedDetailRows.value = [...selectedDetailRows.value.filter(row => !selection.some(sel => sel.id === row.id)), ...selection]
  838. // 如果子表有选中项,则自动选中主表行;否则取消选中主表行
  839. nextTick(() => {
  840. if (selection.length > 0) {
  841. // 子表有选中项,选中主表行
  842. mainTableRef.value.toggleRowSelection(mainRow, true);
  843. } else if (!selectedDetailRows.value.map(row => row.equipPipeId).includes(mainRow.id)) {
  844. const currentlySelected = selectedRows.value.some(row => row.id === mainRow.id);
  845. if (currentlySelected && selection.length === 0) {
  846. // 只有当主行当前是选中状态且子表没有任何选中项时才取消主行选择
  847. mainTableRef.value.toggleRowSelection(mainRow, false);
  848. }
  849. }
  850. });
  851. }
  852. /** 表格选择框变化 */
  853. const handleSelectionChange = async (selection: any[]) => {
  854. // 计算取消选择的行
  855. const deselectedRows = selectedRows.value.filter(
  856. item => !selection.includes(item)
  857. );
  858. selectedRows.value = selection
  859. // 清除取消选中行的子表选择(包括展开的和收起的)
  860. deselectedRows.forEach(item => {
  861. const rowId = item.id
  862. // 如果该行是展开状态,直接清除表格选中
  863. const tableRef = getDetailTableRef(rowId)
  864. if (tableRef) {
  865. tableRef.clearSelection()
  866. }
  867. // 无论是否展开,都清除缓存中的选中状态
  868. if (expandedRowsCache.value.has(rowId)) {
  869. expandedRowsCache.value.get(rowId)!.selectedIds.clear()
  870. }
  871. // 从全局选中的子表数据中移除
  872. selectedDetailRows.value = selectedDetailRows.value.filter(
  873. detailRow => detailRow.equipPipeId !== rowId
  874. )
  875. })
  876. }
  877. type scheduleType = 'regular' | 'year' | ''
  878. /** 处理单条记录排期 */
  879. const handleSingleSchedule = (row: PipeEquipmentVO, type: scheduleType) => {
  880. currentEquip.value = row
  881. currentCheckType.value = type
  882. planScheduleEquipPipeDialogRef.value?.open()
  883. }
  884. /** 处理批量排期 */
  885. // const handleBatchSchedule = (type: scheduleType) => {
  886. // if (selectedDetailRows.value.length === 0) {
  887. // message.warning('请至少选择一条记录')
  888. // return
  889. // }
  890. // currentCheckType.value = type
  891. // planScheduleEquipPipeDialogRef.value?.open(type)
  892. // }
  893. const handleBatchSchedule = () => {
  894. // if (selectedRows.value.length === 0) {
  895. // message.warning('请至少选择一条记录')
  896. // return
  897. // }
  898. // isBatchMode.value = true
  899. // planScheduleEquipPipeDialogRef.value?.open('all')
  900. if (selectedDetailRows.value.length === 0 && selectedRows.value.length === 0) {
  901. message.warning('请至少选择一条记录')
  902. return
  903. }
  904. //按定检和年检分组
  905. selectedLegalList.value = []
  906. selectedYearList.value = []
  907. // 选择了主表但是没有选子表,则获取该主表下的所有子表数据
  908. let ids = selectedDetailRows.value.map(item => item.equipPipeId)
  909. selectedRows.value.forEach(item => {
  910. if (!ids.includes(item.id)) {
  911. item.pipes.forEach(pipe => {
  912. if (!pipe.hasLegalScheduling && pipe.planLegalCheckDate == null) {
  913. selectedLegalList.value.push(pipe)
  914. }
  915. if (!pipe.hasYearScheduling && pipe.planYearCheckDate == null) {
  916. selectedYearList.value.push(pipe)
  917. }
  918. })
  919. }
  920. })
  921. selectedDetailRows.value.forEach(item => {
  922. if (!item.hasLegalScheduling && item.planLegalCheckDate == null){
  923. selectedLegalList.value.push(item)
  924. }
  925. if (!item.hasYearScheduling && item.planYearCheckDate == null){
  926. selectedYearList.value.push(item)
  927. }
  928. })
  929. //console.log("selectedRows.value",selectedRows.value)
  930. //console.log(selectedLegalList.value,selectedYearList.value)
  931. //scheduleDialogRef.value?.open(selectedPipeRows.value,selectedRows.value)
  932. //selectedPipeRows.value = [row];
  933. console.log('selectedLegalList.value',selectedLegalList.value,selectedYearList.value)
  934. planScheduleEquipPipeDialogRef.value?.open(selectedLegalList.value,selectedYearList.value)
  935. }
  936. const handleSchedule = async (row: any,checkType?: string) => {
  937. selectedRows.value = [row]
  938. //按定检和年检分组
  939. selectedLegalList.value = []
  940. selectedYearList.value = []
  941. row.pipes.forEach(item => {
  942. if (selectedDetailRows.value.includes(item)) {
  943. if (!item.hasLegalScheduling && item.planLegalCheckDate == null) {
  944. selectedLegalList.value.push(item)
  945. }
  946. if (!item.hasYearScheduling && item.planYearCheckDate == null) {
  947. selectedYearList.value.push(item)
  948. }
  949. }
  950. })
  951. if (selectedLegalList.value.length == 0 && selectedYearList.value.length == 0) {
  952. // 默认带出全部
  953. row.pipes.forEach(item => {
  954. if (!item.hasLegalScheduling && item.planLegalCheckDate == null) {
  955. selectedLegalList.value.push(item)
  956. }
  957. if (!item.hasYearScheduling && item.planYearCheckDate == null) {
  958. selectedYearList.value.push(item)
  959. }
  960. })
  961. }
  962. planScheduleEquipPipeDialogRef.value?.open(selectedLegalList.value, selectedYearList.value,checkType)
  963. }
  964. /** 处理批量修改 */
  965. const handleBatchEditFn = () => {
  966. if (selectedRows.value.length === 0) {
  967. message.warning('请至少选择一条记录')
  968. return
  969. }
  970. formRef.value.open(selectedRows.value, '1')
  971. }
  972. /** 批量修改地址 - 打开弹窗 */
  973. const handleBatchEditLocationFn = async () => {
  974. const selectRows = selectedRows.value || []
  975. if (!selectRows.length) {
  976. return ElMessage.error('请选择要修改的设备')
  977. }
  978. formLoading.value = true
  979. try {
  980. const params = {
  981. id: selectRows[0]?.id
  982. }
  983. const res = await EquipPipeSchedulingApi.getPlanSchedulingPipesList(params)
  984. const equip = res.list?.[0]
  985. if (equip) {
  986. batchEditLocationFormData.value.areaType = equip.areaType || ''
  987. batchEditLocationFormData.value.equipDistrict = equip.equipDistrict || ''
  988. batchEditLocationFormData.value.equipStreet = equip.equipStreet || ''
  989. }
  990. batchEditLocationVisible.value = true
  991. } finally {
  992. formLoading.value = false
  993. }
  994. }
  995. const changeArea = (areaType: 'all' | 'gz') => {
  996. batchEditLocationFormData.value.areaType = areaType
  997. }
  998. const changeAddress = () => {
  999. batchEditLocationFormData.value.equipStreet = null as any
  1000. setTimeout(() => {
  1001. batchEditLocationFormRef.value?.clearValidate(['equipStreet'])
  1002. }, 0)
  1003. }
  1004. const batchEditLocationSubmitForm = async () => {
  1005. if (!batchEditLocationFormRef.value) return
  1006. const valid = await batchEditLocationFormRef.value.validate()
  1007. if (!valid) return
  1008. formLoading.value = true
  1009. try {
  1010. const selectRows = selectedRows.value || []
  1011. const data = {
  1012. ...batchEditLocationFormData.value,
  1013. ids: selectRows.map((item) => item.id)
  1014. }
  1015. await EquipPipeSchedulingApi.batchUpdateDistrict(data)
  1016. ElMessage.success('修改成功')
  1017. handleQuery()
  1018. batchEditLocationVisible.value = false
  1019. } finally {
  1020. formLoading.value = false
  1021. }
  1022. }
  1023. /** 约检单/任务单 跳转查询 */
  1024. const handleToRoute = (routeName: 'AcceptOrder1' | 'TaskOrder') => {
  1025. const { unitName } = unref(currentCheckData) || {}
  1026. router.push({
  1027. name: routeName,
  1028. query: {
  1029. unitName: unitName,
  1030. filterCancel: '400'
  1031. }
  1032. })
  1033. }
  1034. /** 排期成功处理 */
  1035. const handleScheduleSuccess = () => {
  1036. selectedRows.value = []
  1037. handleQuery()
  1038. }
  1039. /** 处理容器归类变化 */
  1040. const handleTypeListChange = (values: string[]) => {
  1041. selectedTypeList.value = containerTypeOptions.filter((dict) => values.includes(dict.value))
  1042. }
  1043. /** 处理表格排序 */
  1044. const handleSortChange = ({ prop, order }) => {
  1045. if (!prop || !order) {
  1046. list.value.sort((a, b) => 0) // 重置排序
  1047. return
  1048. }
  1049. list.value.sort((a, b) => {
  1050. const aValue = a[prop] || ''
  1051. const bValue = b[prop] || ''
  1052. if (order === 'ascending') {
  1053. return aValue > bValue ? 1 : -1
  1054. } else {
  1055. return aValue < bValue ? 1 : -1
  1056. }
  1057. })
  1058. }
  1059. /** 处理区域变化 */
  1060. const handleAreaChange = (areas: number[]) => {
  1061. // 获取移除的区域(通过比较之前的区域列表和现在的区域列表)
  1062. const prevAreas = Array.from(areaStreetMap.value.keys())
  1063. const removedAreas = prevAreas.filter((area) => !areas.includes(area))
  1064. // 移除取消选择的区域下的街道
  1065. if (removedAreas.length > 0) {
  1066. const currentStreets = queryParams.value.equipStreet || []
  1067. removedAreas.forEach((areaId) => {
  1068. const streetsToRemove = areaStreetMap.value.get(areaId) || []
  1069. // 从当前选中的街道中移除这些街道
  1070. queryParams.value.equipStreet = currentStreets.filter(
  1071. (streetId) => !streetsToRemove.includes(streetId)
  1072. )
  1073. // 从映射中移除该区域
  1074. areaStreetMap.value.delete(areaId)
  1075. })
  1076. }
  1077. }
  1078. /** 处理区域清空 */
  1079. const handleAreaClear = () => {
  1080. // 清空所有选中的街道
  1081. queryParams.value.equipStreet = []
  1082. // 清空区域-街道映射
  1083. areaStreetMap.value.clear()
  1084. }
  1085. /** 处理街道变化 */
  1086. const handleStreetChange = (streets: number[], areaId: number) => {
  1087. // 更新区域-街道映射
  1088. if (queryParams.value.equipDistrict?.includes(areaId)) {
  1089. areaStreetMap.value.set(areaId, streets)
  1090. }
  1091. }
  1092. /** 处理街道清空 */
  1093. const handleStreetClear = () => {
  1094. // 清空所有区域下的街道选择
  1095. areaStreetMap.value.clear()
  1096. }
  1097. /** 处理日期变化 */
  1098. const handleDateChange = (val: [string, string] | null) => {
  1099. daterange.value = val || []
  1100. queryParams.value.nextDate = val
  1101. ? [
  1102. dayjs(val[0]).startOf('day').format('YYYY-MM-DD HH:mm:ss'),
  1103. dayjs(val[1]).endOf('day').format('YYYY-MM-DD HH:mm:ss')
  1104. ]
  1105. : []
  1106. }
  1107. /** 处理月份变化 */
  1108. const handleMonthChange = (val: string | null) => {
  1109. if (!val) {
  1110. queryParams.value.nextDate = []
  1111. return
  1112. }
  1113. const date = dayjs(val)
  1114. queryParams.value.nextDate = [
  1115. date.startOf('month').format('YYYY-MM-DD HH:mm:ss'),
  1116. date.endOf('month').format('YYYY-MM-DD HH:mm:ss')
  1117. ]
  1118. month.value = val
  1119. }
  1120. // 已展开行
  1121. const expandRowKeys = ref<string[]>([])
  1122. const expandRows = ref([])
  1123. const toggleExpand = async (row: any) => {
  1124. const key = row.id
  1125. // 第一次点击展开,第二次点击同一行收起
  1126. if (expandRowKeys.value.includes(key)) {
  1127. mainTableRef.value.toggleRowExpansion(row, false)
  1128. } else {
  1129. mainTableRef.value.toggleRowExpansion(row, true)
  1130. }
  1131. }
  1132. // 监听日期类型变化
  1133. watch(datePickerType, (newVal) => {
  1134. // 清空日期相关字段
  1135. // daterange.value = newVal === 'daterange' ? daterange.value = cloneDeep(currentDefaultYear) : []
  1136. daterange.value = []
  1137. month.value = ''
  1138. queryParams.value.nextDate = []
  1139. })
  1140. const { getPlanNewData } = usePlanNewStore()
  1141. const currentCheckData = ref<PlanNewPageVO>()
  1142. onMounted(() => {
  1143. const { id } = (router.currentRoute.value.query || {}) as unknown as { id: string }
  1144. const data = getPlanNewData(id)
  1145. if (data) {
  1146. currentCheckData.value = data
  1147. open(data)
  1148. }
  1149. })
  1150. defineExpose({
  1151. open
  1152. })
  1153. // 工商信息
  1154. const handleUnitCodeFn = (id) => {
  1155. if (!id) {
  1156. return ElMessage.warning('该单位信息异常!')
  1157. }
  1158. unitContainerFormRef.value?.open(id)
  1159. }
  1160. </script>
  1161. <style lang="scss" scoped>
  1162. .plan-section {
  1163. padding: 16px;
  1164. border: 1px solid #ebeef5;
  1165. border-radius: 4px;
  1166. .section-title {
  1167. display: flex;
  1168. padding: 8px 16px;
  1169. margin: -16px -16px 16px;
  1170. font-weight: bold;
  1171. background-color: #f5f7fa;
  1172. border-bottom: 1px solid #ebeef5;
  1173. align-items: center;
  1174. }
  1175. }
  1176. .schedule-link {
  1177. color: var(--el-color-primary);
  1178. &:hover {
  1179. color: var(--el-color-primary-light-3);
  1180. }
  1181. }
  1182. :deep(.area-select) {
  1183. .area-cascader {
  1184. flex: 1;
  1185. }
  1186. }
  1187. :deep(.inner-table .el-checkbox__input.is-checked .el-checkbox__inner),
  1188. :deep(.inner-table .el-checkbox__input.is-indeterminate .el-checkbox__inner) {
  1189. background-color: #67c23a; // 绿色
  1190. border-color: #67c23a;
  1191. }
  1192. :deep(.selected-row){
  1193. background-color: #ecf5ff !important;
  1194. }
  1195. // 子表选中行特殊背景色(浅绿色)
  1196. :deep(.inner-table .selected-row) {
  1197. background-color: #e8f5e9 !important;
  1198. }
  1199. // 排期日期链接样式
  1200. .schedule-date-link {
  1201. cursor: pointer;
  1202. transition: all 0.2s;
  1203. &:hover {
  1204. color: var(--el-color-primary-light-3);
  1205. text-decoration: underline;
  1206. }
  1207. }
  1208. </style>