approval.vue 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258
  1. <script lang="ts" setup>
  2. import { rangeShortcuts } from '@/utils/formatTime'
  3. import { useDebounceFn } from '@vueuse/core'
  4. import dayjs from 'dayjs'
  5. import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
  6. import { TableColumnCtx } from 'element-plus/es/components/table/src/table-column/defaults'
  7. import { FormInstance, FormRules } from 'element-plus'
  8. import Form from '@/components/Form/src/Form.vue'
  9. import { useUserStore } from '@/store/modules/user'
  10. import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
  11. interface List {
  12. id: number
  13. deptId: number
  14. projectId: number
  15. taskId: number
  16. projectClassification: string
  17. relocationDays: number
  18. latestWellDoneTime: number
  19. currentDepth: number
  20. dailyFootage: number
  21. monthlyFootage: number
  22. annualFootage: number
  23. dailyPowerUsage: number
  24. monthlyPowerUsage: number
  25. dailyFuel: number
  26. monthlyFuel: number
  27. dailyOilVolume: number
  28. remainDieselVolume: number
  29. productionTime: number
  30. nonProductionTime: number
  31. ryNptReason: string
  32. drillingWorkingTime: number
  33. otherProductionTime: number
  34. accidentTime: number
  35. repairTime: number
  36. selfStopTime: number
  37. complexityTime: number
  38. relocationTime: number
  39. rectificationTime: number
  40. waitingStopTime: number
  41. winterBreakTime: number
  42. constructionStartDate: number
  43. constructionEndDate: number
  44. productionStatus: string
  45. currentOperation: string
  46. nextPlan: string
  47. rigStatus: string
  48. repairStatus: string
  49. personnel: string
  50. totalStaffNum: number
  51. leaveStaffNum: number
  52. mudDensity: number
  53. mudViscosity: number
  54. lateralLength: number
  55. wellInclination: number
  56. azimuth: number
  57. remark: string
  58. status: number
  59. processInstanceId: string
  60. auditStatus: number
  61. opinion: string
  62. createTime: number
  63. deptName: string
  64. contractName: string
  65. taskName: string
  66. designWellDepth: number
  67. designWellStruct: number
  68. totalConstructionWells: number
  69. completedWells: number
  70. equipmentType: string
  71. transitTime: number
  72. lastCurrentDepth: number
  73. }
  74. interface Column {
  75. prop?: keyof List
  76. label: string
  77. 'min-width'?: string
  78. isTag?: boolean
  79. fixed?: 'left' | 'right'
  80. formatter?: (row: List) => any
  81. children?: Column[]
  82. dictType?: string
  83. }
  84. const columns = ref<Column[]>([
  85. {
  86. label: '日期',
  87. prop: 'createTime',
  88. 'min-width': '120px',
  89. formatter: (row: List) => dayjs(row.createTime).format('YYYY-MM-DD'),
  90. fixed: 'left'
  91. },
  92. {
  93. label: '施工队伍',
  94. prop: 'deptName',
  95. 'min-width': '120px',
  96. fixed: 'left'
  97. },
  98. {
  99. label: '任务',
  100. prop: 'taskName',
  101. 'min-width': '120px',
  102. fixed: 'left'
  103. },
  104. {
  105. label: '施工状态',
  106. prop: 'rigStatus',
  107. 'min-width': '120px',
  108. isTag: true,
  109. dictType: DICT_TYPE.PMS_PROJECT_TASK_RY_SCHEDULE,
  110. fixed: 'left'
  111. },
  112. {
  113. label: '审批状态',
  114. prop: 'auditStatus',
  115. 'min-width': '120px',
  116. isTag: true,
  117. formatter: (row: List) => {
  118. switch (row.auditStatus) {
  119. case 0:
  120. return '待提交'
  121. case 10:
  122. return '待审批'
  123. case 20:
  124. return '审批通过'
  125. case 30:
  126. return '审批拒绝'
  127. default:
  128. return ''
  129. }
  130. }
  131. },
  132. {
  133. label: '设备型号',
  134. prop: 'equipmentType',
  135. 'min-width': '120px'
  136. },
  137. {
  138. label: '上井次完井时间',
  139. prop: 'latestWellDoneTime',
  140. 'min-width': '120px',
  141. formatter: (row: List) =>
  142. row.latestWellDoneTime ? dayjs(row.latestWellDoneTime).format('YYYY-MM-DD') : ''
  143. },
  144. {
  145. label: '井深(m)',
  146. children: [
  147. {
  148. label: '设计',
  149. prop: 'designWellDepth',
  150. 'min-width': '120px'
  151. },
  152. {
  153. label: '当前',
  154. prop: 'currentDepth',
  155. 'min-width': '120px'
  156. }
  157. ]
  158. },
  159. {
  160. label: '进尺(m)',
  161. children: [
  162. {
  163. label: '日',
  164. prop: 'dailyFootage',
  165. 'min-width': '120px'
  166. },
  167. {
  168. label: '月',
  169. prop: 'monthlyFootage',
  170. 'min-width': '120px'
  171. },
  172. {
  173. label: '年累计',
  174. prop: 'annualFootage',
  175. 'min-width': '120px'
  176. }
  177. ]
  178. },
  179. {
  180. label: '总施工井数',
  181. prop: 'totalConstructionWells',
  182. 'min-width': '120px'
  183. },
  184. {
  185. label: '完工井数',
  186. prop: 'completedWells',
  187. 'min-width': '120px'
  188. },
  189. {
  190. label: '泥浆性能',
  191. children: [
  192. {
  193. label: '密度(g/cm³)',
  194. prop: 'mudDensity',
  195. 'min-width': '120px'
  196. },
  197. {
  198. label: '粘度(S)',
  199. prop: 'mudViscosity',
  200. 'min-width': '120px'
  201. }
  202. ]
  203. },
  204. {
  205. label: '当日',
  206. children: [
  207. {
  208. label: '用电量(kWh)',
  209. prop: 'dailyPowerUsage',
  210. 'min-width': '120px'
  211. },
  212. {
  213. label: '油耗(吨)',
  214. prop: 'dailyFuel',
  215. 'min-width': '120px'
  216. }
  217. ]
  218. },
  219. // {
  220. // label: '施工开始日期',
  221. // prop: 'constructionStartDate',
  222. // 'min-width': '120px',
  223. // formatter: (row: List) => dayjs(row.constructionStartDate).format('YYYY-MM-DD HH:mm:ss')
  224. // },
  225. // {
  226. // label: '施工结束日期',
  227. // prop: 'constructionEndDate',
  228. // 'min-width': '120px',
  229. // formatter: (row: List) => dayjs(row.constructionEndDate).format('YYYY-MM-DD HH:mm:ss')
  230. // },
  231. {
  232. label: '水平段长度(m)',
  233. prop: 'lateralLength',
  234. 'min-width': '120px'
  235. },
  236. {
  237. label: '井斜(°)',
  238. prop: 'wellInclination',
  239. 'min-width': '120px'
  240. },
  241. {
  242. label: '方位(°)',
  243. prop: 'azimuth',
  244. 'min-width': '120px'
  245. },
  246. {
  247. label: '设计井身结构',
  248. prop: 'designWellStruct',
  249. 'min-width': '120px'
  250. },
  251. {
  252. label: '生产动态',
  253. prop: 'productionStatus',
  254. 'min-width': '120px'
  255. },
  256. {
  257. label: '项目',
  258. prop: 'contractName',
  259. 'min-width': '120px'
  260. },
  261. {
  262. label: '进尺工作时间(H)',
  263. prop: 'drillingWorkingTime',
  264. 'min-width': '120px'
  265. },
  266. {
  267. label: '其它生产时间(H)',
  268. prop: 'otherProductionTime',
  269. 'min-width': '120px'
  270. },
  271. {
  272. label: '非生产时间',
  273. children: [
  274. {
  275. label: '事故(H)',
  276. prop: 'accidentTime',
  277. 'min-width': '120px'
  278. },
  279. {
  280. label: '修理(H)',
  281. prop: 'repairTime',
  282. 'min-width': '120px'
  283. },
  284. {
  285. label: '自停(H)',
  286. prop: 'selfStopTime',
  287. 'min-width': '120px'
  288. },
  289. {
  290. label: '复杂(H)',
  291. prop: 'complexityTime',
  292. 'min-width': '120px'
  293. },
  294. {
  295. label: '搬迁(H)',
  296. prop: 'relocationTime',
  297. 'min-width': '120px'
  298. },
  299. {
  300. label: '整改(H)',
  301. prop: 'rectificationTime',
  302. 'min-width': '120px'
  303. },
  304. {
  305. label: '等停(H)',
  306. prop: 'waitingStopTime',
  307. 'min-width': '120px'
  308. },
  309. {
  310. label: '冬休(H)',
  311. prop: 'winterBreakTime',
  312. 'min-width': '120px'
  313. }
  314. ]
  315. }
  316. ])
  317. const getTextWidth = (text: string, fontSize = 12) => {
  318. const span = document.createElement('span')
  319. span.style.visibility = 'hidden'
  320. span.style.position = 'absolute'
  321. span.style.whiteSpace = 'nowrap'
  322. span.style.fontSize = `${fontSize}px`
  323. span.style.fontFamily = 'PingFang SC'
  324. span.innerText = text
  325. document.body.appendChild(span)
  326. const width = span.offsetWidth
  327. document.body.removeChild(span)
  328. return width
  329. }
  330. const calculateColumnWidths = (colums: Column[]) => {
  331. for (const col of colums) {
  332. let { formatter, prop, label, 'min-width': minWidth, isTag, children } = col
  333. if (children && children.length > 0) {
  334. calculateColumnWidths(children)
  335. continue
  336. }
  337. minWidth =
  338. Math.min(
  339. ...[
  340. Math.max(
  341. ...[
  342. getTextWidth(label),
  343. ...list.value.map((v) => {
  344. return getTextWidth(formatter ? formatter(v) : v[prop!])
  345. })
  346. ]
  347. ) + (isTag ? 40 : 20),
  348. 200
  349. ]
  350. ) + 'px'
  351. col['min-width'] = minWidth
  352. }
  353. }
  354. function checkTimeSumEquals24(row: List) {
  355. // 获取三个字段的值,转换为数字,如果为空则视为0
  356. const gasTime = row.drillingWorkingTime || 0
  357. const waterTime = row.otherProductionTime || 0
  358. const nonProdTime =
  359. row.accidentTime ||
  360. 0 + row.repairTime ||
  361. 0 + row.selfStopTime ||
  362. 0 + row.complexityTime ||
  363. 0 + row.relocationTime ||
  364. 0 + row.rectificationTime ||
  365. 0 + row.waitingStopTime ||
  366. 0 + row.winterBreakTime ||
  367. 0
  368. // 计算总和
  369. const sum = gasTime + waterTime + nonProdTime
  370. // 返回是否等于24(允许一定的浮点数误差)
  371. return Math.abs(sum - 24) < 0.01 // 使用0.01作为误差范围
  372. }
  373. function cellStyle(data: {
  374. row: List
  375. column: TableColumnCtx<List>
  376. rowIndex: number
  377. columnIndex: number
  378. }) {
  379. const { row, column } = data
  380. if (column.property === 'dailyFuel') {
  381. const originalValue = row.dailyFuel ?? 0
  382. if (originalValue > 15)
  383. return {
  384. color: 'red',
  385. fontWeight: 'bold'
  386. }
  387. }
  388. const timeFields = [
  389. 'drillingWorkingTime',
  390. 'otherProductionTime',
  391. 'accidentTime',
  392. 'repairTime',
  393. 'selfStopTime',
  394. 'complexityTime',
  395. 'relocationTime',
  396. 'rectificationTime',
  397. 'waitingStopTime',
  398. 'winterBreakTime'
  399. ]
  400. if (timeFields.includes(column.property)) {
  401. if (!checkTimeSumEquals24(row)) {
  402. return {
  403. color: 'orange',
  404. fontWeight: 'bold'
  405. }
  406. }
  407. }
  408. // 默认返回空对象,不应用特殊样式
  409. return {}
  410. }
  411. const id = useUserStore().getUser.deptId
  412. const deptId = id
  413. interface Query {
  414. pageNo: number
  415. pageSize: number
  416. deptId: number
  417. contractName?: string
  418. taskName?: string
  419. createTime: string[]
  420. projectClassification: '1' | '2'
  421. }
  422. const query = ref<Query>({
  423. pageNo: 1,
  424. pageSize: 10,
  425. deptId: id,
  426. createTime: [
  427. ...rangeShortcuts[3].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
  428. ],
  429. projectClassification: '1'
  430. })
  431. function handleSizeChange(val: number) {
  432. query.value.pageSize = val
  433. handleQuery()
  434. }
  435. function handleCurrentChange(val: number) {
  436. query.value.pageNo = val
  437. loadList()
  438. }
  439. const loading = ref(false)
  440. const list = ref<List[]>([])
  441. const total = ref(0)
  442. const loadList = useDebounceFn(async function () {
  443. loading.value = true
  444. try {
  445. const data = await IotRyDailyReportApi.getIotRyDailyReportPage(query.value)
  446. list.value = data.list
  447. total.value = data.total
  448. nextTick(() => {
  449. calculateColumnWidths(columns.value)
  450. })
  451. } finally {
  452. loading.value = false
  453. }
  454. }, 500)
  455. function handleQuery(setPage = true) {
  456. if (setPage) {
  457. query.value.pageNo = 1
  458. }
  459. loadList()
  460. }
  461. function resetQuery() {
  462. query.value = {
  463. pageNo: 1,
  464. pageSize: 10,
  465. deptId: 157,
  466. contractName: '',
  467. taskName: '',
  468. createTime: [
  469. ...rangeShortcuts[2].value().map((item) => dayjs(item).format('YYYY-MM-DD HH:mm:ss'))
  470. ],
  471. projectClassification: '1'
  472. }
  473. handleQuery()
  474. }
  475. watch(
  476. [
  477. () => query.value.createTime,
  478. () => query.value.deptId,
  479. () => query.value.taskName,
  480. () => query.value.contractName
  481. ],
  482. () => {
  483. handleQuery()
  484. },
  485. { immediate: true }
  486. )
  487. const FORM_KEYS = [
  488. 'id',
  489. 'deptName',
  490. 'contractName',
  491. 'taskName',
  492. 'rigStatus',
  493. 'designWellDepth',
  494. 'currentDepth',
  495. 'dailyPowerUsage',
  496. 'dailyFuel',
  497. 'mudDensity',
  498. 'mudViscosity',
  499. 'lateralLength',
  500. 'wellInclination',
  501. 'azimuth',
  502. 'designWellStruct',
  503. 'productionStatus',
  504. 'remark',
  505. 'createTime',
  506. 'deptId',
  507. 'projectId',
  508. 'taskId',
  509. 'opinion',
  510. 'personnel',
  511. 'accidentTime',
  512. 'repairTime',
  513. 'selfStopTime',
  514. 'complexityTime',
  515. 'relocationTime',
  516. 'rectificationTime',
  517. 'waitingStopTime',
  518. 'winterBreakTime',
  519. 'drillingWorkingTime',
  520. 'otherProductionTime',
  521. 'lastCurrentDepth'
  522. ] as const
  523. type FormKey = (typeof FORM_KEYS)[number]
  524. type Form = Partial<Pick<List, FormKey>>
  525. const dialogVisible = ref(false)
  526. const formRef = ref<FormInstance>()
  527. const formLoading = ref(false)
  528. const message = useMessage()
  529. const initFormData = (): Form => ({})
  530. const form = ref<Form>(initFormData())
  531. async function loadDetail(id: number) {
  532. try {
  533. const res = await IotRyDailyReportApi.getIotRyDailyReport(id)
  534. FORM_KEYS.forEach((key) => {
  535. form.value[key] = res[key] ?? form.value[key]
  536. })
  537. form.value.id = id
  538. if (res.auditStatus !== 10) {
  539. formType.value = 'readonly'
  540. }
  541. } finally {
  542. }
  543. }
  544. const formType = ref<'approval' | 'readonly'>('approval')
  545. function handleOpenForm(id: number, type: 'approval' | 'readonly') {
  546. form.value = initFormData()
  547. formRef.value?.resetFields()
  548. formType.value = type
  549. dialogVisible.value = true
  550. loadDetail(id).then(() => {
  551. formRef.value?.validate()
  552. })
  553. }
  554. const route = useRoute()
  555. onMounted(() => {
  556. if (Object.keys(route.query).length > 0) {
  557. handleOpenForm(Number(route.query.id), 'approval')
  558. }
  559. })
  560. // const transitTime = computed(() => {
  561. // const cap = form.value.capacity
  562. // const gas = form.value.dailyGasInjection ?? 0
  563. // if (!cap) return { original: 0, value: '0%' }
  564. // const original = gas / cap
  565. // return { original, value: (original * 100).toFixed(2) + '%' }
  566. // })
  567. const sumTimes = () => {
  568. const {
  569. drillingWorkingTime = 0,
  570. otherProductionTime = 0,
  571. accidentTime = 0,
  572. repairTime = 0,
  573. selfStopTime = 0,
  574. complexityTime = 0,
  575. relocationTime = 0,
  576. rectificationTime = 0,
  577. waitingStopTime = 0,
  578. winterBreakTime = 0
  579. } = form.value
  580. return parseFloat(
  581. (
  582. drillingWorkingTime +
  583. otherProductionTime +
  584. accidentTime +
  585. repairTime +
  586. selfStopTime +
  587. complexityTime +
  588. relocationTime +
  589. rectificationTime +
  590. waitingStopTime +
  591. winterBreakTime
  592. ).toFixed(2)
  593. )
  594. }
  595. const validateTotalTime = (_rule: any, _value: any, callback: any) => {
  596. const total = sumTimes()
  597. if (total !== 24) {
  598. callback(new Error(`当前合计 ${total} 小时,时间之和必须等于 24`))
  599. } else {
  600. callback()
  601. }
  602. }
  603. // const validateNptReason = (_rule: any, value: any, callback: any) => {
  604. // if ((form.value.nonProductionTime || 0) > 0 && !value) {
  605. // callback(new Error('非生产时间大于 0 时,必须选择原因'))
  606. // } else {
  607. // callback()
  608. // }
  609. // }
  610. const validateLastCurrentDepth = (_rule: any, value: any, callback: any) => {
  611. if (value && value < (form.value.lastCurrentDepth ?? 0)) {
  612. callback(new Error('当前深度需大于等于上一次填报深度'))
  613. } else {
  614. callback()
  615. }
  616. }
  617. const timeRuleItem = [
  618. { required: true, message: '请输入时间', trigger: 'blur' },
  619. { validator: validateTotalTime, trigger: 'blur' }
  620. ]
  621. const rules = reactive<FormRules>({
  622. currentDepth: [
  623. { required: true, message: '请输入当前深度', trigger: ['change', 'blur'] },
  624. { validator: validateLastCurrentDepth, trigger: ['change', 'blur'] }
  625. ],
  626. productionStatus: [{ required: true, message: '请输入生产动态', trigger: ['change', 'blur'] }],
  627. // 复用规则
  628. drillingWorkingTime: timeRuleItem,
  629. otherProductionTime: timeRuleItem,
  630. accidentTime: timeRuleItem,
  631. repairTime: timeRuleItem,
  632. selfStopTime: timeRuleItem,
  633. complexityTime: timeRuleItem,
  634. relocationTime: timeRuleItem,
  635. rectificationTime: timeRuleItem,
  636. waitingStopTime: timeRuleItem,
  637. winterBreakTime: timeRuleItem
  638. })
  639. watch(
  640. [
  641. () => form.value.drillingWorkingTime,
  642. () => form.value.otherProductionTime,
  643. () => form.value.accidentTime,
  644. () => form.value.repairTime,
  645. () => form.value.selfStopTime,
  646. () => form.value.complexityTime,
  647. () => form.value.relocationTime,
  648. () => form.value.rectificationTime,
  649. () => form.value.waitingStopTime,
  650. () => form.value.winterBreakTime
  651. ],
  652. () => {
  653. nextTick(() => {
  654. if (sumTimes() === 24) {
  655. formRef.value?.clearValidate([
  656. 'drillingWorkingTime',
  657. 'otherProductionTime',
  658. 'accidentTime',
  659. 'repairTime',
  660. 'selfStopTime',
  661. 'complexityTime',
  662. 'relocationTime',
  663. 'rectificationTime',
  664. 'waitingStopTime',
  665. 'winterBreakTime'
  666. ])
  667. }
  668. })
  669. }
  670. )
  671. const submitForm = async (auditStatus: 20 | 30) => {
  672. if (!formRef.value) return
  673. try {
  674. // await formRef.value.validate()
  675. formLoading.value = true
  676. const { opinion, id } = form.value
  677. const data = { id: id, auditStatus, opinion } as any
  678. await IotRyDailyReportApi.approvalIotRyDailyReport(data)
  679. message.success(auditStatus === 20 ? '通过成功' : '拒绝成功')
  680. dialogVisible.value = false
  681. loadList()
  682. } catch (error) {
  683. console.warn('表单校验未通过或提交出错')
  684. } finally {
  685. formLoading.value = false
  686. }
  687. }
  688. </script>
  689. <template>
  690. <div
  691. class="h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))] >"
  692. >
  693. <div class="grid grid-cols-[15%_1fr] gap-4 h-full">
  694. <div class="flex flex-col p-4 gap-2 bg-white dark:bg-[#1d1e1f] shadow rounded-lg h-full">
  695. <DeptTreeSelect :deptId="deptId" :topId="158" v-model="query.deptId" />
  696. </div>
  697. <div class="grid grid-rows-[62px_1fr] h-full gap-4">
  698. <el-form
  699. size="default"
  700. class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 gap-8 flex items-center justify-between"
  701. >
  702. <div class="flex items-center gap-8">
  703. <el-form-item label="项目">
  704. <el-input
  705. v-model="query.contractName"
  706. placeholder="请输入项目"
  707. clearable
  708. @keyup.enter="handleQuery()"
  709. class="!w-240px"
  710. />
  711. </el-form-item>
  712. <el-form-item label="任务">
  713. <el-input
  714. v-model="query.taskName"
  715. placeholder="请输入任务"
  716. clearable
  717. @keyup.enter="handleQuery()"
  718. class="!w-240px"
  719. />
  720. </el-form-item>
  721. <el-form-item label="创建时间">
  722. <el-date-picker
  723. v-model="query.createTime"
  724. value-format="YYYY-MM-DD HH:mm:ss"
  725. type="daterange"
  726. start-placeholder="开始日期"
  727. end-placeholder="结束日期"
  728. :shortcuts="rangeShortcuts"
  729. class="!w-220px"
  730. :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
  731. />
  732. </el-form-item>
  733. </div>
  734. <el-form-item>
  735. <el-button type="primary" @click="handleQuery()">
  736. <Icon icon="ep:search" class="mr-5px" /> 搜索
  737. </el-button>
  738. <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" />重置</el-button>
  739. </el-form-item>
  740. </el-form>
  741. <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg p-4 flex flex-col">
  742. <div class="flex-1 relative">
  743. <el-auto-resizer class="absolute">
  744. <template #default="{ width, height }">
  745. <el-table
  746. :data="list"
  747. v-loading="loading"
  748. stripe
  749. class="absolute"
  750. :max-height="height"
  751. show-overflow-tooltip
  752. :width="width"
  753. :cell-style="cellStyle"
  754. border
  755. >
  756. <DailyTableColumn :columns="columns" />
  757. <el-table-column label="操作" width="120px" align="center" fixed="right">
  758. <template #default="{ row }">
  759. <el-button
  760. link
  761. type="success"
  762. @click="handleOpenForm(row.id, 'readonly')"
  763. v-hasPermi="['pms:iot-ry-daily-report:update']"
  764. >
  765. 查看
  766. </el-button>
  767. <el-button
  768. v-show="row.auditStatus === 10"
  769. link
  770. type="primary"
  771. @click="handleOpenForm(row.id, 'approval')"
  772. v-hasPermi="['pms:iot-ry-daily-report:update']"
  773. >
  774. 审批
  775. </el-button>
  776. </template>
  777. </el-table-column>
  778. </el-table>
  779. </template>
  780. </el-auto-resizer>
  781. </div>
  782. <div class="h-10 mt-4 flex items-center justify-end">
  783. <el-pagination
  784. size="default"
  785. v-show="total > 0"
  786. v-model:current-page="query.pageNo"
  787. v-model:page-size="query.pageSize"
  788. :background="true"
  789. :page-sizes="[10, 20, 30, 50, 100]"
  790. :total="total"
  791. layout="total, sizes, prev, pager, next, jumper"
  792. @size-change="handleSizeChange"
  793. @current-change="handleCurrentChange"
  794. />
  795. </div>
  796. </div>
  797. </div>
  798. </div>
  799. <Dialog title="编辑" v-model="dialogVisible">
  800. <el-form
  801. ref="formRef"
  802. label-position="top"
  803. size="default"
  804. :rules="rules"
  805. :model="form"
  806. v-loading="formLoading"
  807. require-asterisk-position="right"
  808. >
  809. <div class="flex flex-col gap-3 text-sm">
  810. <div
  811. class="rounded-md border border-blue-100 bg-blue-50/80 p-3 dark:border-blue-900/30 dark:bg-blue-900/10"
  812. >
  813. <div class="flex flex-col gap-2.5">
  814. <div class="flex items-center justify-between">
  815. <div class="text-gray-600 dark:text-gray-400">
  816. <span class="font-bold text-gray-800 dark:text-gray-200"> 油量消耗:</span>
  817. 当日油耗
  818. </div>
  819. <span
  820. class="inline-flex items-center rounded border border-red-200 bg-red-100 px-2 py-0.5 text-xs font-medium text-red-600 dark:bg-red-900/20 dark:border-red-800 dark:text-red-400"
  821. >
  822. >15吨 红色预警
  823. </span>
  824. </div>
  825. <div class="flex items-center justify-between">
  826. <div class="text-gray-600 dark:text-gray-400">
  827. <span class="font-bold text-gray-800 dark:text-gray-200">时间平衡:</span>
  828. 进尺 + 其它生产 + 非生产 = 24H
  829. </div>
  830. <span
  831. class="inline-flex items-center rounded border border-orange-200 bg-orange-100 px-2 py-0.5 text-xs font-medium text-orange-600 dark:bg-orange-900/20 dark:border-orange-800 dark:text-orange-400"
  832. >
  833. ≠24H 橙色预警
  834. </span>
  835. </div>
  836. </div>
  837. </div>
  838. <!-- <div
  839. v-if="form.opinion"
  840. class="flex gap-3 rounded-md border border-yellow-200 bg-yellow-50 p-3 dark:border-yellow-800 dark:bg-yellow-900/10"
  841. >
  842. <Icon
  843. icon="ep:warning-filled"
  844. class="mt-0.5 shrink-0 text-base text-yellow-600 dark:text-yellow-500"
  845. />
  846. <div class="flex flex-col">
  847. <h4 class="mb-1 font-bold text-yellow-800 dark:text-yellow-500"> 审核意见 </h4>
  848. <p class="leading-relaxed text-gray-600 dark:text-gray-400">
  849. {{ form.opinion }}
  850. </p>
  851. </div>
  852. </div> -->
  853. </div>
  854. <div class="grid grid-cols-2 gap-4 mt-5">
  855. <el-form-item label="施工队伍" prop="deptName">
  856. <el-input v-model="form.deptName" placeholder="" disabled />
  857. </el-form-item>
  858. <el-form-item label="项目" prop="contractName">
  859. <el-input v-model="form.contractName" placeholder="" disabled />
  860. </el-form-item>
  861. <el-form-item label="任务" prop="taskName">
  862. <el-input v-model="form.taskName" placeholder="" disabled />
  863. </el-form-item>
  864. <el-form-item label="施工状态" prop="rigStatus">
  865. <el-select v-model="form.rigStatus" placeholder="请选择施工状态" disabled>
  866. <el-option
  867. v-for="(dict, index) in getStrDictOptions(DICT_TYPE.PMS_PROJECT_TASK_RY_SCHEDULE)"
  868. :key="index"
  869. :label="dict.label"
  870. :value="dict.value"
  871. />
  872. </el-select>
  873. </el-form-item>
  874. <el-form-item label="设计井深(m)" prop="designWellDepth">
  875. <el-input v-model="form.designWellDepth" placeholder="" disabled />
  876. </el-form-item>
  877. <el-form-item label="当前井深(m)" prop="currentDepth">
  878. <el-input-number
  879. class="placeholder-"
  880. :min="0"
  881. v-model="form.currentDepth"
  882. placeholder="请输入当前井深(m)"
  883. disabled
  884. />
  885. </el-form-item>
  886. <el-form-item label="当日用电量(kWh)" prop="dailyPowerUsage">
  887. <el-input-number
  888. :min="0"
  889. v-model="form.dailyPowerUsage"
  890. placeholder="请输入当日用电量(kWh)"
  891. clearable
  892. disabled
  893. />
  894. </el-form-item>
  895. <el-form-item label="当日油耗(吨)" prop="dailyFuel">
  896. <el-input-number
  897. :min="0"
  898. v-model="form.dailyFuel"
  899. placeholder="请输入当日油耗(吨)"
  900. clearable
  901. :class="{ 'warning-input': (form.dailyFuel ?? 0) > 15 }"
  902. disabled
  903. />
  904. </el-form-item>
  905. <el-form-item label="泥浆密度(g/cm³)" prop="mudDensity">
  906. <el-input-number
  907. :min="0"
  908. v-model="form.mudDensity"
  909. placeholder="请输入泥浆性能-密度(g/cm³)"
  910. clearable
  911. disabled
  912. />
  913. </el-form-item>
  914. <el-form-item label="泥浆粘度(S)" prop="mudViscosity">
  915. <el-input-number
  916. :min="0"
  917. v-model="form.mudViscosity"
  918. placeholder="请输入泥浆性能-粘度(S)"
  919. clearable
  920. disabled
  921. />
  922. </el-form-item>
  923. <el-form-item label="水平段长度(m)" prop="lateralLength">
  924. <el-input-number
  925. :min="0"
  926. v-model="form.lateralLength"
  927. placeholder="请输入水平段长度(m)"
  928. clearable
  929. disabled
  930. />
  931. </el-form-item>
  932. <el-form-item label="井斜(°)" prop="wellInclination">
  933. <el-input-number
  934. :min="0"
  935. v-model="form.wellInclination"
  936. placeholder="请输入井斜(°)"
  937. clearable
  938. disabled
  939. />
  940. </el-form-item>
  941. <el-form-item label="方位(°)" prop="azimuth">
  942. <el-input-number
  943. :min="0"
  944. v-model="form.azimuth"
  945. placeholder="请输入方位(°)"
  946. clearable
  947. disabled
  948. />
  949. </el-form-item>
  950. <el-form-item label="设计井身结构" prop="designWellStruct">
  951. <el-input
  952. v-model="form.designWellStruct"
  953. placeholder=""
  954. type="textarea"
  955. disabled
  956. autosize
  957. />
  958. </el-form-item>
  959. <!-- <el-form-item label="生产动态" prop="productionStatus">
  960. <el-input
  961. v-model="form.productionStatus"
  962. placeholder="请输入生产动态"
  963. type="textarea"
  964. autosize
  965. :max-length="1000"
  966. disabled
  967. />
  968. </el-form-item> -->
  969. <el-form-item label="人员情况" prop="personnel">
  970. <el-input
  971. v-model="form.personnel"
  972. placeholder="请输入人员情况"
  973. type="textarea"
  974. :max-length="1000"
  975. autosize
  976. disabled
  977. />
  978. </el-form-item>
  979. <!-- <el-form-item label="备注" prop="remark">
  980. <el-input
  981. v-model="form.remark"
  982. placeholder="请输入备注"
  983. :max-length="1000"
  984. type="textarea"
  985. autosize
  986. disabled
  987. />
  988. </el-form-item> -->
  989. </div>
  990. <el-divider content-position="left">生产时间</el-divider>
  991. <div class="grid grid-cols-2 gap-4 mt-5">
  992. <el-form-item label="进尺工作时间(H)" prop="drillingWorkingTime">
  993. <el-input-number
  994. class="w-full!"
  995. :min="0"
  996. v-model="form.drillingWorkingTime"
  997. placeholder="进尺工作时间(H)"
  998. disabled
  999. :class="{ 'orange-input': sumTimes() !== 24 }"
  1000. />
  1001. </el-form-item>
  1002. <el-form-item label="其它生产时间(H)" prop="otherProductionTime">
  1003. <el-input-number
  1004. class="w-full!"
  1005. :min="0"
  1006. v-model="form.otherProductionTime"
  1007. placeholder="其它生产时间(H)"
  1008. disabled
  1009. :class="{ 'orange-input': sumTimes() !== 24 }"
  1010. />
  1011. </el-form-item>
  1012. </div>
  1013. <el-divider content-position="left">非生产时间</el-divider>
  1014. <div class="grid grid-cols-4 gap-4 mt-5">
  1015. <el-form-item label="事故(H)" prop="accidentTime">
  1016. <el-input-number
  1017. class="w-full!"
  1018. :min="0"
  1019. v-model="form.accidentTime"
  1020. placeholder="请输入事故(H)"
  1021. disabled
  1022. :class="{ 'orange-input': sumTimes() !== 24 }"
  1023. />
  1024. </el-form-item>
  1025. <el-form-item label="修理(H)" prop="repairTime">
  1026. <el-input-number
  1027. class="w-full!"
  1028. :min="0"
  1029. v-model="form.repairTime"
  1030. placeholder="请输入修理(H)"
  1031. disabled
  1032. :class="{ 'orange-input': sumTimes() !== 24 }"
  1033. />
  1034. </el-form-item>
  1035. <el-form-item label="自停(H)" prop="selfStopTime">
  1036. <el-input-number
  1037. class="w-full!"
  1038. :min="0"
  1039. v-model="form.selfStopTime"
  1040. placeholder="请输入自停(H)"
  1041. disabled
  1042. :class="{ 'orange-input': sumTimes() !== 24 }"
  1043. />
  1044. </el-form-item>
  1045. <el-form-item label="复杂(H)" prop="complexityTime">
  1046. <el-input-number
  1047. class="w-full!"
  1048. :min="0"
  1049. v-model="form.complexityTime"
  1050. placeholder="请输入复杂(H)"
  1051. disabled
  1052. :class="{ 'orange-input': sumTimes() !== 24 }"
  1053. />
  1054. </el-form-item>
  1055. <el-form-item label="搬迁(H)" prop="relocationTime">
  1056. <el-input-number
  1057. class="w-full!"
  1058. :min="0"
  1059. v-model="form.relocationTime"
  1060. placeholder="请输入搬迁(H)"
  1061. disabled
  1062. :class="{ 'orange-input': sumTimes() !== 24 }"
  1063. />
  1064. </el-form-item>
  1065. <el-form-item label="整改(H)" prop="rectificationTime">
  1066. <el-input-number
  1067. class="w-full!"
  1068. :min="0"
  1069. v-model="form.rectificationTime"
  1070. placeholder="请输入整改(H)"
  1071. disabled
  1072. :class="{ 'orange-input': sumTimes() !== 24 }"
  1073. />
  1074. </el-form-item>
  1075. <el-form-item label="等停(H)" prop="waitingStopTime">
  1076. <el-input-number
  1077. class="w-full!"
  1078. :min="0"
  1079. v-model="form.waitingStopTime"
  1080. placeholder="请输入等停(H)"
  1081. disabled
  1082. :class="{ 'orange-input': sumTimes() !== 24 }"
  1083. />
  1084. </el-form-item>
  1085. <el-form-item label="冬休(H)" prop="winterBreakTime">
  1086. <el-input-number
  1087. class="w-full!"
  1088. :min="0"
  1089. v-model="form.winterBreakTime"
  1090. placeholder="请输入冬休(H)"
  1091. disabled
  1092. :class="{ 'orange-input': sumTimes() !== 24 }"
  1093. />
  1094. </el-form-item>
  1095. </div>
  1096. <div class="grid grid-cols-1 gap-4 mt-5">
  1097. <el-form-item label="生产动态" prop="productionStatus">
  1098. <el-input
  1099. v-model="form.productionStatus"
  1100. placeholder="请输入生产动态"
  1101. type="textarea"
  1102. autosize
  1103. :max-length="1000"
  1104. disabled
  1105. />
  1106. </el-form-item>
  1107. <el-form-item label="备注" prop="remark">
  1108. <el-input
  1109. v-model="form.remark"
  1110. placeholder="请输入备注"
  1111. :max-length="1000"
  1112. type="textarea"
  1113. autosize
  1114. disabled
  1115. />
  1116. </el-form-item>
  1117. </div>
  1118. <el-form-item class="mt-4" label="审批意见" prop="opinion">
  1119. <el-input
  1120. v-model="form.opinion"
  1121. placeholder="请输入审批意见"
  1122. :max-length="1000"
  1123. type="textarea"
  1124. autosize
  1125. :disabled="formType === 'readonly'"
  1126. />
  1127. </el-form-item>
  1128. </el-form>
  1129. <template #footer>
  1130. <el-button
  1131. size="default"
  1132. @click="submitForm(20)"
  1133. type="primary"
  1134. :disabled="formLoading || formType === 'readonly'"
  1135. >
  1136. 审批通过
  1137. </el-button>
  1138. <el-button
  1139. size="default"
  1140. @click="submitForm(30)"
  1141. type="danger"
  1142. :disabled="formLoading || formType === 'readonly'"
  1143. >
  1144. 审批拒绝
  1145. </el-button>
  1146. <el-button size="default" @click="dialogVisible = false">取 消</el-button>
  1147. </template>
  1148. </Dialog>
  1149. </div>
  1150. </template>
  1151. <style scoped>
  1152. :deep(.el-form-item) {
  1153. margin-bottom: 0;
  1154. }
  1155. :deep(.el-table) {
  1156. border-top-right-radius: 8px;
  1157. border-top-left-radius: 8px;
  1158. .el-table__cell {
  1159. height: 40px;
  1160. }
  1161. .el-table__header-wrapper {
  1162. .el-table__cell {
  1163. background: var(--el-fill-color-light);
  1164. }
  1165. }
  1166. }
  1167. :deep(.warning-input) {
  1168. .el-input__inner {
  1169. color: red !important;
  1170. -webkit-text-fill-color: red !important;
  1171. }
  1172. }
  1173. :deep(.orange-input) {
  1174. .el-input__inner {
  1175. color: orange !important;
  1176. -webkit-text-fill-color: orange !important;
  1177. }
  1178. }
  1179. :deep(.el-input-number) {
  1180. width: 100%;
  1181. }
  1182. :deep(.el-input-number__decrease) {
  1183. display: none !important;
  1184. }
  1185. :deep(.el-input-number__increase) {
  1186. display: none !important;
  1187. }
  1188. </style>