Browse Source

fix:瑞恒单井队生产动态字段不显示

yanghao 3 days ago
parent
commit
a177fe1aa7

+ 12 - 4
src/api/pms/iotopeationfill/plan/index.ts

@@ -8,12 +8,12 @@ export interface IotOperationPlanVO {
   planCycle: number // 周期
   planUnit: string // 单位
   charge: string // 负责人
-  charges: [],
-  chargeName: string,
+  charges: []
+  chargeName: string
   deviceIds: string // 设备
   remark: string // 备注
   deptId: number // 部门id
-  planDevList:[]
+  planDevList: []
 }
 
 // 巡检计划 API
@@ -47,11 +47,19 @@ export const IotOperationPlanApi = {
   exportIotOperationPlan: async (params) => {
     return await request.download({ url: `/rq/iot-operation-plan/export-excel`, params })
   },
-  updateIotOperationStatus : (id: number, status: number) => {
+  updateIotOperationStatus: (id: number, status: number) => {
     const data = {
       id,
       status
     }
     return request.put({ url: '/rq/iot-operation-plan/update-status', data: data })
+  },
+
+  // 根据部门手动生成当天的运行记录
+  manualGenerateByDeptId: async (deptId: number) => {
+    return await request.post<string>({
+      url: '/rq/iot-operation-plan/manual-generate',
+      params: { deptId }
+    })
   }
 }

+ 279 - 10
src/views/pms/device/statuslog/DeviceStatus.vue

@@ -1,11 +1,16 @@
 <script setup lang="ts">
 import { useTableComponents } from '@/components/ZmTable/useTableComponents'
 import { IotDeviceApi, IotDeviceVO } from '@/api/pms/device'
+import { IotOperationPlanApi } from '@/api/pms/iotopeationfill/plan'
+import * as DeptApi from '@/api/system/dept'
 import { useUserStore } from '@/store/modules/user'
 import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
 import download from '@/utils/download'
 import { rangeShortcuts } from '@/utils/formatTime'
+import { checkPermi } from '@/utils/permission'
+import { defaultProps, handleTree } from '@/utils/tree'
 import DeviceStatusLogDrawer from '@/views/pms/device/statuslog/DeviceStatusLogDrawer.vue'
+import type { FormInstance, FormRules } from 'element-plus'
 
 defineOptions({ name: 'IotDeviceStatus' })
 
@@ -20,7 +25,21 @@ interface QueryParams extends PageParam {
   createTime?: string[]
 }
 
+interface GenerateDeptOption {
+  id: number
+  name: string
+  parentId?: number
+  type?: string
+  disabled?: boolean
+  children?: GenerateDeptOption[]
+}
+
+interface GenerateRecordForm {
+  deptId?: number
+}
+
 const { t } = useI18n()
+const message = useMessage()
 const { push } = useRouter()
 const { ZmTable, ZmTableColumn } = useTableComponents<IotDeviceVO>()
 
@@ -50,6 +69,18 @@ const total = ref(0)
 const currentDeviceId = ref<number>()
 const drawerVisible = ref(false)
 const showDrawer = ref()
+const generateDialogVisible = ref(false)
+const generateLoading = ref(false)
+const generateDeptOptionsLoading = ref(false)
+const generateDeptOptions = ref<GenerateDeptOption[]>([])
+const generateFormRef = ref<FormInstance>()
+const generateForm = reactive<GenerateRecordForm>({
+  deptId: undefined
+})
+const generateFormRules: FormRules = {
+  deptId: [{ required: true, message: '请选择部门', trigger: 'change' }]
+}
+const generateDeptTreeProps = { ...defaultProps, disabled: 'disabled' }
 
 const resultOptions = computed(() => [
   {
@@ -129,6 +160,60 @@ const handleView = async (deviceId: number) => {
   })
 }
 
+const loadGenerateDeptOptions = async () => {
+  generateDeptOptionsLoading.value = true
+  try {
+    const depts = await DeptApi.specifiedSimpleDepts(deptId)
+    const selectableDepts = depts.map((item) => ({
+      ...item,
+      type: String(item.type || ''),
+      disabled: String(item.type || '') !== '3'
+    }))
+    generateDeptOptions.value = handleTree(selectableDepts)
+  } finally {
+    generateDeptOptionsLoading.value = false
+  }
+}
+
+const openGenerateDialog = async () => {
+  generateForm.deptId = undefined
+  generateDialogVisible.value = true
+  await nextTick()
+  generateFormRef.value?.clearValidate()
+  if (!generateDeptOptions.value.length) {
+    await loadGenerateDeptOptions()
+  }
+}
+
+const submitGenerateRecord = async () => {
+  if (!generateFormRef.value) return
+  const valid = await generateFormRef.value.validate().catch(() => false)
+  if (!valid || !generateForm.deptId) return
+
+  generateLoading.value = true
+  try {
+    const result = await IotOperationPlanApi.manualGenerateByDeptId(generateForm.deptId)
+    message.success(result)
+    generateDialogVisible.value = false
+  } finally {
+    generateLoading.value = false
+  }
+}
+
+const handleBusinessCommand = (command: string) => {
+  if (command === 'adjust-status') {
+    openForm()
+    return
+  }
+  if (command === 'generate-record') {
+    openGenerateDialog()
+    return
+  }
+  if (command === 'export') {
+    handleExport()
+  }
+}
+
 const handleExport = async () => {
   exportLoading.value = true
   try {
@@ -256,16 +341,29 @@ onMounted(() => {
         <el-button @click="resetQuery">
           <Icon icon="ep:refresh" class="mr-5px" />{{ t('devicePerson.reset') }}
         </el-button>
-        <el-button
-          type="primary"
-          plain
-          @click="openForm"
-          v-hasPermi="['pms:iot-device-status-log:create']">
-          <Icon icon="ep:plus" class="mr-5px" />{{ t('deviceStatus.setUp') }}
-        </el-button>
-        <el-button type="success" plain :loading="exportLoading" @click="handleExport">
-          <Icon icon="ep:download" class="mr-5px" />导出
-        </el-button>
+        <el-dropdown trigger="click" placement="bottom-end" @command="handleBusinessCommand">
+          <el-button plain :loading="exportLoading">
+            <Icon icon="ep:operation" class="mr-5px" />业务操作
+            <Icon icon="ep:arrow-down" class="ml-5px" />
+          </el-button>
+          <template #dropdown>
+            <el-dropdown-menu>
+              <el-dropdown-item
+                v-if="checkPermi(['pms:iot-device-status-log:create'])"
+                command="adjust-status">
+                <Icon icon="ep:refresh" class="mr-8px" />调整状态
+              </el-dropdown-item>
+              <el-dropdown-item
+                v-if="checkPermi(['rq:iot-operation-plan:create'])"
+                command="generate-record">
+                <Icon icon="ep:document-add" class="mr-8px" />生成记录
+              </el-dropdown-item>
+              <el-dropdown-item command="export" divided :disabled="exportLoading">
+                <Icon icon="ep:download" class="mr-8px" />导出数据
+              </el-dropdown-item>
+            </el-dropdown-menu>
+          </template>
+        </el-dropdown>
       </el-form-item>
     </el-form>
 
@@ -332,6 +430,75 @@ onMounted(() => {
     </div>
   </div>
 
+  <Dialog
+    v-model="generateDialogVisible"
+    :fullscreen="false"
+    width="560px"
+    class="generate-record-dialog">
+    <template #title>
+      <div class="generate-dialog-title">
+        <div class="generate-dialog-title__icon">
+          <Icon icon="ep:document-add" :size="22" />
+        </div>
+        <div>
+          <div class="generate-dialog-title__text">生成运行记录</div>
+          <div class="generate-dialog-title__desc">选择作业部门并生成今日运行填报记录</div>
+        </div>
+      </div>
+    </template>
+
+    <div class="generate-dialog-content">
+      <section class="generate-panel">
+        <div class="generate-panel__header">
+          <div class="generate-panel__title">
+            <span class="generate-panel__marker"></span>
+            <span>生成范围</span>
+          </div>
+        </div>
+        <div class="generate-panel__body">
+          <el-form
+            ref="generateFormRef"
+            :model="generateForm"
+            :rules="generateFormRules"
+            label-position="top"
+            size="default">
+            <el-form-item label="作业部门" prop="deptId">
+              <el-tree-select
+                v-model="generateForm.deptId"
+                :data="generateDeptOptions"
+                :props="generateDeptTreeProps"
+                :loading="generateDeptOptionsLoading"
+                node-key="id"
+                check-strictly
+                default-expand-all
+                filterable
+                clearable
+                placeholder="请选择三级部门"
+                class="w-full" />
+            </el-form-item>
+          </el-form>
+        </div>
+      </section>
+
+      <div class="generate-warning">
+        <div class="generate-warning__icon">
+          <Icon icon="ep:warning-filled" :size="18" />
+        </div>
+        <div class="generate-warning__text">
+          所选部门今日如已有运行记录,系统将删除原记录并按当前配置重新生成。
+        </div>
+      </div>
+    </div>
+    <template #footer>
+      <el-button :disabled="generateLoading" @click="generateDialogVisible = false">
+        取消
+      </el-button>
+      <el-button type="primary" :loading="generateLoading" @click="submitGenerateRecord">
+        <Icon v-if="!generateLoading" icon="ep:check" class="mr-5px" />确认生成
+      </el-button>
+    </template>
+  </Dialog>
+
   <DeviceStatusLogDrawer
     ref="showDrawer"
     :model-value="drawerVisible"
@@ -370,6 +537,108 @@ onMounted(() => {
   margin-left: 0;
 }
 
+.generate-dialog-title {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  padding-right: 44px;
+}
+
+.generate-dialog-title__icon {
+  display: flex;
+  width: 38px;
+  height: 38px;
+  color: var(--el-color-primary);
+  background: var(--el-color-primary-light-9);
+  border-radius: 8px;
+  align-items: center;
+  justify-content: center;
+}
+
+.generate-dialog-title__text {
+  font-size: 16px;
+  font-weight: 600;
+  line-height: 22px;
+  color: var(--el-text-color-primary);
+}
+
+.generate-dialog-title__desc {
+  margin-top: 2px;
+  font-size: 12px;
+  line-height: 18px;
+  color: var(--el-text-color-secondary);
+}
+
+.generate-dialog-content {
+  display: flex;
+  flex-direction: column;
+  gap: 14px;
+  padding: 3px;
+}
+
+.generate-panel {
+  overflow: hidden;
+  background: var(--el-bg-color);
+  border: 1px solid var(--el-border-color-lighter);
+  border-radius: 6px;
+  box-shadow: 0 8px 24px rgb(15 35 70 / 5%);
+}
+
+.generate-panel__header {
+  display: flex;
+  min-height: 52px;
+  padding: 0 16px;
+  background: #f4f9ff;
+  border-bottom: 1px solid var(--el-border-color-lighter);
+  align-items: center;
+}
+
+.generate-panel__title {
+  display: flex;
+  font-size: 15px;
+  font-weight: 600;
+  color: var(--el-text-color-primary);
+  align-items: center;
+}
+
+.generate-panel__marker {
+  width: 4px;
+  height: 18px;
+  margin-right: 10px;
+  background: var(--el-color-primary);
+  border-radius: 4px;
+}
+
+.generate-panel__body {
+  padding: 20px 18px 16px;
+}
+
+.generate-panel__body :deep(.el-form-item) {
+  margin-bottom: 10px;
+}
+
+.generate-warning {
+  display: flex;
+  gap: 10px;
+  padding: 13px 16px;
+  color: var(--el-color-warning-dark-2);
+  background: var(--el-color-warning-light-9);
+  border: 1px solid var(--el-color-warning-light-7);
+  border-radius: 6px;
+  align-items: center;
+}
+
+.generate-warning__icon {
+  display: flex;
+  flex: 0 0 auto;
+}
+
+.generate-warning__text {
+  font-size: 14px;
+  line-height: 22px;
+  color: var(--el-text-color-regular);
+}
+
 .query-control {
   width: 180px;
 }

+ 604 - 0
src/views/pms/iotopeationfill/indexNew.vue

@@ -0,0 +1,604 @@
+<template>
+  <div
+    class="operation-fill-page grid grid-cols-[auto_1fr] grid-rows-[auto_1fr] gap-4 h-[calc(100vh-20px-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))]">
+    <DeptTreeSelect
+      v-model="queryParams.deptId"
+      :dept-id="queryParams.deptId ?? userDeptId"
+      :top-id="rootDeptId"
+      :init-select="false"
+      :show-title="false"
+      request-api="getSimpleDeptList"
+      class="operation-fill-tree row-span-2"
+      @node-click="handleDeptNodeClick" />
+
+    <el-form
+      ref="queryFormRef"
+      :model="queryParams"
+      size="default"
+      label-width="68px"
+      class="operation-fill-query bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-6 py-3 min-w-0">
+      <div class="query-row">
+        <el-form-item :label="t('operationFill.name')" prop="fillContent">
+          <el-input
+            v-model="queryParams.fillContent"
+            :placeholder="t('operationFill.nameHolder')"
+            clearable
+            @keyup.enter="handleQuery"
+            class="query-control" />
+        </el-form-item>
+        <el-form-item :label="t('operationFill.status')" prop="orderStatus">
+          <el-select
+            v-model="queryParams.orderStatus"
+            :placeholder="t('operationFill.status')"
+            clearable
+            class="query-control">
+            <el-option
+              v-for="dict in getStrDictOptions(DICT_TYPE.OPERATION_FILL_ORDER_STATUS)"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item :label="t('operationFill.createTime')" prop="createTime" label-width="100px">
+          <el-date-picker
+            v-model="queryParams.createTime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            type="daterange"
+            :start-placeholder="t('operationFill.start')"
+            :end-placeholder="t('operationFill.end')"
+            :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+            class="query-control query-control--date" />
+        </el-form-item>
+      </div>
+
+      <el-form-item class="query-actions">
+        <el-button type="primary" @click="handleQuery">
+          <Icon icon="ep:search" class="mr-5px" />{{ t('operationFill.search') }}
+        </el-button>
+        <el-button @click="resetQuery">
+          <Icon icon="ep:refresh" class="mr-5px" />{{ t('operationFill.reset') }}
+        </el-button>
+      </el-form-item>
+    </el-form>
+
+    <div class="bg-white dark:bg-[#1d1e1f] shadow rounded-lg flex flex-col p-4 min-w-0 min-h-0">
+      <div class="flex-1 relative min-h-0">
+        <el-auto-resizer class="absolute">
+          <template #default="{ width, height }">
+            <ZmTable
+              :loading="loading"
+              :data="list"
+              :width="width"
+              :height="height"
+              :max-height="height"
+              show-border>
+              <ZmTableColumn :label="t('common.index')" width="70" align="center" fixed="left">
+                <template #default="scope">
+                  {{ scope.$index + 1 }}
+                </template>
+              </ZmTableColumn>
+              <ZmTableColumn
+                :label="t('bomList.name')"
+                align="center"
+                prop="orderName"
+                fixed="left" />
+              <ZmTableColumn :label="t('operationFill.duty')" align="center" prop="userName" />
+              <ZmTableColumn
+                :label="t('operationFill.orderDevice')"
+                align="center"
+                prop="fillList" />
+
+              <ZmTableColumn :label="t('operationFill.status')" align="center" prop="orderStatus">
+                <template #default="scope">
+                  <el-tooltip
+                    v-if="scope.row.orderStatus === 3"
+                    effect="dark"
+                    :content="scope.row.reason"
+                    placement="top">
+                    <dict-tag
+                      :type="DICT_TYPE.OPERATION_FILL_ORDER_STATUS"
+                      :value="scope.row.orderStatus" />
+                  </el-tooltip>
+                  <dict-tag
+                    v-else
+                    :type="DICT_TYPE.OPERATION_FILL_ORDER_STATUS"
+                    :value="scope.row.orderStatus" />
+                </template>
+              </ZmTableColumn>
+              <ZmTableColumn :label="t('operationFill.deviceCount')" align="center" prop="allDev">
+                <template #default="scope">
+                  <el-tag type="info"> {{ scope.row.allDev }}</el-tag>
+                </template>
+              </ZmTableColumn>
+              <ZmTableColumn :label="t('operationFill.fillCount')" align="center" prop="fillDev">
+                <template #default="scope">
+                  <el-tag type="success"> {{ scope.row.fillDev }}</el-tag>
+                </template>
+              </ZmTableColumn>
+              <ZmTableColumn
+                :label="t('operationFill.unFillCount')"
+                align="center"
+                prop="unFillDev">
+                <template #default="scope">
+                  <el-tag type="danger"> {{ scope.row.unFillDev }}</el-tag>
+                </template>
+              </ZmTableColumn>
+              <ZmTableColumn
+                :label="t('dict.createTime')"
+                align="center"
+                prop="createTime"
+                :formatter="dateFormatter"
+                min-width="170" />
+              <ZmTableColumn
+                :label="t('dict.fillTime')"
+                align="center"
+                prop="updateTime"
+                :formatter="dateFormatter"
+                min-width="170" />
+              <ZmTableColumn
+                :label="t('operationFill.operation')"
+                align="center"
+                min-width="120px"
+                fixed="right"
+                action>
+                <template #default="scope">
+                  <div v-if="scope.row.orderStatus == 0 || scope.row.orderStatus == 2">
+                    <el-button
+                      link
+                      type="primary"
+                      @click="
+                        openWrite(
+                          scope.row.deptId +
+                            ',' +
+                            scope.row.userId +
+                            ',' +
+                            scope.row.createTime +
+                            ',' +
+                            scope.row.id +
+                            ',' +
+                            scope.row.orderStatus
+                        )
+                      "
+                      v-hasPermi="['rq:iot-opeation-fill:update']"
+                      v-if="scope.row.orderStatus !== 1">
+                      {{ t('operationFill.fill') }}
+                    </el-button>
+                    <el-button
+                      link
+                      type="warning"
+                      v-hasPermi="['rq:iot-opeation-fill:update']"
+                      v-if="scope.row.orderStatus !== 1"
+                      @click="openDialog(scope.row.id)">
+                      {{ t('operationFill.ignore') }}
+                    </el-button>
+                  </div>
+                  <div v-else-if="scope.row.orderStatus === 3">
+                    <el-button
+                      link
+                      type="success"
+                      @click="
+                        openWrite(
+                          scope.row.deptId +
+                            ',' +
+                            scope.row.userId +
+                            ',' +
+                            scope.row.createTime +
+                            ',' +
+                            scope.row.id +
+                            ',' +
+                            scope.row.orderStatus
+                        )
+                      ">
+                      {{ t('operationFill.view') }}
+                    </el-button>
+                  </div>
+                  <div v-else>
+                    <el-button
+                      link
+                      type="primary"
+                      @click="
+                        openWrite(
+                          scope.row.deptId +
+                            ',' +
+                            scope.row.userId +
+                            ',' +
+                            scope.row.createTime +
+                            ',' +
+                            scope.row.id +
+                            ',' +
+                            0
+                        )
+                      "
+                      v-hasPermi="['rq:iot-opeation-fill:update']"
+                      v-if="isSameDay(scope.row.createTime)">
+                      {{ t('fault.edit') }}
+                    </el-button>
+                    <el-button
+                      link
+                      type="success"
+                      @click="
+                        openWrite(
+                          scope.row.deptId +
+                            ',' +
+                            scope.row.userId +
+                            ',' +
+                            scope.row.createTime +
+                            ',' +
+                            scope.row.id +
+                            ',' +
+                            scope.row.orderStatus
+                        )
+                      ">
+                      {{ t('operationFill.view') }}
+                    </el-button>
+                  </div>
+
+                  <!-- 编辑按钮 -->
+                </template>
+              </ZmTableColumn>
+            </ZmTable>
+          </template>
+        </el-auto-resizer>
+      </div>
+
+      <div class="h-8 mt-2 flex items-center justify-end">
+        <el-pagination
+          v-show="total > 0"
+          size="default"
+          :current-page="queryParams.pageNo"
+          :page-size="queryParams.pageSize"
+          :background="true"
+          :page-sizes="[10, 20, 30, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange" />
+      </div>
+    </div>
+  </div>
+
+  <el-dialog
+    v-model="dialogVisible"
+    title="忽略理由"
+    :width="600"
+    append-to-body
+    :close-on-click-modal="false">
+    <el-form ref="reasonFormRef" :model="form" :rules="rules" label-width="60px">
+      <el-form-item label="理由" prop="reason">
+        <el-input
+          v-model="form.reason"
+          type="textarea"
+          placeholder="请输入忽略理由"
+          :rows="4"
+          resize="none" />
+      </el-form-item>
+    </el-form>
+
+    <template #footer>
+      <el-button @click="handleCancel">取消</el-button>
+      <el-button type="primary" @click="handleConfirm">确定</el-button>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup lang="ts">
+import type { FormInstance } from 'element-plus'
+import { dateFormatter } from '@/utils/formatTime'
+import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
+import { onMounted, ref } from 'vue'
+import { IotOpeationFillApi, IotOpeationFillVO } from '@/api/pms/iotopeationfill'
+import { useUserStore } from '@/store/modules/user'
+import DeptTreeSelect from '@/components/DeptTreeSelect/index.vue'
+
+import { useTableComponents } from '@/components/ZmTable/useTableComponents'
+const { ZmTable, ZmTableColumn } = useTableComponents<IotOpeationFillVO>()
+const { push } = useRouter()
+const { query } = useRoute() // 查询参数
+const getQueryValue = (value: (typeof query)[string]) => (Array.isArray(value) ? value[0] : value)
+const deptId = getQueryValue(query.deptId)
+const orderStatus = getQueryValue(query.orderStatus)
+const createTime = getQueryValue(query.createTime)
+const rootDeptId = 156
+const userDeptId = useUserStore().getUser.deptId
+
+interface QueryParams extends PageParam {
+  fillContent?: string
+  createTime: string[]
+  deptId?: number | string
+  orderStatus?: string | number | null
+}
+
+interface IgnoreForm {
+  id?: number
+  reason: string
+}
+
+/** 巡检工单 列表 */
+defineOptions({ name: 'IotOpeationFill1' })
+const dialogVisible = ref(false)
+const { t } = useI18n() // 国际化
+const loading = ref(true) // 列表的加载中
+const list = ref<IotOpeationFillVO[]>([]) // 列表的数据
+const total = ref(0) // 列表的总页数
+const queryParams = reactive<QueryParams>({
+  pageNo: 1,
+  pageSize: 10,
+  fillContent: undefined,
+  createTime: [],
+  deptId: userDeptId,
+  orderStatus: undefined
+  //userId:useUserStore().getUser.id
+})
+
+const form = reactive<IgnoreForm>({
+  id: undefined,
+  reason: ''
+})
+
+// 表单验证规则
+const rules = {
+  reason: [
+    { required: true, message: '请输入忽略理由', trigger: 'blur' },
+    { min: 2, message: '理由长度不能少于2个字符', trigger: 'blur' }
+  ]
+}
+
+// 打开对话框
+const openDialog = (id: number) => {
+  dialogVisible.value = true
+  form.id = id
+  form.reason = ''
+}
+
+// 取消按钮处理
+const handleCancel = () => {
+  dialogVisible.value = false
+  resetForm()
+}
+
+// 确定按钮处理
+const handleConfirm = async () => {
+  // 表单验证
+  try {
+    await reasonFormRef.value?.validate()
+    // 验证通过,调用接口
+    await IotOpeationFillApi.updateIotOpeationFill1(form)
+    ElMessage.success('操作成功')
+    dialogVisible.value = false
+    resetForm()
+    await getList()
+  } catch (error) {
+    return
+  }
+}
+// 重置表单
+const resetForm = () => {
+  reasonFormRef.value?.resetFields()
+}
+const reasonFormRef = ref<FormInstance>()
+
+const queryFormRef = ref() // 搜索的表单
+
+// 判断两个日期是否为同一天
+const isSameDay = (dateString?: string) => {
+  if (!dateString) return false
+
+  // 将日期字符串转换为日期对象
+  const targetDate = new Date(dateString)
+  const today = new Date()
+
+  // 比较年、月、日
+  return (
+    targetDate.getFullYear() === today.getFullYear() &&
+    targetDate.getMonth() === today.getMonth() &&
+    targetDate.getDate() === today.getDate()
+  )
+}
+
+const handleDeptNodeClick = async (row: Tree) => {
+  queryParams.deptId = row.id
+  queryParams.pageNo = 1
+  await getList()
+}
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true
+  try {
+    const data = await IotOpeationFillApi.getOperationRecordPage(queryParams)
+    list.value = data.list
+    total.value = data.total
+  } finally {
+    loading.value = false
+  }
+}
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.pageNo = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields()
+  handleQuery()
+}
+
+const handleSizeChange = (val: number) => {
+  queryParams.pageSize = val
+  handleQuery()
+}
+
+const handleCurrentChange = (val: number) => {
+  queryParams.pageNo = val
+  getList()
+}
+
+const openWrite = (id?: string) => {
+  push({ name: 'FillOrderInfo', params: { id } })
+}
+
+/** 初始化 **/
+onMounted(async () => {
+  // 计算近一周时间
+  const end = new Date()
+  const start = new Date()
+  start.setTime(start.getTime() - 7 * 24 * 60 * 60 * 1000)
+
+  // 格式化日期为后端需要的格式
+  const formatDate = (date: Date) => {
+    const year = date.getFullYear()
+    const month = String(date.getMonth() + 1).padStart(2, '0')
+    const day = String(date.getDate()).padStart(2, '0')
+    const hours = String(date.getHours()).padStart(2, '0')
+    const minutes = String(date.getMinutes()).padStart(2, '0')
+    const seconds = String(date.getSeconds()).padStart(2, '0')
+    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
+  }
+
+  queryParams.createTime = [formatDate(start), formatDate(end)]
+
+  if (deptId != null) {
+    queryParams.deptId = deptId
+  }
+  if (orderStatus === '4') {
+    queryParams.orderStatus = null
+  }
+  if (orderStatus != null && orderStatus !== '4') {
+    queryParams.orderStatus = orderStatus
+  }
+  if (createTime) {
+    const timeArr = createTime.split(',')
+    if (timeArr.length === 2) {
+      queryParams.createTime = timeArr
+    } else {
+      // 处理格式不正确的情况,可以给个默认值或提示
+      console.warn('createTime参数格式不正确')
+    }
+    //queryParams.createTime = createTime;
+  }
+
+  getList()
+})
+</script>
+
+<style scoped>
+.operation-fill-query {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  justify-content: space-between;
+  gap: 12px 24px;
+}
+
+.query-row {
+  display: flex;
+  flex: 1 1 auto;
+  flex-wrap: wrap;
+  align-items: center;
+  gap: 12px 24px;
+  min-width: 0;
+}
+
+.query-actions {
+  flex: 0 0 auto;
+}
+
+.query-actions :deep(.el-form-item__content) {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 8px 10px;
+}
+
+.query-actions :deep(.el-button) {
+  margin-left: 0;
+}
+
+.query-control {
+  width: 180px;
+}
+
+.query-control--date {
+  width: 220px;
+}
+
+:deep(.el-form-item) {
+  margin-bottom: 0;
+}
+
+@media (width >= 2200px) {
+  .operation-fill-query,
+  .query-row {
+    flex-wrap: nowrap;
+  }
+}
+
+@media (width <= 1500px) {
+  .operation-fill-query {
+    gap: 12px 18px;
+  }
+
+  .query-row {
+    gap: 12px 18px;
+  }
+
+  .query-control {
+    width: 168px;
+  }
+
+  .query-control--date {
+    width: 210px;
+  }
+}
+
+@media (width <= 1200px) {
+  .operation-fill-page {
+    grid-template-columns: minmax(0, 1fr);
+    grid-template-rows: auto auto minmax(480px, 1fr);
+    height: auto;
+    min-height: calc(
+      100vh - 20px - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height)
+    );
+  }
+
+  :deep(.operation-fill-tree) {
+    grid-row: auto !important;
+    width: 100% !important;
+    height: 320px !important;
+    min-width: 0 !important;
+  }
+
+  .query-actions {
+    width: 100%;
+  }
+}
+
+@media (width <= 768px) {
+  .operation-fill-query {
+    padding: 12px;
+  }
+
+  .query-row,
+  .query-row :deep(.el-form-item),
+  .query-actions {
+    width: 100%;
+  }
+
+  .query-control,
+  .query-control--date {
+    width: 100%;
+  }
+
+  .query-actions :deep(.el-form-item__content) {
+    display: grid;
+    grid-template-columns: repeat(2, minmax(0, 1fr));
+    gap: 8px;
+    width: 100%;
+  }
+
+  .query-actions :deep(.el-button) {
+    width: 100%;
+    margin-left: 0;
+  }
+}
+</style>

+ 5 - 3
src/views/pms/stat/rdkb.vue

@@ -39,9 +39,11 @@ const targetWrapperStyle = computed(() => ({
 
 const targetAreaStyle = computed(() => {
   return {
-    '--kb-scale': scale.value,
-    width: `${DESIGN_WIDTH * scale.value}px`,
-    height: `${DESIGN_HEIGHT * scale.value}px`
+    '--kb-scale': 1,
+    width: `${DESIGN_WIDTH}px`,
+    height: `${DESIGN_HEIGHT}px`,
+    transform: `scale(${scale.value})`,
+    transformOrigin: 'top left'
   }
 })
 

+ 5 - 3
src/views/pms/stat/rhkb.vue

@@ -40,9 +40,11 @@ const targetWrapperStyle = computed(() => ({
 
 const targetAreaStyle = computed(() => {
   return {
-    '--kb-scale': scale.value,
-    width: `${DESIGN_WIDTH * scale.value}px`,
-    height: `${DESIGN_HEIGHT * scale.value}px`
+    '--kb-scale': 1,
+    width: `${DESIGN_WIDTH}px`,
+    height: `${DESIGN_HEIGHT}px`,
+    transform: `scale(${scale.value})`,
+    transformOrigin: 'top left'
   }
 })
 

+ 5 - 3
src/views/pms/stat/rykb.vue

@@ -39,9 +39,11 @@ const targetWrapperStyle = computed(() => ({
 
 const targetAreaStyle = computed(() => {
   return {
-    '--kb-scale': scale.value,
-    width: `${DESIGN_WIDTH * scale.value}px`,
-    height: `${DESIGN_HEIGHT * scale.value}px`
+    '--kb-scale': 1,
+    width: `${DESIGN_WIDTH}px`,
+    height: `${DESIGN_HEIGHT}px`,
+    transform: `scale(${scale.value})`,
+    transformOrigin: 'top left'
   }
 })