Просмотр исходного кода

feat(pms): 支持页面缓存和修井日报新增

- 启用设备详情和维修编辑页面缓存
- 新增维修编辑页缓存包装组件
- 为修井日报添加带权限控制的新增入口
- 新增表单自动带入左侧施工队伍
- 接入任务井选项接口并支持任务井选择
Zimo 3 недель назад
Родитель
Сommit
c2985c6eab

+ 16 - 0
src/api/pms/iotprojecttask/index.ts

@@ -21,6 +21,16 @@ export interface GenerateReportParams {
   reportDate: number
 }
 
+export interface TaskWellNameVO {
+  id: number
+  wellName: string
+}
+
+export interface TaskWellNameParams {
+  deptId: number
+  wellName: string
+}
+
 // 项目信息任务拆分 API
 export const IotProjectTaskApi = {
   // 查询项目信息任务拆分分页
@@ -30,6 +40,12 @@ export const IotProjectTaskApi = {
   getIotProjectTaskList: async (params: any) => {
     return await request.get({ url: `/rq/iot-project-task/list`, params })
   },
+  getTaskWellNames: async (params: TaskWellNameParams) => {
+    return await request.get<TaskWellNameVO[]>({
+      url: `/rq/iot-project-task/taskWellNames`,
+      params
+    })
+  },
   // 查询项目信息任务拆分详情
   getIotProjectTask: async (id: number) => {
     return await request.get({ url: `/rq/iot-project-task/get?id=` + id })

+ 3 - 3
src/router/modules/remaining.ts

@@ -516,7 +516,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
         component: () => import('@/views/pms/device/IotDeviceForm.vue'),
         name: 'DeviceDetailForm',
         meta: {
-          noCache: true,
+          noCache: false,
           hidden: true,
           canTo: true,
           icon: 'ep:document',
@@ -1103,10 +1103,10 @@ const remainingRouter: AppRouteRecordRaw[] = [
       },
       {
         path: 'maintain/edit/:id(\\d+)',
-        component: () => import('@/views/pms/maintain/IotMaintainAddEdit.vue'),
+        component: () => import('@/views/pms/maintain/IotMaintainEditPage.vue'),
         name: 'MaintainEdit',
         meta: {
-          noCache: true,
+          noCache: false,
           hidden: true,
           canTo: true,
           icon: 'ep:edit',

+ 2 - 0
src/views/pms/device/IotDeviceForm.vue

@@ -16,6 +16,8 @@ import type { IotModelVO } from '@/api/pms/model'
 import type { SupplierVO } from '@/api/supplier/base'
 import { useRefreshStore } from '@/store/modules/pms/refreshStore.js'
 
+defineOptions({ name: 'DeviceDetailForm' })
+
 type DynamicFieldType = 'text' | 'textarea' | 'date' | 'double' | 'int'
 
 interface DynamicField extends Omit<DeviceAttrModelData, 'code' | 'name' | 'type'> {

+ 64 - 7
src/views/pms/iotrydailyreport/ry-xj-form.vue

@@ -1,5 +1,6 @@
-<script lang="ts" setup generic="T">
+<script lang="ts" setup>
 import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
+import { IotProjectTaskApi } from '@/api/pms/iotprojecttask'
 import { useTableComponents } from '@/components/ZmTable/useTableComponents'
 import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
 import { calculateDuration, formatT } from '@/utils/formatTime'
@@ -15,6 +16,8 @@ const userStore = useUserStore()
 interface Props {
   visible: boolean
   type?: 'edit' | 'approval' | 'readonly'
+  deptId?: number
+  deptName?: string
   loadList: () => void
   noValidateStatus?: boolean
 }
@@ -159,7 +162,8 @@ const FORM_KEYS: (keyof FormOriginal)[] = [
 const formRef = ref<FormInstance>()
 const loading = ref(false)
 const formLoading = ref(false)
-const formType = ref<'edit' | 'readonly'>('edit')
+type FormMode = 'create' | 'edit' | 'readonly'
+const formType = ref<FormMode>('edit')
 const message = useMessage()
 const { t } = useI18n()
 
@@ -184,7 +188,41 @@ const isEdit = computed(() => props.type === 'edit')
 const isMainFieldDisabled = computed(() => formType.value === 'readonly' || isApproval.value)
 const isConstructionBriefDisabled = computed(() => formType.value === 'readonly')
 
-const wellOptions = ref<{ label: string; value: number }[]>([])
+interface WellOption {
+  label: string
+  value: number
+}
+
+const wellOptions = ref<WellOption[]>([])
+
+async function loadCreateTaskOptions() {
+  if (props.deptId === undefined) {
+    wellOptions.value = []
+    return
+  }
+
+  loading.value = true
+  try {
+    const tasks = await IotProjectTaskApi.getTaskWellNames({
+      deptId: props.deptId,
+      wellName: ''
+    })
+
+    wellOptions.value = tasks.map((task) => ({
+      label: task.wellName,
+      value: task.id
+    }))
+  } catch {
+    wellOptions.value = []
+    message.error('任务井加载失败')
+  } finally {
+    loading.value = false
+  }
+}
+
+function handleTaskChange(taskId: number) {
+  form.value.taskId = taskId
+}
 
 async function loadDetail(id: number) {
   loading.value = true
@@ -261,9 +299,21 @@ const removeProductionStatusRow = (index: number) => {
 
 const { ZmTable, ZmTableColumn } = useTableComponents<ReportDetail>()
 
-function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+function handleOpenForm(id: number | undefined, type: FormMode) {
   formType.value = type
   emits('update:visible', true)
+
+  if (id === undefined) {
+    wellOptions.value = []
+    form.value = initFormData()
+    form.value.deptId = props.deptId
+    form.value.deptName = props.deptName
+    addProductionStatusRow()
+    loadCreateTaskOptions()
+    nextTick(() => formRef.value?.clearValidate())
+    return
+  }
+
   loadDetail(id).then(() => {
     nextTick(() => formRef.value?.clearValidate())
   })
@@ -420,7 +470,9 @@ const submitForm = async () => {
     }
 
     await IotRyDailyReportApi.createIotRyDailyReport(submitData)
-    message.success(t('common.updateSuccess'))
+    message.success(
+      t(formType.value === 'create' ? 'common.createSuccess' : 'common.updateSuccess')
+    )
     emits('update:visible', false)
     props.loadList()
   } catch (error) {
@@ -498,7 +550,7 @@ const allocatedTimeDisabled = computed(() => {
     size="100%">
     <template #header>
       <span class="text-xl font-bold text-[var(--el-text-color-primary)]">
-        {{ type === 'edit' ? '编辑日报' : '审批日报' }}
+        {{ formType === 'create' ? '新增日报' : type === 'edit' ? '编辑日报' : '审批日报' }}
       </span>
     </template>
 
@@ -578,7 +630,12 @@ const allocatedTimeDisabled = computed(() => {
             v-model="form.taskId"
             placeholder="请选择任务井"
             :options="wellOptions"
-            :disabled="form.auditStatus !== 20 && form.auditStatus !== 30" />
+            filterable
+            @change="handleTaskChange"
+            :disabled="
+              formType === 'readonly' ||
+              (formType === 'edit' && form.auditStatus !== 20 && form.auditStatus !== 30)
+            " />
         </el-form-item>
         <el-form-item label="施工区域" prop="location">
           <el-input v-model="form.location" disabled />

+ 51 - 2
src/views/pms/iotrydailyreport/xfill.vue

@@ -1,5 +1,6 @@
 <script lang="ts" setup>
 import { IotRyDailyReportApi } from '@/api/pms/iotrydailyreport'
+import * as DeptApi from '@/api/system/dept'
 import { useUserStore } from '@/store/modules/user'
 import { resolveDailyReportDeptId } from '@/utils/dailyReportDept'
 import { rangeShortcuts } from '@/utils/formatTime'
@@ -72,6 +73,7 @@ function handleQuery(setPage = true) {
 
 function resetQuery() {
   query.value = { ...initQuery }
+  loadSelectedDeptName(query.value.deptId)
 
   handleQuery()
 }
@@ -93,7 +95,9 @@ const visible = ref(false)
 
 const formRef = ref()
 
-function handleOpenForm(id: number, type: 'edit' | 'readonly') {
+type FormMode = 'create' | 'edit' | 'readonly'
+
+function handleOpenForm(id: number | undefined, type: FormMode) {
   if (formRef.value) {
     formRef.value.handleOpenForm(id, type)
   }
@@ -101,7 +105,38 @@ function handleOpenForm(id: number, type: 'edit' | 'readonly') {
 
 const route = useRoute()
 
+interface DeptTreeNode {
+  id: number
+  name: string
+}
+
+const selectedDeptName = ref('')
+
+function handleDeptNodeClick(node: DeptTreeNode) {
+  selectedDeptName.value = node.name
+}
+
+async function loadSelectedDeptName(deptId?: number) {
+  if (deptId === undefined) {
+    selectedDeptName.value = ''
+    return
+  }
+
+  const currentDeptId = deptId
+  try {
+    const dept = await DeptApi.getDept(currentDeptId)
+    if (query.value.deptId === currentDeptId) {
+      selectedDeptName.value = dept.name
+    }
+  } catch {
+    if (query.value.deptId === currentDeptId) {
+      selectedDeptName.value = ''
+    }
+  }
+}
+
 onMounted(() => {
+  loadSelectedDeptName(query.value.deptId)
   if (Object.keys(route.query).length > 0) {
     handleOpenForm(Number(route.query.id), 'edit')
   }
@@ -117,6 +152,7 @@ onMounted(() => {
       v-model="query.deptId"
       :init-select="false"
       :show-title="false"
+      @node-click="handleDeptNodeClick"
       class="row-span-2" />
     <!-- <div class="p-4 bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-2"> </div> -->
     <el-form
@@ -156,6 +192,13 @@ onMounted(() => {
           <Icon icon="ep:search" class="mr-5px" /> 搜索
         </el-button>
         <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" />重置</el-button>
+        <el-button
+          type="primary"
+          plain
+          @click="handleOpenForm(undefined, 'create')"
+          v-hasPermi="['pms:iot-ry-daily-report:add']">
+          <Icon icon="ep:plus" class="mr-5px" /> 新增
+        </el-button>
       </el-form-item>
     </el-form>
     <ry-xj-table
@@ -185,7 +228,13 @@ onMounted(() => {
       </template>
     </ry-xj-table>
   </div>
-  <ry-xj-form v-model:visible="visible" type="edit" ref="formRef" :load-list="loadList" />
+  <ry-xj-form
+    v-model:visible="visible"
+    type="edit"
+    ref="formRef"
+    :dept-id="query.deptId"
+    :dept-name="selectedDeptName"
+    :load-list="loadList" />
 </template>
 
 <style scoped>

+ 9 - 0
src/views/pms/maintain/IotMaintainEditPage.vue

@@ -0,0 +1,9 @@
+<template>
+  <IotMaintainAddEdit />
+</template>
+
+<script setup lang="ts">
+import IotMaintainAddEdit from './IotMaintainAddEdit.vue'
+
+defineOptions({ name: 'MaintainEdit' })
+</script>