task.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  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. <el-form-item label="任务单号" prop="orderNo">
  12. <el-input
  13. v-model="queryParams.orderNo"
  14. placeholder="请输入任务单号"
  15. clearable
  16. @keyup.enter="handleQuery"
  17. class="!w-240px"
  18. />
  19. </el-form-item>
  20. <el-form-item label="使用单位" prop="unitName">
  21. <el-input
  22. v-model="queryParams.unitName"
  23. placeholder="请输入使用单位"
  24. clearable
  25. @keyup.enter="handleQuery"
  26. class="!w-240px"
  27. />
  28. </el-form-item>
  29. <el-form-item label="检验性质" prop="checkType">
  30. <el-select
  31. v-model="queryParams.checkType"
  32. placeholder="请选择检验性质"
  33. clearable
  34. class="!w-240px"
  35. >
  36. <el-option v-for="(item, key) in PressureBoilerCheckTypeMap" :key="key" :label="item" :value="key" />
  37. </el-select>
  38. </el-form-item>
  39. <el-form-item label="检验时间" prop="checkDate">
  40. <el-date-picker
  41. v-model="queryParams.checkDate"
  42. value-format="YYYY-MM-DD HH:mm:ss"
  43. type="daterange"
  44. start-placeholder="开始日期"
  45. end-placeholder="结束日期"
  46. :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
  47. class="!w-240px"
  48. />
  49. </el-form-item>
  50. <!-- <el-form-item label="检验员" prop="appoinmentUserName">-->
  51. <!-- <el-input-->
  52. <!-- v-model="queryParams.appoinmentUserName"-->
  53. <!-- placeholder="请输入检验员名称"-->
  54. <!-- clearable-->
  55. <!-- @keyup.enter="handleQuery"-->
  56. <!-- class="!w-240px"-->
  57. <!-- />-->
  58. <!-- </el-form-item>-->
  59. <el-form-item label="检验员" prop="checkUserIds">
  60. <el-select
  61. class="!w-240px"
  62. v-model="queryParams.checkUserIds"
  63. readonly
  64. clearable
  65. placeholder="请选择检验员"
  66. multiple
  67. popper-class="user-select-popper"
  68. @click.stop.prevent="() => handleOpenUserDialog(recheckStrIdsOpts, 'checkUserIds')"
  69. >
  70. <el-option
  71. v-for="child in recheckStrIdsOpts"
  72. :key="child && child.id"
  73. :label="child.nickName"
  74. :value="child.id"
  75. />
  76. </el-select>
  77. </el-form-item>
  78. <el-form-item label="合同编号" prop="contractNo">
  79. <el-input
  80. v-model="queryParams.contractNo"
  81. placeholder="请输入合同编号"
  82. clearable
  83. @keyup.enter="handleQuery"
  84. class="!w-240px"
  85. />
  86. </el-form-item>
  87. <el-form-item label="任务状态" prop="status">
  88. <el-select
  89. v-model="queryParams.taskStatus"
  90. placeholder="请选择任务状态"
  91. clearable
  92. class="!w-240px"
  93. >
  94. <el-option label="全部" value="all" />
  95. <el-option v-for="(item, key) in filteredTaskStatusMap" :key="key" :label="item" :value="key"/>
  96. </el-select>
  97. </el-form-item>
  98. <el-form-item label="受理单提交人" prop="submitIds">
  99. <el-select
  100. class="!w-240px"
  101. v-model="queryParams.submitIds"
  102. readonly
  103. clearable
  104. placeholder="请选择受理单提交人"
  105. multiple
  106. popper-class="user-select-popper"
  107. @click.stop.prevent="() => handleOpenUserDialog(recheckStrIdsOpts, 'submitIds')"
  108. >
  109. <el-option
  110. v-for="child in recheckStrIdsOpts"
  111. :key="child && child.id"
  112. :label="child.nickName"
  113. :value="child.id"
  114. />
  115. </el-select>
  116. </el-form-item>
  117. <el-form-item label="受理单提交" prop="submitTime">
  118. <el-date-picker
  119. v-model="queryParams.submitTime"
  120. value-format="YYYY-MM-DD HH:mm:ss"
  121. type="daterange"
  122. start-placeholder="开始日期"
  123. end-placeholder="结束日期"
  124. :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
  125. class="!w-240px"
  126. />
  127. </el-form-item>
  128. <el-form-item>
  129. <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
  130. <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
  131. </el-form-item>
  132. </el-form>
  133. </ContentWrap>
  134. <!-- 列表 -->
  135. <ContentWrap>
  136. <el-button type="primary" @click="handleBatchConfirmationFn" :disabled="selectedRows.length === 0">批量办结确认</el-button>
  137. <el-table ref="tableRef" v-loading="loading" :data="list" :stripe="true" @selection-change="handleSelectionChange">
  138. <el-table-column type="selection" width="30" />
  139. <el-table-column label="任务单号" align="center" prop="orderNo" min-width="150px" />
  140. <el-table-column label="使用单位" align="center" prop="unitName" min-width="150px" />
  141. <el-table-column label="检验性质" align="center" prop="checkType" min-width="120px">
  142. <template #default="scope">
  143. {{ PressureBoilerCheckTypeMap[scope.row.checkType] }}
  144. </template>
  145. </el-table-column>
  146. <el-table-column label="设备数量" align="center" prop="equipNum" min-width="150px"/>
  147. <el-table-column label="任务单状态" align="center" prop="taskStatus" min-width="150px">
  148. <template #default="scope">
  149. <el-tag :type="getTypeColor(scope.row.taskStatus)">{{ PressureTaskOrderTaskStatusMap[scope.row.taskStatus] }}</el-tag>
  150. </template>
  151. </el-table-column>
  152. <el-table-column
  153. label="检验时间"
  154. align="center"
  155. prop="checkDate"
  156. min-width="120px"
  157. >
  158. <template #default="scope">
  159. {{ formatArrayDate(scope.row.checkDate) }}
  160. </template>
  161. </el-table-column>
  162. <el-table-column label="项目负责人" align="center" prop="manager" min-width="120px" >
  163. <template #default="scope">
  164. {{ scope.row.manager ? scope.row.manager.nickname : '-' }}
  165. </template>
  166. </el-table-column>
  167. <el-table-column label="检验员" align="center" prop="appoinmentUser" min-width="150px">
  168. <template #default="scope">
  169. <div v-if="scope.row.appoinmentUser && scope.row.appoinmentUser.length > 0">
  170. <div v-for="user in scope.row.appoinmentUser" :key="user.id">
  171. {{ user.nickname }} ({{ user.employeeNo }})
  172. </div>
  173. </div>
  174. <div v-else>-</div>
  175. </template>
  176. </el-table-column>
  177. <el-table-column label="收费方式" align="center" prop="feeType" min-width="100px">
  178. <template #default="scope">
  179. {{ PressureFeeTypeMap[scope.row.feeType] }}
  180. </template>
  181. </el-table-column>
  182. <el-table-column label="合同编号" align="center" prop="contractNo" min-width="150px">
  183. <template #default="scope">
  184. {{ scope.row.contractNo ? scope.row.contractNo : '-' }}
  185. </template>
  186. </el-table-column>
  187. <el-table-column label="变更记录" align="center" prop="changeLogCount" min-width="100px">
  188. <template #default="scope">
  189. <div v-if="scope.row.changeLogCount > 0">
  190. <el-link type="primary" @click="showChangeLog(scope.row)">{{ scope.row.changeLogCount }}</el-link>
  191. </div>
  192. <div v-else>-</div>
  193. </template>
  194. </el-table-column>
  195. <el-table-column label="操作" align="center" min-width="180px" fixed="right">
  196. <template #default="scope">
  197. <!-- 认领 -->
  198. <el-button
  199. v-if="scope.row.taskStatus === PressureTaskOrderTaskStatus.WAIT_CONFIRM"
  200. link
  201. type="primary"
  202. @click="handleConfirm(scope.row.id)"
  203. >
  204. 认领
  205. </el-button>
  206. <!-- 取消认领 -->
  207. <el-button
  208. v-if="scope.row.taskStatus === PressureTaskOrderTaskStatus.CONFIRMED"
  209. link
  210. type="primary"
  211. :disabled="scope.row.manager?.id !== userStore?.user?.id"
  212. @click="handleCancelConfirm(scope.row.id)"
  213. >
  214. 取消认领
  215. </el-button>
  216. <!-- 办结确认 -->
  217. <el-button
  218. link
  219. type="primary"
  220. v-if="scope.row.taskStatus == 710"
  221. @click="handleConfirmationFn(scope.row.id)"
  222. >
  223. 办结确认
  224. </el-button>
  225. <el-button
  226. link
  227. type="primary"
  228. @click="handleEdit(scope.row.id)"
  229. >
  230. 编辑
  231. </el-button>
  232. </template>
  233. </el-table-column>
  234. </el-table>
  235. <!-- 分页 -->
  236. <Pagination
  237. :total="total"
  238. v-model:page="queryParams.pageNo"
  239. v-model:limit="queryParams.pageSize"
  240. @pagination="getList"
  241. />
  242. </ContentWrap>
  243. <!-- 选择人员公共弹窗 -->
  244. <CustomDialog
  245. v-model="customUserDialogVisible"
  246. :dialogAttrs="{
  247. zIndex: 10006
  248. }"
  249. @confirm="handleUserConfirm"
  250. >
  251. <el-input
  252. v-model="userQueryData.nickName"
  253. clearable
  254. placeholder="请输入名称"
  255. @keyup.enter="handleFetchUserList"
  256. style="margin-bottom: 14px"
  257. />
  258. <SmartTable
  259. ref="userTableRef"
  260. v-model:pageNo="userQueryData.pageNo"
  261. v-model:pagesize="userQueryData.pageSize"
  262. :total="userQueryData.total"
  263. v-model:columns="userColumns"
  264. :data="userTableList"
  265. :buttons="[]"
  266. :showSettingTools="false"
  267. :showSearch="false"
  268. :showRefresh="false"
  269. @on-page-size-change="onPageSizeChange"
  270. @on-page-no-change="onPageNoChange"
  271. />
  272. </CustomDialog>
  273. </template>
  274. <script setup lang="ts">
  275. import { ref, reactive, onMounted, computed } from 'vue'
  276. import { formatArrayDate } from '@/utils/formatTime'
  277. import { BoilerTaskOrderApi, BoilerTaskOrderVO } from '@/api/pressure2/boilertaskorder'
  278. import { PressureBoilerCheckTypeMap, PressureFeeTypeMap, PressureTaskOrderTaskStatusMap, PressureTaskOrderTaskStatus } from '@/utils/constants'
  279. import {ElMessageBox, ElMessage, ElTable} from 'element-plus'
  280. import { useRouter } from 'vue-router'
  281. // 在script部分
  282. import { getUserPage } from '@/api/system/user'
  283. import SmartTable from "@/components/SmartTable/SmartTable";
  284. import { getUserList } from '@/api/common/user'
  285. import {useUserStore} from "@/store/modules/user";
  286. // 定义用户搜索相关的响应式变量
  287. const userOptions = ref([])
  288. const userSearchLoading = ref(false)
  289. const router = useRouter()
  290. const tableRef = ref<InstanceType<typeof ElTable>>()
  291. const selectedRows = ref<BoilerTaskOrderVO[]>([]) // 选中的行
  292. // 通过输入的值查询对应受理单提交人名字
  293. // 远程搜索用户方法
  294. const remoteSearchUsers = (query) => {
  295. if (query) {
  296. userSearchLoading.value = true
  297. getUserPage({
  298. pageNo: 1,
  299. pageSize: 10,
  300. nickName: query
  301. }).then(response => {
  302. const users = response.list || []
  303. userOptions.value = users.map(user => ({
  304. value: user.id, // 值是用户ID
  305. label: user.nickname, // 显示的是用户昵称
  306. key: user.id // 用于v-for的key
  307. }))
  308. }).finally(() => {
  309. userSearchLoading.value = false
  310. })
  311. } else {
  312. userOptions.value = []
  313. }
  314. }
  315. // 剔除查询模块中不需要的选项
  316. const filteredTaskStatusMap = computed(() => {
  317. const result = {};
  318. // 需要剔除的状态
  319. const excludeStatus = [
  320. PressureTaskOrderTaskStatus.RECORD_INPUT, // 记录录入 500
  321. PressureTaskOrderTaskStatus.RECORD_CHECK, // 记录校核 510
  322. PressureTaskOrderTaskStatus.REPORT_INPUT, // 报告编制 520
  323. PressureTaskOrderTaskStatus.REPORT_AUDIT, // 报告审核 600
  324. PressureTaskOrderTaskStatus.REPORT_APPROVE // 报告审批 700
  325. ];
  326. // 只保留不在排除列表中的状态
  327. Object.entries(PressureTaskOrderTaskStatusMap).forEach(([key, value]) => {
  328. if (!excludeStatus.includes(Number(key))) {
  329. result[key] = value;
  330. }
  331. });
  332. return result;
  333. });
  334. const getTypeColor = (status: string | number) => {
  335. const statusMap = {
  336. [PressureTaskOrderTaskStatus.WAIT_CONFIRM]: 'primary',
  337. [PressureTaskOrderTaskStatus.CANCELLED]: 'info',
  338. [PressureTaskOrderTaskStatus.AUDITING_EDIT]: 'warning',
  339. [PressureTaskOrderTaskStatus.AUDITING_CANCEL]: 'warning',
  340. [PressureTaskOrderTaskStatus.AUDITING_TIME]: 'warning',
  341. [PressureTaskOrderTaskStatus.CONFIRMED]: 'success',
  342. [PressureTaskOrderTaskStatus.RECORD_INPUT]: 'warning',
  343. [PressureTaskOrderTaskStatus.RECORD_CHECK]: 'warning',
  344. [PressureTaskOrderTaskStatus.REPORT_INPUT]: 'warning',
  345. [PressureTaskOrderTaskStatus.REPORT_AUDIT]: 'warning',
  346. [PressureTaskOrderTaskStatus.REPORT_APPROVE]: 'warning',
  347. [PressureTaskOrderTaskStatus.REPORT_END]: 'success'
  348. };
  349. return statusMap[status] || 'info';
  350. }
  351. /** 承压任务单 列表 */
  352. defineOptions({ name: 'CheckerTaskList' })
  353. const loading = ref(true)
  354. const list = ref<BoilerTaskOrderVO[]>([])
  355. const total = ref(0)
  356. const queryParams = reactive({
  357. pageNo: 1,
  358. pageSize: 10,
  359. orderNo: undefined,
  360. unitName: undefined,
  361. checkType: undefined,
  362. checkDate: [],
  363. checkUserIds: [],
  364. submitIds:[],
  365. contractNo: undefined,
  366. taskStatus: 'all',
  367. submitTime: [],
  368. equipMainType: 200,
  369. })
  370. const queryFormRef = ref()
  371. /** 查询列表 */
  372. const getList = async () => {
  373. loading.value = true
  374. try {
  375. const params = { ...queryParams }
  376. if (params.taskStatus === 'all') {
  377. params.taskStatus = undefined
  378. }
  379. const data = await BoilerTaskOrderApi.getBoilerTaskOrderPage(params)
  380. list.value = data.list
  381. total.value = data.total
  382. } finally {
  383. loading.value = false
  384. }
  385. }
  386. /** 搜索按钮操作 */
  387. const handleQuery = () => {
  388. queryParams.pageNo = 1
  389. getList()
  390. }
  391. /** 重置按钮操作 */
  392. const resetQuery = () => {
  393. queryFormRef.value.resetFields()
  394. queryParams.taskStatus = 'all'
  395. handleQuery()
  396. }
  397. // 修改后的编辑/查看详情操作
  398. const handleEdit = (id: string) => {
  399. router.push({
  400. name: 'BoilerTaskOrderView',
  401. query: {
  402. id,
  403. type: 'checker'
  404. }
  405. })
  406. }
  407. // 变更记录
  408. const showChangeLog = (row: BoilerTaskOrderVO) => {
  409. console.log('ChangeLog:', row)
  410. }
  411. // 认领
  412. const handleConfirm = async (id: string) => {
  413. try {
  414. await ElMessageBox.confirm('是否认领该任务单?', '认领提示', {
  415. confirmButtonText: '确定',
  416. cancelButtonText: '取消',
  417. type: 'warning'
  418. })
  419. await BoilerTaskOrderApi.confirmTaskOrder({ id, "confirm": true })
  420. ElMessage.success('认领成功')
  421. getList()
  422. } catch (error) {
  423. if (error !== 'cancel') {
  424. ElMessage.error('认领失败')
  425. console.error('Confirm error:', error)
  426. }
  427. }
  428. }
  429. // 取消认领
  430. const handleCancelConfirm = async (id: string) => {
  431. try {
  432. await ElMessageBox.confirm('是否取消认领该任务单?', '取消认领提示', {
  433. confirmButtonText: '确定',
  434. cancelButtonText: '取消',
  435. type: 'warning'
  436. })
  437. await BoilerTaskOrderApi.confirmTaskOrder({ id, "confirm": false })
  438. ElMessage.success('取消认领成功')
  439. getList()
  440. } catch (error) {
  441. if (error !== 'cancel') {
  442. ElMessage.error('取消认领失败')
  443. console.error('Cancel confirm error:', error)
  444. }
  445. }
  446. }
  447. // 批量办结确认
  448. const handleBatchConfirmationFn = async () => {
  449. const list = tableRef?.value?.getSelectionRows()
  450. if (list.length === 0) {
  451. ElMessage.warning('请选择需要办结确认的任务!')
  452. return
  453. }
  454. const flag = list.every(
  455. (item) => item.taskStatus === PressureTaskOrderTaskStatus.REPORT_CONFIRMATION
  456. )
  457. if (!flag) {
  458. ElMessage.warning('请选择状态为办结确认的任务!')
  459. return
  460. }
  461. const ids = list.map((item) => item.id)
  462. try {
  463. await ElMessageBox.confirm('确认要批量办结确认吗?此操作不可撤销。', '办结确认', {
  464. confirmButtonText: '确认',
  465. cancelButtonText: '取消',
  466. type: 'warning'
  467. })
  468. const submitResult = await BoilerTaskOrderApi.finishApi({
  469. ids
  470. })
  471. if (submitResult) {
  472. ElMessage.success('办结确认成功!')
  473. // 清除所有选择
  474. tableRef?.value?.clearSelection()
  475. getList()
  476. }
  477. } catch (err) {
  478. ElMessage.info('已取消办结确认操作')
  479. }
  480. }
  481. //办结确认
  482. const handleConfirmationFn = async (id: string) => {
  483. try {
  484. await ElMessageBox.confirm('确认要办结确认该任务吗?此操作不可撤销。', '办结确认', {
  485. confirmButtonText: '确认',
  486. cancelButtonText: '取消',
  487. type: 'warning'
  488. })
  489. const ids = [id]
  490. const submitResult = await BoilerTaskOrderApi.finishApi({
  491. ids
  492. })
  493. if (submitResult) {
  494. ElMessage.success('办结确认成功!')
  495. // 清除所有选择
  496. tableRef?.value?.clearSelection()
  497. getList()
  498. }
  499. } catch (err) {
  500. ElMessage.info('已取消办结确认操作')
  501. }
  502. }
  503. // 人员选择弹窗 start
  504. const userTableRef = ref()
  505. const userStore = useUserStore()
  506. const userInfo = computed(() => userStore.user)
  507. const fieldKey = ref('')
  508. const customUserDialogVisible = ref(false)
  509. const checkFormOptions = ref<any[]>([])
  510. interface UserListQuery {
  511. nickName: string
  512. pageNo: number
  513. pageSize: number
  514. total?: number
  515. }
  516. const userQueryData = reactive<UserListQuery>({
  517. nickName: '',
  518. pageNo: 1,
  519. pageSize: 10,
  520. total: 0
  521. })
  522. const recheckStrIdsOpts = ref<any[]>([
  523. { id: userInfo.value.id, nickName: userInfo.value?.nickname }
  524. ])
  525. const userTableList = ref<any[]>([])
  526. const userColumns = ref<any[]>([
  527. {
  528. type: 'selection',
  529. width: '50px'
  530. },
  531. {
  532. label: '工号',
  533. prop: 'employeeNo'
  534. },
  535. {
  536. label: '姓名',
  537. prop: 'nickname'
  538. },
  539. {
  540. label: '部门',
  541. prop: 'deptName'
  542. }
  543. ])
  544. const handleUserConfirm = () => {
  545. const selectRows = userTableRef.value.getTableRef().getSelectionRows()
  546. // 过滤组合合成options
  547. const currOptions = checkFormOptions.value.map((item) => item.id) || []
  548. selectRows
  549. .filter((item) => !currOptions.includes(item.id))
  550. .forEach((item) => {
  551. checkFormOptions.value.push({
  552. id: item.id,
  553. nickName: item.nickname,
  554. employeeNo: item.employeeNo
  555. })
  556. })
  557. queryParams[fieldKey.value] = [
  558. ...new Set([...queryParams[fieldKey.value], ...selectRows.map((row) => row.id)])
  559. ]
  560. customUserDialogVisible.value = false
  561. }
  562. // 打开用户选择框
  563. const handleOpenUserDialog = (options: any, key: string) => {
  564. checkFormOptions.value = options
  565. userQueryData.nickName = ''
  566. fieldKey.value = key
  567. userQueryData.pageNo = 1
  568. userQueryData.pageSize = 10
  569. handleFetchUserList()
  570. }
  571. // 获取用户信息
  572. const handleFetchUserList = async () => {
  573. const queryParams: UserListQuery = {
  574. ...userQueryData
  575. }
  576. delete queryParams.total
  577. const result = await getUserList(queryParams)
  578. userTableList.value = result.list
  579. userQueryData.total = result.total
  580. customUserDialogVisible.value = true
  581. }
  582. const onPageSizeChange = (val) => {
  583. userQueryData.pageSize = val
  584. handleFetchUserList()
  585. }
  586. const onPageNoChange = (val) => {
  587. userQueryData.pageNo = val
  588. handleFetchUserList()
  589. }
  590. // 人员选择弹窗 end
  591. /** 表格选择框变化 */
  592. const handleSelectionChange = (selection: BoilerTaskOrderVO[]) => {
  593. selectedRows.value = selection
  594. }
  595. /** 初始化 **/
  596. onMounted(() => {
  597. getList()
  598. })
  599. </script>
  600. <style lang="scss" scoped>
  601. </style>