Эх сурвалжийг харах

设备责任人页面调整,两个树选择器调整 row-span 由外部传入

Zimo 3 өдөр өмнө
parent
commit
3dec6d7fa1

+ 53 - 14
src/components/DeptTreeSelect/index.vue

@@ -11,13 +11,19 @@ interface Tree {
   sort?: number
 }
 
+type RequestApi = 'specifiedSimpleDepts' | 'getSimpleDeptList'
+
 const props = defineProps({
   deptId: { type: Number, required: true },
   modelValue: { type: Number, default: undefined },
   topId: { type: Number, required: true },
   title: { type: String, default: '部门' },
   initSelect: { type: Boolean, default: true },
-  showTitle: { type: Boolean, default: true }
+  showTitle: { type: Boolean, default: true },
+  requestApi: {
+    type: String as PropType<RequestApi>,
+    default: 'specifiedSimpleDepts'
+  }
 })
 
 const emits = defineEmits(['update:modelValue', 'node-click'])
@@ -39,20 +45,47 @@ const sortTreeBySort = (treeNodes: Tree[]) => {
   return sortedNodes
 }
 
+const resolveFallbackId = (depts: Tree[], preferredId: number) => {
+  if (depts.some((item) => item.id === preferredId)) return preferredId
+  if (depts.some((item) => item.id === props.topId)) return props.topId
+  return depts[0]?.id
+}
+
+const loadDeptData = async () => {
+  if (props.requestApi === 'getSimpleDeptList') {
+    const depts = (await DeptApi.getSimpleDeptList()) as Tree[]
+    return {
+      depts,
+      currentId: resolveFallbackId(depts, props.deptId)
+    }
+  }
+
+  let id = props.deptId
+  if (id !== props.topId) {
+    const depts = await DeptApi.specifiedSimpleDepts(props.topId)
+    if (depts.length && !depts.find((item) => item.id === props.deptId)) id = props.topId
+  }
+  const depts = (await DeptApi.specifiedSimpleDepts(id)) as Tree[]
+  return {
+    depts,
+    currentId: id
+  }
+}
+
 const loadTree = async () => {
   try {
-    let id = props.deptId
-    if (id !== props.topId) {
-      const depts = await DeptApi.specifiedSimpleDepts(props.topId)
-      if (depts.length && !depts.find((item) => item.id === props.deptId)) id = props.topId
-    }
-    const res = await DeptApi.specifiedSimpleDepts(id)
-    if (props.initSelect && props.modelValue && !res.some((item) => item.id === props.modelValue)) {
-      emits('update:modelValue', id)
+    const { depts, currentId } = await loadDeptData()
+    if (
+      props.initSelect &&
+      props.modelValue &&
+      currentId !== undefined &&
+      !depts.some((item) => item.id === props.modelValue)
+    ) {
+      emits('update:modelValue', currentId)
     }
-    deptList.value = sortTreeBySort(handleTree(res))
+    deptList.value = sortTreeBySort(handleTree(depts))
     nextTick(() => {
-      const targetKey = props.modelValue ?? (props.initSelect ? id : null)
+      const targetKey = props.modelValue ?? (props.initSelect ? currentId : null)
       if (targetKey && treeRef.value) {
         treeRef.value.setCurrentKey(targetKey)
         if (!expandedKeys.value.includes(targetKey)) expandedKeys.value.push(targetKey)
@@ -73,7 +106,7 @@ const handleNodeClick = (data: Tree) => {
 const filterNode = (val: string, data: Tree) => !val || data.name.includes(val)
 
 watch(deptName, (val) => treeRef.value?.filter(val))
-watch(() => props.deptId, loadTree)
+watch(() => [props.deptId, props.topId, props.requestApi], loadTree)
 watch(
   () => props.modelValue,
   (val) => {
@@ -91,14 +124,20 @@ onMounted(loadTree)
 
 <template>
   <div
-    class="dept-aside-container relative bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-4 transition-all duration-300 ease-in-out overflow-visible"
+    class="dept-aside-container relative bg-white dark:bg-[#1d1e1f] shadow rounded-lg transition-all duration-300 ease-in-out overflow-visible"
     :class="[isCollapsed ? 'is-collapsed' : 'p-4']"
   >
     <div v-show="!isCollapsed" class="h-full flex flex-col gap-4 overflow-hidden w-full">
       <h1 v-if="showTitle" class="text-lg font-medium truncate shrink-0">{{ props.title }}</h1>
 
       <div class="shrink-0">
-        <el-input v-model="deptName" placeholder="请输入部门名称" clearable :prefix-icon="Search" />
+        <el-input
+          v-model="deptName"
+          placeholder="请输入部门名称"
+          clearable
+          size="default"
+          :prefix-icon="Search"
+        />
       </div>
 
       <div class="flex-1 relative overflow-hidden">

+ 2 - 1
src/components/DeviceCategoryTree/index.vue

@@ -115,7 +115,7 @@ onMounted(loadTree)
 
 <template>
   <div
-    class="device-category-aside relative bg-white dark:bg-[#1d1e1f] shadow rounded-lg row-span-2 transition-all duration-300 ease-in-out overflow-visible"
+    class="device-category-aside relative bg-white dark:bg-[#1d1e1f] shadow rounded-lg transition-all duration-300 ease-in-out overflow-visible"
     :class="[isCollapsed ? 'is-collapsed' : 'p-4']"
   >
     <div v-show="!isCollapsed" class="h-full flex flex-col gap-4 overflow-hidden w-full">
@@ -126,6 +126,7 @@ onMounted(loadTree)
           v-model="deviceCategoryName"
           placeholder="请输入设备分类名称"
           clearable
+          size="default"
           :prefix-icon="Search"
         />
       </div>

+ 253 - 264
src/views/pms/device/personlog/DevicePerson.vue

@@ -1,220 +1,66 @@
-<template>
-  <el-row :gutter="20">
-    <!-- 左侧部门树 -->
-    <DeptTree @node-click="handleDeptNodeClick" v-model:collapsed="isLeftContentCollapsed" />
-    <el-col :xs="24" :span="isLeftContentCollapsed ? 24 : 20">
-      <ContentWrap>
-        <!-- 搜索工作栏 -->
-        <el-form
-          class="-mb-15px"
-          :model="queryParams"
-          ref="queryFormRef"
-          :inline="true"
-          label-width="68px"
-        >
-          <el-form-item
-            :label="t('devicePerson.deviceCode')"
-            prop="deviceCode"
-            style="margin-left: 20px"
-          >
-            <el-input
-              v-model="queryParams.deviceCode"
-              :placeholder="t('devicePerson.codeHolder')"
-              clearable
-              @keyup.enter="handleQuery"
-              class="!w-200px"
-            />
-          </el-form-item>
-          <el-form-item :label="t('devicePerson.deviceName')" prop="deviceName">
-            <el-input
-              v-model="queryParams.deviceName"
-              :placeholder="t('devicePerson.nameHolder')"
-              clearable
-              @keyup.enter="handleQuery"
-              class="!w-200px"
-            />
-          </el-form-item>
-
-          <el-form-item
-            :label="t('devicePerson.responsiblePerson')"
-            prop="setFlag"
-            label-width="140px"
-          >
-            <el-select
-              v-model="queryParams.setFlag"
-              :placeholder="t('devicePerson.choose')"
-              clearable
-              class="!w-150px"
-            >
-              <el-option
-                v-for="dict in resultOptions"
-                :key="dict.value"
-                :label="dict.label"
-                :value="dict.value"
-              />
-            </el-select>
-          </el-form-item>
-          <el-form-item :label="t('devicePerson.rp')" prop="nickname">
-            <el-input
-              v-model="queryParams.nickname"
-              :placeholder="t('devicePerson.nicknameHolder')"
-              clearable
-              @keyup.enter="handleQuery"
-              class="!w-200px"
-            />
-          </el-form-item>
-          <el-form-item label="创建时间">
-            <el-date-picker
-              v-model="queryParams.createTime"
-              value-format="YYYY-MM-DD HH:mm:ss"
-              type="daterange"
-              start-placeholder="开始日期"
-              end-placeholder="结束日期"
-              :shortcuts="rangeShortcuts"
-              :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-              class="!w-220px"
-            />
-          </el-form-item>
-
-          <el-form-item>
-            <el-button @click="handleQuery"
-              ><Icon icon="ep:search" class="mr-5px" /> {{ t('devicePerson.search') }}</el-button
-            >
-            <el-button @click="resetQuery"
-              ><Icon icon="ep:refresh" class="mr-5px" /> {{ t('devicePerson.reset') }}</el-button
-            >
-            <el-button
-              type="primary"
-              plain
-              @click="openForm('create', undefined, queryParams.deptId)"
-              v-hasPermi="['pms:iot-device-person-log:create']"
-            >
-              <Icon icon="ep:plus" class="mr-5px" /> {{ t('devicePerson.setUp') }}
-            </el-button>
-            <!-- v-hasPermi="['rq:iot-device:export']" -->
-            <el-button type="success" plain @click="handleExport" :loading="exportLoading">
-              <Icon icon="ep:download" class="mr-5px" /> 导出
-            </el-button>
-          </el-form-item>
-        </el-form>
-      </ContentWrap>
-
-      <!-- 列表 -->
-      <ContentWrap>
-        <el-table
-          v-loading="loading"
-          :data="list"
-          :stripe="true"
-          height="calc(85vh - 175px)"
-          :show-overflow-tooltip="true"
-        >
-          <el-table-column :label="t('monitor.serial')" width="70" align="center">
-            <template #default="scope">
-              {{ scope.$index + 1 }}
-            </template>
-          </el-table-column>
-          <el-table-column :label="t('monitor.deviceCode')" align="center" prop="deviceCode" />
-          <el-table-column :label="t('monitor.deviceName')" align="center" prop="deviceName">
-            <template #default="scope">
-              <el-link :underline="false" type="primary" @click="handleDetail(scope.row.id)">
-                {{ scope.row.deviceName }}
-              </el-link>
-            </template>
-          </el-table-column>
-          <el-table-column :label="t('devicePerson.dept')" align="center" prop="deptName" />
-          <el-table-column :label="t('devicePerson.rp')" align="center" prop="responsibleNames" />
-          <el-table-column :label="t('devicePerson.operation')" align="center" min-width="120px">
-            <template #default="scope">
-              <el-button
-                link
-                type="primary"
-                @click="handleView(scope.row.id)"
-                v-hasPermi="['rq:iot-device:query']"
-              >
-                {{ t('devicePerson.adjustmentRecords') }}
-              </el-button>
-            </template>
-          </el-table-column>
-        </el-table>
-        <!-- 分页 -->
-        <Pagination
-          :total="total"
-          v-model:page="queryParams.pageNo"
-          v-model:limit="queryParams.pageSize"
-          @pagination="getList"
-        />
-      </ContentWrap>
-    </el-col>
-  </el-row>
-  <DevicePersonLogDrawer
-    :model-value="drawerVisible"
-    @update:model-value="(val) => (drawerVisible = val)"
-    :device-id="currentDeviceId"
-    ref="showDrawer"
-  />
-</template>
-
 <script setup lang="ts">
-import download from '@/utils/download'
+import { useTableComponents } from '@/components/ZmTable/useTableComponents'
 import { IotDeviceApi, IotDeviceVO } from '@/api/pms/device'
-import DeptTree from '@/views/system/user/DeptTree2.vue'
-import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
-import DevicePersonLogDrawer from '@/views/pms/device/personlog/DevicePersonLogDrawer.vue'
+import { useUserStore } from '@/store/modules/user'
+import download from '@/utils/download'
 import { rangeShortcuts } from '@/utils/formatTime'
+import DevicePersonLogDrawer from '@/views/pms/device/personlog/DevicePersonLogDrawer.vue'
 
-/** 设备台账 列表 */
 defineOptions({ name: 'IotDevicePerson' })
 
-const message = useMessage() // 消息弹窗
-const { t } = useI18n() // 国际化
-const { push } = useRouter() // 路由跳转
+type DevicePersonRow = IotDeviceVO & {
+  responsibleNames?: string
+}
+
+interface QueryParams extends PageParam {
+  deptId?: number
+  deviceCode?: string
+  deviceName?: string
+  setFlag?: string
+  nickname?: string
+  createTime?: string[]
+}
+
+const { t } = useI18n()
+const { push } = useRouter()
+const { ZmTable, ZmTableColumn } = useTableComponents<DevicePersonRow>()
 
-const loading = ref(true) // 列表的加载中
-const ifShow = ref(false)
-const list = ref<IotDeviceVO[]>([]) // 列表的数据
-const total = ref(0) // 列表的总页数
-let isLeftContentCollapsed = ref(false)
-const queryParams = reactive({
+const rootDeptId = 156
+const deptId = useUserStore().getUser.deptId || rootDeptId
+
+const initQuery: QueryParams = {
   pageNo: 1,
   pageSize: 10,
+  deptId: undefined,
   deviceCode: undefined,
   deviceName: undefined,
-  brand: undefined,
-  model: undefined,
-  deptId: undefined,
-  deviceStatus: undefined,
-  assetProperty: undefined,
-  picUrl: undefined,
-  remark: undefined,
-  manufacturerId: undefined,
-  supplierId: undefined,
-  manDate: [],
-  nameplate: undefined,
-  expires: undefined,
-  plPrice: undefined,
-  plDate: [],
-  plYear: undefined,
-  plStartDate: [],
-  plMonthed: undefined,
-  plAmounted: undefined,
-  remainAmount: undefined,
-  infoId: undefined,
-  infoType: undefined,
-  infoName: undefined,
-  infoRemark: undefined,
-  infoUrl: undefined,
-  templateJson: undefined,
-  creator: undefined,
   setFlag: '',
   nickname: '',
   createTime: []
-})
-const queryFormRef = ref() // 搜索的表单
-const exportLoading = ref(false) // 导出的加载中
-const contentSpan = ref(20)
-const treeShow = ref(true)
+}
+
+const queryParams = reactive<QueryParams>({ ...initQuery })
+const queryFormRef = ref()
+const loading = ref(false)
+const exportLoading = ref(false)
+const list = ref<DevicePersonRow[]>([])
+const total = ref(0)
+
+const resultOptions = computed(() => [
+  {
+    label: '全部',
+    value: 'A'
+  },
+  {
+    label: '是',
+    value: 'Y'
+  },
+  {
+    label: '否',
+    value: 'N'
+  }
+])
 
-/** 查询列表 */
 const getList = async () => {
   loading.value = true
   try {
@@ -226,35 +72,34 @@ const getList = async () => {
   }
 }
 
-/** 处理部门被点击 */
-const handleDeptNodeClick = async (row) => {
-  queryParams.deptId = row.id
-  await getList()
-}
-
-/** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNo = 1
   getList()
 }
-const moreQuery = (show) => {
-  ifShow.value = show
-}
-/** 重置按钮操作 */
+
 const resetQuery = () => {
-  queryFormRef.value.resetFields()
+  Object.assign(queryParams, { ...initQuery })
+  queryFormRef.value?.resetFields()
   handleQuery()
 }
 
-/** 添加/修改操作 */
-const formRef = ref()
-const openForm = (type: string, id?: number) => {
-  //修改
-  if (typeof id === 'number') {
-    push({ name: 'DeviceDetailEdit', params: { id } })
-    return
-  }
-  // 新增 传递当前选中的部门ID
+const handleSizeChange = (val: number) => {
+  queryParams.pageSize = val
+  handleQuery()
+}
+
+const handleCurrentChange = (val: number) => {
+  queryParams.pageNo = val
+  getList()
+}
+
+const handleDeptNodeClick = async (row: Tree) => {
+  queryParams.deptId = row.id
+  queryParams.pageNo = 1
+  await getList()
+}
+
+const openForm = () => {
   push({
     name: 'ConfigDevicePerson',
     query: {
@@ -263,70 +108,214 @@ const openForm = (type: string, id?: number) => {
   })
 }
 
-/** 删除按钮操作 */
-const handleDelete = async (id: number) => {
-  try {
-    // 删除的二次确认
-    await message.delConfirm()
-    // 发起删除
-    await IotDeviceApi.deleteIotDevice(id)
-    message.success(t('common.delSuccess'))
-    // 刷新列表
-    await getList()
-  } catch {}
-}
-
-// 是否设置过责任人 下拉列表 模拟字典项
-const resultOptions = computed(() => [
-  {
-    label: '全部',
-    value: 'A' // 空值会触发 clearable 效果
-  },
-  {
-    label: '是',
-    value: 'Y' // 空值会触发 clearable 效果
-  },
-  {
-    label: '否',
-    value: 'N' // 空值会触发 clearable 效果
-  }
-])
-
 const handleDetail = (id: number) => {
   push({ name: 'DeviceDetailInfo', params: { id } })
 }
 
-/** 查看设备责任人调整详情 */
-const currentDeviceId = ref() // 设备id
-const drawerVisible = ref<boolean>(false)
+const currentDeviceId = ref<number>()
+const drawerVisible = ref(false)
 const showDrawer = ref()
 
 const handleView = async (deviceId: number) => {
   currentDeviceId.value = deviceId
   drawerVisible.value = true
-  // 强制重新加载数据
   nextTick(() => {
     showDrawer.value?.loadDevicePersons(deviceId)
   })
-  showDrawer.value.openDrawer()
 }
 
-/** 导出按钮操作 */
 const handleExport = async () => {
+  exportLoading.value = true
   try {
     const data = await IotDeviceApi.exportIotDevicePerson(queryParams)
     download.excel(data, '设备责任人.xls')
-  } catch {
   } finally {
     exportLoading.value = false
   }
 }
-const { wsCache } = useCache()
-/** 初始化 **/
+
 onMounted(() => {
-  const user = wsCache.get(CACHE_KEY.USER)
-  // queryParams.deptId = user.user.deptId
   getList()
 })
 </script>
-<style scoped></style>
+
+<template>
+  <div
+    class="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
+      :top-id="rootDeptId"
+      :deptId="deptId"
+      v-model="queryParams.deptId"
+      :init-select="false"
+      :show-title="false"
+      request-api="getSimpleDeptList"
+      @node-click="handleDeptNodeClick"
+      class="row-span-2"
+    />
+
+    <el-form
+      ref="queryFormRef"
+      :model="queryParams"
+      size="default"
+      label-width="68px"
+      class="bg-white dark:bg-[#1d1e1f] rounded-lg shadow px-8 py-3 gap-6 flex items-center justify-between flex-wrap min-w-0"
+    >
+      <div class="flex items-center gap-6 flex-wrap">
+        <el-form-item :label="t('devicePerson.deviceCode')" prop="deviceCode">
+          <el-input
+            v-model="queryParams.deviceCode"
+            :placeholder="t('devicePerson.codeHolder')"
+            clearable
+            class="!w-180px"
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item :label="t('devicePerson.deviceName')" prop="deviceName">
+          <el-input
+            v-model="queryParams.deviceName"
+            :placeholder="t('devicePerson.nameHolder')"
+            clearable
+            class="!w-180px"
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item
+          :label="t('devicePerson.responsiblePerson')"
+          prop="setFlag"
+          label-width="120px"
+        >
+          <el-select
+            v-model="queryParams.setFlag"
+            :placeholder="t('devicePerson.choose')"
+            clearable
+            class="!w-140px"
+          >
+            <el-option
+              v-for="dict in resultOptions"
+              :key="dict.value"
+              :label="dict.label"
+              :value="dict.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item :label="t('devicePerson.rp')" prop="nickname">
+          <el-input
+            v-model="queryParams.nickname"
+            :placeholder="t('devicePerson.nicknameHolder')"
+            clearable
+            class="!w-180px"
+            @keyup.enter="handleQuery"
+          />
+        </el-form-item>
+        <el-form-item label="创建时间" prop="createTime">
+          <el-date-picker
+            v-model="queryParams.createTime"
+            value-format="YYYY-MM-DD HH:mm:ss"
+            type="daterange"
+            start-placeholder="开始日期"
+            end-placeholder="结束日期"
+            :shortcuts="rangeShortcuts"
+            :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
+            class="!w-220px"
+          />
+        </el-form-item>
+      </div>
+
+      <el-form-item>
+        <el-button type="primary" @click="handleQuery">
+          <Icon icon="ep:search" class="mr-5px" />{{ t('devicePerson.search') }}
+        </el-button>
+        <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-person-log:create']"
+        >
+          <Icon icon="ep:plus" class="mr-5px" />{{ t('devicePerson.setUp') }}
+        </el-button>
+        <el-button type="success" plain :loading="exportLoading" @click="handleExport">
+          <Icon icon="ep:download" class="mr-5px" />导出
+        </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">
+      <div class="flex-1 relative min-h-0">
+        <el-auto-resizer class="absolute">
+          <template #default="{ width, height }">
+            <ZmTable
+              :data="list"
+              :loading="loading"
+              :width="width"
+              :height="height"
+              :max-height="height"
+              show-border
+            >
+              <ZmTableColumn
+                type="index"
+                :label="t('monitor.serial')"
+                :width="70"
+                fixed="left"
+                hide-in-column-settings
+              />
+              <ZmTableColumn prop="deviceCode" :label="t('monitor.deviceCode')" fixed="left" />
+              <ZmTableColumn prop="deviceName" :label="t('monitor.deviceName')" fixed="left">
+                <template #default="{ row }">
+                  <el-link :underline="false" type="primary" @click="handleDetail(row.id)">
+                    {{ row.deviceName }}
+                  </el-link>
+                </template>
+              </ZmTableColumn>
+              <ZmTableColumn prop="deptName" :label="t('devicePerson.dept')" />
+              <ZmTableColumn prop="responsibleNames" :label="t('devicePerson.rp')" />
+              <ZmTableColumn :label="t('devicePerson.operation')" width="150" fixed="right" action>
+                <template #default="{ row }">
+                  <el-button
+                    link
+                    type="primary"
+                    @click="handleView(row.id)"
+                    v-hasPermi="['rq:iot-device:query']"
+                  >
+                    {{ t('devicePerson.adjustmentRecords') }}
+                  </el-button>
+                </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>
+
+  <DevicePersonLogDrawer
+    ref="showDrawer"
+    :model-value="drawerVisible"
+    :device-id="currentDeviceId"
+    @update:model-value="(val) => (drawerVisible = val)"
+  />
+</template>
+
+<style scoped>
+:deep(.el-form-item) {
+  margin-bottom: 0;
+}
+</style>

+ 1 - 0
src/views/pms/devicetemplate/index.vue

@@ -179,6 +179,7 @@ onMounted(() => {
       v-model="queryParams.deviceCategoryId"
       :show-title="false"
       @node-click="handleDeviceCategoryTreeNodeClick"
+      class="row-span-2"
     />
 
     <el-form