index.vue 46 KB

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