Browse Source

Merge remote-tracking branch 'origin/master'

lipenghui 2 tháng trước cách đây
mục cha
commit
f9fcd19646

+ 10 - 0
src/api/pms/device/index.ts

@@ -55,6 +55,16 @@ export const IotDeviceApi = {
     return await request.get({ url: `/rq/iot-device/deviceDynamicsPage`, params })
   },
 
+  // 获得设备状态调整数据 分页
+  statusRelationDevices: async (params: any) => {
+    return await request.get({ url: `/rq/iot-device/statusRelationDevices`, params })
+  },
+
+  // 获得设备调拨数据 分页
+  allotRelationDevices: async (params: any) => {
+    return await request.get({ url: `/rq/iot-device/allotRelationDevices`, params })
+  },
+
   // 获得设备关联责任人 分页
   simpleDevices: async (params: any) => {
     return await request.get({ url: `/rq/iot-device/simple-list`, params })

+ 41 - 0
src/views/pms/device/ConfigDeviceAllot.vue

@@ -96,6 +96,8 @@ import {defaultProps, handleTree} from "@/utils/tree";
 import * as DeptApi from "@/api/system/dept";
 import {IotDeviceApi, IotDeviceVO} from "@/api/pms/device";
 import DeptTree2 from "@/views/pms/device/DeptTree2.vue";
+import { useRouter } from 'vue-router'
+const router = useRouter()
 
 defineOptions({ name: 'ConfigDeviceAllot' })
 const selectedDeptId = ref<number | string>('')
@@ -181,6 +183,18 @@ watch([selectedDevices, selectedDeptId], () => {
 
 // 修改部门变更处理方法
 const handleDeptChange = (deptId) => {
+  if (!deptId) {
+    selectedDeptId.value = ''
+    return
+  }
+  // 校验部门选择
+  if (!validateDeptSelection(deptId)) {
+    // 重置部门选择
+    selectedDeptId.value = ''
+    deptTreeRef.value?.treeRef?.setCurrentKey(undefined) // 清除树的选择状态
+    deptTreeRef.value?.treeRef?.setCurrentNode(null)
+    return
+  }
   selectedDeptId.value = deptId
   updateTempRelations()
 }
@@ -205,6 +219,24 @@ const getDeviceList = async () => {
   }
 }
 
+// 计算选中的设备原部门集合
+const originDeptIds = computed(() =>
+  selectedDevices.value
+    .map(deviceId =>
+      simpleDevices.value.find(d => d.id === deviceId)?.deptId
+    )
+    .filter(Boolean) as number[]
+)
+
+// 部门选择校验方法
+const validateDeptSelection = (deptId: number) => {
+  if (originDeptIds.value.includes(deptId)) {
+    ElMessage.error('不能选择设备原属部门作为调拨部门')
+    return false
+  }
+  return true
+}
+
 const removeTempRelation = (deviceId: number) => {
   tempRelationsMap.value.delete(deviceId)
   selectedDevices.value = selectedDevices.value.filter(id => id !== deviceId)
@@ -212,6 +244,14 @@ const removeTempRelation = (deviceId: number) => {
 
 const submitRelations = async () => {
   try {
+    // 提交前二次校验
+    const invalidDept = tempRelations.value.some(r =>
+      originDeptIds.value.includes(r.deptId)
+    )
+    if (invalidDept) {
+      ElMessage.error('存在调拨部门与设备原属部门相同的情况,请检查')
+      return
+    }
     // 转换为后端需要的格式
     const submitData = tempRelations.value.map(r => ({
       deviceId: r.deviceId,
@@ -223,6 +263,7 @@ const submitRelations = async () => {
     console.log('提交数据:', submitData)
     ElMessage.success('提交成功')
     tempRelations.value = []
+    router.back()
   } catch (error) {
     ElMessage.error('提交失败,请重试')
   }

+ 64 - 64
src/views/pms/device/ConfigDevicePerson.vue

@@ -70,33 +70,47 @@
     </el-row>
 
     <!-- 暂存关联列表 -->
-    <div class="temp-list card">
-      <h3>设备责任人调整记录</h3>
-      <el-table :data="tempRelations" style="width: 100%">
-        <el-table-column prop="deviceNames" label="设备" width="200" />
-        <el-table-column prop="userNames" label="关联责任人" />
-        <el-table-column label="操作" width="120">
-          <template #default="{ row }">
-            <el-button
-              type="danger"
-              size="small"
-              @click="removeTempRelation(row.deviceIds)"
-            >
-              删除
-            </el-button>
-          </template>
-        </el-table-column>
-      </el-table>
-
-      <div class="submit-area">
-        <el-button
-          type="primary"
-          size="large"
-          @click="submitRelations"
-          :disabled="tempRelations.length === 0"
-        >
-          保 存
-        </el-button>
+    <div class="submit-area">
+      <div class="card">
+        <el-input
+          v-model="formData.reason"
+          placeholder="请输入调整原因"
+          class="reason-input"
+          type="textarea"
+          :rows="3"
+          @input="handleReasonInput"
+          :disabled="!selectedDevice || selectedUsers.length === 0"
+        />
+      </div>
+      <div class="temp-list card">
+        <h3>设备责任人调整记录</h3>
+        <el-table :data="tempRelations" style="width: 100%">
+          <el-table-column prop="deviceNames" label="设备" width="200" />
+          <el-table-column prop="userNames" label="关联责任人" />
+          <el-table-column prop="reason" label="调整原因" />
+          <el-table-column label="操作" width="120">
+            <template #default="{ row }">
+              <el-button
+                type="danger"
+                size="small"
+                @click="removeTempRelation(row.deviceIds)"
+              >
+                删除
+              </el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <div class="submit-area">
+          <el-button
+            type="primary"
+            size="large"
+            @click="submitRelations"
+            :disabled="tempRelations.length === 0"
+          >
+            保 存
+          </el-button>
+        </div>
       </div>
     </div>
   </div>
@@ -111,17 +125,11 @@ import {IotDeviceApi, IotDeviceVO} from "@/api/pms/device";
 import {IotDevicePersonApi, IotDevicePersonVO} from "@/api/pms/iotdeviceperson";
 import * as UserApi from "@/api/system/user";
 import {simpleUserList, UserVO} from "@/api/system/user";
+import { useRouter } from 'vue-router'
+const router = useRouter()
 
 defineOptions({ name: 'ConfigDevicePerson' })
 
-// 模拟数据
-const deviceList = ref([
-  { id: 'd1', name: '数控机床', type: '生产设备' },
-  { id: 'd2', name: '检测仪', type: '检测设备' },
-  { id: 'd3', name: '包装机', type: '包装设备' },
-  // 更多设备...
-])
-
 const simpleDevices = ref<IotDeviceVO[]>([])
 const simpleUsers = ref<UserVO[]>([])
 
@@ -137,6 +145,7 @@ const formData = ref({
   deptId1: undefined as string | undefined,
   deviceStatus: undefined,
   assetProperty: undefined,
+  reason: '',
   picUrl: undefined,
 })
 
@@ -147,19 +156,6 @@ const queryParams = reactive({
 
 const emit = defineEmits(['success', 'node-click']) // 定义 success 树点击 事件,用于操作成功后的回调
 
-const departmentList = ref([
-  { id: 'dept1', name: '生产部' },
-  { id: 'dept2', name: '质检部' },
-  { id: 'dept3', name: '设备部' },
-])
-
-const userList = ref([
-  { id: 'u1', name: '张三', position: '工程师', deptId: 'dept1' },
-  { id: 'u2', name: '李四', position: '技术员', deptId: 'dept1' },
-  { id: 'u3', name: '王五', position: '质检员', deptId: 'dept2' },
-  // 更多用户...
-])
-
 // 响应式数据
 const selectedDevice = ref<number>(0)
 const selectedDept = ref('')
@@ -169,22 +165,9 @@ const tempRelations = ref<Array<{
   deviceNames: string
   userIds: number[]
   userNames: string
+  reason: string
 }>>([])
 
-// 计算属性
-const filteredUsers = computed(() => {
-  return userList.value.filter(user => user.deptId === selectedDept.value)
-})
-
-const canSave = computed(() => {
-  return !!selectedDevice.value && selectedUsers.value.length > 0
-})
-
-// 方法
-const loadUsers = () => {
-  selectedUsers.value = []
-}
-
 // 添加设备选择监听
 watch(selectedDevice, (newVal) => {
   if (newVal) {
@@ -192,6 +175,7 @@ watch(selectedDevice, (newVal) => {
     selectedUsers.value = []
     // 可选:清空部门选择
     formData.value.deptId = undefined
+    formData.value.reason = ''
     simpleUsers.value = []
   }
 })
@@ -210,6 +194,10 @@ const handleUserSelectionChange = (value: number[]) => {
 
   // 新增或更新关联关系
   updateDeviceRelation(device, value)
+  // 自动同步原因(如果已输入)
+  if (formData.value.reason) {
+    handleReasonInput(formData.value.reason)
+  }
 }
 
 // 修改 暂时 保存关联方法
@@ -283,6 +271,15 @@ const getUserList = async () => {
   }
 }
 
+// 新增输入处理方法
+const handleReasonInput = (value: string) => {
+  formData.value.reason = value
+  if (selectedDevice.value && selectedUsers.value.length > 0) {
+    const device = simpleDevices.value.find(d => d.id === selectedDevice.value)
+    device && updateDeviceRelation(device, selectedUsers.value)
+  }
+}
+
 // 更新设备关联关系
 const updateDeviceRelation = (device: IotDeviceVO, userIds: number[]) => {
   // 获取当前选择的人员
@@ -292,7 +289,8 @@ const updateDeviceRelation = (device: IotDeviceVO, userIds: number[]) => {
     deviceIds: [device.id],
     deviceNames: `${device.deviceCode} (${device.deviceName})`,
     userIds: users.map(u => u.id),
-    userNames: users.map(u => u.nickname).join(', ')
+    userNames: users.map(u => u.nickname).join(', '),
+    reason: formData.value.reason
   }
 
   // 查找是否已存在该设备的关联
@@ -332,7 +330,8 @@ const submitRelations = async () => {
     const submitData = tempRelations.value.flatMap(relation => {
       return relation.deviceIds.map(deviceId => ({
         deviceId,
-        userIds: relation.userIds
+        userIds: relation.userIds,
+        reason: relation.reason
       }))
     })
     await IotDevicePersonApi.saveDevicePersonRelation(submitData)
@@ -340,6 +339,7 @@ const submitRelations = async () => {
     console.log('提交数据:', submitData)
     ElMessage.success('提交成功')
     tempRelations.value = []
+    router.back()
   } catch (error) {
     ElMessage.error('提交失败,请重试')
   }

+ 12 - 1
src/views/pms/device/ConfigDeviceStatus.vue

@@ -62,7 +62,7 @@
             class="reason-input"
             type="textarea"
             :rows="3"
-            @blur="saveCurrentRelation"
+            @input="handleReasonInput"
           />
 
           <div class="action-bar">
@@ -122,6 +122,8 @@ import * as DeptApi from "@/api/system/dept";
 import {IotDeviceApi, IotDeviceVO} from "@/api/pms/device";
 import {simpleUserList, UserVO} from "@/api/system/user";
 import {DICT_TYPE, getStrDictOptions} from "@/utils/dict";
+import { useRouter } from 'vue-router'
+const router = useRouter()
 
 defineOptions({ name: 'ConfigDeviceStatus' })
 
@@ -248,6 +250,14 @@ const handleStatusChange = () => {
   }
 }
 
+// 新增输入处理方法
+const handleReasonInput = (value: string) => {
+  formData.value.reason = value
+  if (selectedDevices.value.length > 0 && formData.value.deviceStatus) {
+    saveCurrentRelation()
+  }
+}
+
 // 添加多设备判断方法
 const isMultiDevice = (row: any) => {
   return selectedDevices.value.includes(row.deviceId) && selectedDevices.value.length > 1
@@ -282,6 +292,7 @@ const submitRelations = async () => {
     await IotDeviceApi.saveDeviceStatuses(submitData)
     ElMessage.success('提交成功')
     tempRelations.value = []
+    router.back()
   } catch (error) {
     ElMessage.error('提交失败')
   }

+ 34 - 3
src/views/pms/device/DeviceAllot.vue

@@ -43,7 +43,21 @@
               class="!w-200px"
             />
           </el-form-item>
-
+          <el-form-item label="是否发生过调拨" prop="setFlag" label-width="140px">
+            <el-select
+              v-model="queryParams.setFlag"
+              placeholder="请选择"
+              clearable
+              class="!w-240px"
+            >
+              <el-option
+                v-for="dict in resultOptions"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
           <el-form-item v-show="ifShow" label="设备状态" label-width="85px" prop="deviceStatus">
             <el-select
               v-model="queryParams.deviceStatus"
@@ -208,7 +222,8 @@ const queryParams = reactive({
   supplierId: undefined,
   nameplate: undefined,
   expires: undefined,
-  creator: undefined
+  creator: undefined,
+  setFlag: ''
 })
 const queryFormRef = ref() // 搜索的表单
 const exportLoading = ref(false) // 导出的加载中
@@ -229,7 +244,7 @@ const shou = (tree) =>{
 const getList = async () => {
   loading.value = true
   try {
-    const data = await IotDeviceApi.deviceDynamicsPage(queryParams)
+    const data = await IotDeviceApi.allotRelationDevices(queryParams)
     list.value = data.list
     total.value = data.total
   } finally {
@@ -289,6 +304,22 @@ const handleDelete = async (id: number) => {
   } 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 } })
 }

+ 34 - 2
src/views/pms/device/DevicePerson.vue

@@ -43,7 +43,21 @@
               class="!w-200px"
             />
           </el-form-item>
-
+          <el-form-item label="是否设置了责任人" prop="setFlag" label-width="140px">
+            <el-select
+              v-model="queryParams.setFlag"
+              placeholder="请选择"
+              clearable
+              class="!w-240px"
+            >
+              <el-option
+                v-for="dict in resultOptions"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
           <el-form-item v-show="ifShow" label="设备状态" label-width="85px" prop="deviceStatus">
             <el-select
               v-model="queryParams.deviceStatus"
@@ -166,6 +180,7 @@ import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
 import { dateFormatter } from '@/utils/formatTime'
 import DeptTree from '@/views/system/user/DeptTree.vue'
 import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
+import DevicePersonLogDrawer from "@/views/pms/device/DevicePersonLogDrawer.vue";
 
 /** 设备台账 列表 */
 defineOptions({ name: 'IotDevicePerson' })
@@ -209,7 +224,8 @@ const queryParams = reactive({
   infoRemark: undefined,
   infoUrl: undefined,
   templateJson: undefined,
-  creator: undefined
+  creator: undefined,
+  setFlag: ''
 })
 const queryFormRef = ref() // 搜索的表单
 const exportLoading = ref(false) // 导出的加载中
@@ -280,6 +296,22 @@ const handleDelete = async (id: number) => {
   } 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 } })
 }

+ 34 - 3
src/views/pms/device/DeviceStatus.vue

@@ -43,7 +43,21 @@
               class="!w-200px"
             />
           </el-form-item>
-
+          <el-form-item label="是否调整了状态" prop="setFlag" label-width="140px">
+            <el-select
+              v-model="queryParams.setFlag"
+              placeholder="请选择"
+              clearable
+              class="!w-240px"
+            >
+              <el-option
+                v-for="dict in resultOptions"
+                :key="dict.value"
+                :label="dict.label"
+                :value="dict.value"
+              />
+            </el-select>
+          </el-form-item>
           <el-form-item v-show="ifShow" label="设备状态" label-width="85px" prop="deviceStatus">
             <el-select
               v-model="queryParams.deviceStatus"
@@ -223,7 +237,8 @@ const queryParams = reactive({
   infoRemark: undefined,
   infoUrl: undefined,
   templateJson: undefined,
-  creator: undefined
+  creator: undefined,
+  setFlag: ''
 })
 const queryFormRef = ref() // 搜索的表单
 const exportLoading = ref(false) // 导出的加载中
@@ -241,7 +256,7 @@ const shou = (tree) =>{
 const getList = async () => {
   loading.value = true
   try {
-    const data = await IotDeviceApi.deviceDynamicsPage(queryParams)
+    const data = await IotDeviceApi.statusRelationDevices(queryParams)
     list.value = data.list
     total.value = data.total
   } finally {
@@ -249,6 +264,22 @@ const getList = async () => {
   }
 }
 
+// 是否设置过责任人 下拉列表 模拟字典项
+const resultOptions = computed(() => [
+  {
+    label: '全部',
+    value: 'A' // 空值会触发 clearable 效果
+  },
+  {
+    label: '是',
+    value: 'Y' // 空值会触发 clearable 效果
+  },
+  {
+    label: '否',
+    value: 'N' // 空值会触发 clearable 效果
+  },
+])
+
 const showDrawer = ref()
 
 /** 查看设备状态调整详情 */