异常记录 下发记录 操作记录

This commit is contained in:
shaoleiliu-netizen123 2026-07-28 09:00:22 +08:00
parent a8c1a388f6
commit 27eee1eff5
9 changed files with 549 additions and 57 deletions

View File

@ -20,7 +20,9 @@ export interface Device{
synEquipId?: number | null,
createTime:string,
updateTime:string
abnormalRecordList:[]
abnormalRecordList:[],
deviceManagers:[]
deviceManager:string
}
export interface DeviceRealtimeVO {

View File

@ -16,7 +16,7 @@ export interface DeviceAbnormalRecord {
stationName?: string
abnormalType?: string
abnormalType?: number
abnormalTypeName?: string
@ -53,7 +53,7 @@ export interface DeviceAbnormalRecord {
// 设备异常记录表 API
export const deviceAbnormalRecordApi = {
// 分页查询
page(params: { page: number; pageSize: number; id?: number; status?: string }) {
page(params: { page: number; pageSize: number; deviceId?: number; abnormalCode?: string,abnormalType?:number }) {
return request({ url: '/biz/deviceAbnormalRecord/page', method: 'get', params })
},

View File

@ -45,7 +45,7 @@ export interface IssueRecord {
// 下发记录表 API
export const issueRecordApi = {
// 分页查询
page(params: { page: number; pageSize: number; id?: number; status?: number }) {
page(params: { page: number; pageSize: number; issueCode?: string; status?: number;deviceId?:number }) {
return request({ url: '/biz/issueRecord/page', method: 'get', params })
},

View File

@ -136,13 +136,6 @@ export const userApi = {
})
},
//获取设备负责人
getEquipmentManager() {
return request({
url:"/sys/user/getEquipmentManager",
method:"get"
})
}
}

0
src/api/test01.ts Normal file
View File

View File

@ -1,21 +1,78 @@
<script setup lang="ts">
import {DeviceAbnormalRecord} from "@/api/deviceAbnormalRecord.ts";
import {DataTableColumns, NDataTable, NTag} from "naive-ui";
import {h, onMounted, ref} from "vue";
import {DataTableColumns, NButton, NDataTable, NIcon, NSpace, NTag} from "naive-ui";
import {h, onMounted, reactive, ref} from "vue";
import {dictDataApi} from "@/api/org.ts";
import {ArrowDown, ArrowUp, RefreshOutline, SearchOutline} from "@vicons/ionicons5";
import {deviceAbnormalRecordApi} from "@/api/deviceAbnormalRecord.ts";
const deviceNormalRecordOptions = ref<{ label: string; value: any;class:any }[]>([])
const props = defineProps<{
deviceAbnormalRecordList: DeviceAbnormalRecord[]
}>()
const props = defineProps({
deviceId:Number
})
const showSearchInput = ref<Boolean>(false)
const searchForm = ref({
abnormalCode: undefined,
abnormalType: undefined
})
const abnormalTypes = [
{
label: '机械异常',
value: '0'
},
{
label: '电气异常',
value: '1'
},
{
label: '软件异常',
value: '2'
},
{
label: '其他异常',
value: '3'
}
]
const pagination = reactive({
page: 1,
pageSize: 10,
itemCount: 0,
showSizePicker: true,
pageSizes: [10, 20, 50]
})
//
const deviceAbnormalTypeOptions = ref<{ label: string; value: any;class:any }[]>( [])
//
const deviceAbnormalLevelOptions = ref<{ label: string; value: any;class:any }[]>( [])
//
const deviceAbnormalRecordColums:DataTableColumns<DeviceAbnormalRecord> = [
const columns:DataTableColumns<DeviceAbnormalRecord> = [
{ title: '异常编号', key: 'abnormalCode',align: 'center' },
{ title: '异常类型', key: 'abnormalType',align: 'center' },
{ title: '异常级别', key: 'abnormalLevel',align: 'center'},
{ title: '报警异常', key: 'abnormalType',align: 'center',
render(row) {
const val = row.abnormalType
const opt = deviceAbnormalTypeOptions.value.find(o => o.value === val || String(o.value) === String(val))
if (!opt) return val ?? '-'
return h(NTag, { type: opt.class, size: 'small' }, { default: () => opt.label })
}
},
{ title: '异常级别', key: 'abnormalLevel',align: 'center',
render(row) {
const val = row.abnormalLevel
const opt = deviceAbnormalLevelOptions.value.find(o => o.value === val || String(o.value) === String(val))
if (!opt) return val ?? '-'
return h(NTag, { type: opt.class, size: 'small' }, { default: () => opt.label })
}
},
{ title: '异常描述', key: 'abnormalDesc',align: 'center' },
{ title: '异常时间', key: 'abnormalTime',align: 'center' },
{ title: '处理状态', key: 'status',align: 'center',
@ -34,23 +91,159 @@
const data = await dictDataApi.listByType('device_abnormal_status')
deviceNormalRecordOptions.value = data.map(d => ({ label: d.dictLabel, value: (Number(d.dictValue) || d.dictValue),class: d.listClass }))
}catch {}
try {
const data = await dictDataApi.listByType('abnormal_type')
deviceAbnormalTypeOptions.value = data.map(d => ({ label: d.dictLabel, value: (Number(d.dictValue) || d.dictValue),class: d.listClass }))
}catch {}
try {
const data = await dictDataApi.listByType('abnormal_level')
deviceAbnormalLevelOptions.value = data.map(d => ({ label: d.dictLabel, value: (Number(d.dictValue) || d.dictValue),class: d.listClass }))
}catch {}
}
const data = ref([])
const load = async() => {
try {
const res = await deviceAbnormalRecordApi.page({
page: pagination.page,
pageSize: pagination.pageSize,
deviceId: props.deviceId,
abnormalCode: searchForm.value.abnormalCode,
abnormalType: searchForm.value.abnormalType,
})
data.value = res.list
pagination.itemCount = res.total
} catch (e) {}
}
const doShowInner = () => {
if (showSearchInput.value) {
showSearchInput.value = false
}else {
showSearchInput.value = true
}
}
const handleSearch = () => {
load()
}
const handleReset = () => {
searchForm.value.abnormalType = null
searchForm.value.abnormalCode = null
pagination.page = 1
pagination.pageSize = 10
load()
}
//
function handlePageChange(page: number) {
pagination.page = page
load()
}
function handlePageSizeChange(pageSize: number) {
pagination.pageSize = pageSize
pagination.page = 1
load()
}
onMounted(()=>{
load()
loadDictOptions()
})
</script>
<template>
<n-card>
<n-data-table
:columns="deviceAbnormalRecordColums"
size="small"
:data="props.deviceAbnormalRecordList"
remote
:scroll-x="600"
<div>
<n-button @click="doShowInner" v-if="showSearchInput">
<n-icon size="20" :depth="3">
<ArrowDown/>
</n-icon>
展开
</n-button>
<n-card v-if="!showSearchInput">
<n-form inline :model="searchForm" label-placement="left">
<n-grid :x-gap="8" :cols="4">
<n-gi>
<n-form-item label="异常编号">
<n-input v-model:value="searchForm.abnormalCode" placeholder="请输入异常编号" clearable style="width: 200px"/>
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="操作人员">
<n-select
v-model:value="searchForm.abnormalType"
:options="abnormalTypes"
placeholder="请选择异常类型"
clearable
style="width: 200px"
/>
</n-form-item>
</n-gi>
<n-gi>
<n-form-item>
<n-space>
<n-button type="primary" @click="handleSearch">
<template #icon>
<n-icon>
<SearchOutline/>
</n-icon>
</template>
搜索
</n-button>
<n-button @click="handleReset">
<template #icon>
<n-icon>
<RefreshOutline/>
</n-icon>
</template>
重置
</n-button>
</n-space>
</n-form-item>
</n-gi>
</n-grid>
</n-form>
<n-button @click="doShowInner" v-if="!showSearchInput" style="float: right;margin: 10px">
<n-icon size="20" :depth="3">
<ArrowUp/>
</n-icon>
闭合
</n-button>
</n-card>
<n-card style="margin: 20px 0">
<n-data-table
:columns="columns"
:data="data"
:bordered="false"
/>
<div class="pagination-container" style="display: flex; justify-content: flex-end; margin-top: 12px">
<n-pagination
v-model:page="pagination.page"
v-model:page-size="pagination.pageSize"
:item-count="pagination.itemCount"
:page-sizes="[10, 20, 50, 100]"
show-size-picker
show-quick-jumper
@update:page="handlePageChange"
@update:page-size="handlePageSizeChange"
>
<template #prefix>
{{ pagination.itemCount }}
</template>
</n-pagination>
</div>
</n-card>
</div>
</template>
<style scoped>

View File

@ -0,0 +1,219 @@
<script setup lang="ts">
import {ArrowDown, ArrowUp, RefreshOutline, SearchOutline} from "@vicons/ionicons5";
import {NButton, NIcon, NSpace} from "naive-ui";
import {onMounted, reactive, ref} from "vue";
import { issueRecordApi,IssueRecord } from '@/api/issuerecord.ts'
const props = defineProps({
deviceId:Number
})
const showSearchInput = ref<Boolean>(false)
const searchForm = ref({
issueCode: undefined,
status: undefined,
})
const pagination = reactive({
page: 1,
pageSize: 2,
itemCount: 0,
showSizePicker: true,
pageSizes: [10, 20, 50]
})
const doShowInner = () => {
if (showSearchInput.value) {
showSearchInput.value = false
}else {
showSearchInput.value = true
}
}
//
const statusList = [
{
label: '下发失败',
value: 0
},
{
label: '下发成功',
value: 1
}
]
//
const data = ref([])
const load = async()=>{
const res = await issueRecordApi.page({
pageSize: pagination.pageSize,
page: pagination.page,
deviceId: props.deviceId,
issueCode: searchForm.value.issueCode,
status: searchForm.value.status
});
data.value = res.list
pagination.itemCount = res.total
}
const columns = [
{
title: '下发编号',
key: 'issueCode'
},
{
title: '下发类型',
key: 'issueType',
render(row) {
var opt = row.issueType
if(opt == 0) return '图纸'
if(opt == 1) return '文件'
if(opt == 2) return '代码'
return '-'
}
},
{
title: '下发状态',
key: 'status',
render(row) {
var opt = row.status
if(opt == 0) return '下发失败'
if(opt == 1) return '下发成功'
}
},
{
title: '下发时间',
key: 'issueTime'
},
{
title: '备注',
key: 'remark'
}
]
const handleSearch = () => {
load()
}
const handleReset = () => {
searchForm.value.issueCode = null
searchForm.value.status = null
pagination.page = 1
pagination.pageSize = 10
handleSearch()
}
//
function handlePageChange(page: number) {
pagination.page = page
load()
}
function handlePageSizeChange(pageSize: number) {
pagination.pageSize = pageSize
pagination.page = 1
load()
}
onMounted(()=>{
load()
})
</script>
<template>
<div>
<n-button @click="doShowInner" v-if="showSearchInput">
<n-icon size="20" :depth="3">
<ArrowDown/>
</n-icon>
展开
</n-button>
<n-card v-if="!showSearchInput">
<n-form inline :model="searchForm" label-placement="left">
<n-grid :x-gap="8" :cols="4">
<n-gi>
<n-form-item label="下发编号">
<n-input v-model:value="searchForm.issueCode" placeholder="请输入设备下发编号" clearable style="width: 200px"/>
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="下发状态">
<n-select
v-model:value="searchForm.status"
:options="statusList"
placeholder="请选择设备类型"
clearable
style="width: 200px"
/>
</n-form-item>
</n-gi>
<n-gi>
<n-form-item>
<n-space>
<n-button type="primary" @click="handleSearch">
<template #icon>
<n-icon>
<SearchOutline/>
</n-icon>
</template>
搜索
</n-button>
<n-button @click="handleReset">
<template #icon>
<n-icon>
<RefreshOutline/>
</n-icon>
</template>
重置
</n-button>
</n-space>
</n-form-item>
</n-gi>
</n-grid>
</n-form>
<n-button @click="doShowInner" v-if="!showSearchInput" style="float: right;margin: 10px">
<n-icon size="20" :depth="3">
<ArrowUp/>
</n-icon>
闭合
</n-button>
</n-card>
<n-card style="margin: 20px 0">
<n-data-table
:columns="columns"
:data="data"
:bordered="false"
/>
<div class="pagination-container" style="display: flex; justify-content: flex-end; margin-top: 12px">
<n-pagination
v-model:page="pagination.page"
v-model:page-size="pagination.pageSize"
:item-count="pagination.itemCount"
:page-sizes="[10, 20, 50, 100]"
show-size-picker
show-quick-jumper
@update:page="handlePageChange"
@update:page-size="handlePageSizeChange"
>
<template #prefix>
{{ pagination.itemCount }}
</template>
</n-pagination>
</div>
</n-card>
</div>
</template>
<style scoped>
</style>

View File

@ -108,18 +108,54 @@ const columns = [
},
{
title: '操作类型',
key: 'operationType'
key: 'operationTypeName'
},
{
title: '操作人员',
key: 'nickname'
key: 'userName'
},
{
title: '操作时间',
key: 'createTime'
},
{
title: '数据来源',
key: 'source',
render(row) {
var opt = row.source
if(opt == 1) return '终端'
if(opt == 2) return '后台'
return '-'
}
}
]
const handleSearch = () => {
load()
}
const handleReset = () => {
searchForm.value.createTime = null
searchForm.value.operationType = null
searchForm.value.userId = null
pagination.page = 1
pagination.pageSize = 10
load()
}
//
function handlePageChange(page: number) {
pagination.page = page
load()
}
function handlePageSizeChange(pageSize: number) {
pagination.pageSize = pageSize
pagination.page = 1
load()
}
onMounted(()=>{
getDeviceList()
@ -149,17 +185,17 @@ onMounted(()=>{
type="date" />
</n-form-item>
</n-gi>
<n-gi>
<n-form-item label="操作类型">
<n-select
v-model:value="searchForm.operationType"
:options="optionTypeList"
placeholder="请选择设备类型"
clearable
style="width: 200px"
/>
</n-form-item>
</n-gi>
<!-- <n-gi>-->
<!-- <n-form-item label="操作类型">-->
<!-- <n-select-->
<!-- v-model:value="searchForm.operationType"-->
<!-- :options="optionTypeList"-->
<!-- placeholder="请选择设备类型"-->
<!-- clearable-->
<!-- style="width: 200px"-->
<!-- />-->
<!-- </n-form-item>-->
<!-- </n-gi>-->
<n-gi>
<n-form-item label="操作人员">
<n-select
@ -208,9 +244,25 @@ onMounted(()=>{
<n-data-table
:columns="columns"
:data="data"
:pagination="pagination"
:bordered="false"
/>
<div class="pagination-container" style="display: flex; justify-content: flex-end; margin-top: 12px">
<n-pagination
v-model:page="pagination.page"
v-model:page-size="pagination.pageSize"
:item-count="pagination.itemCount"
:page-sizes="[10, 20, 50, 100]"
show-size-picker
show-quick-jumper
@update:page="handlePageChange"
@update:page-size="handlePageSizeChange"
>
<template #prefix>
{{ pagination.itemCount }}
</template>
</n-pagination>
</div>
</n-card>
</div>

View File

@ -131,10 +131,10 @@
</n-form-item>
<n-form-item label="设备负责人" path="deviceManager">
<n-select
v-model:value="formData.deviceManagerList"
v-model:value="formData.deviceManagers"
:options="deviceManagerList"
multiple
placeholder="请选择设备类型"
placeholder="请选择设备负责人"
clearable
style="width: 200px"
/>
@ -202,10 +202,10 @@
</n-modal>
<!--异常记录抽屉-->
<n-drawer v-model:show="deviceAbnormalRecordDrawerVisible" :title="title" width="800">
<n-drawer v-model:show="deviceAbnormalRecordDrawerVisible" :title="title" width="1800">
<n-drawer-content :title="title">
<DeviceAbnormalRecordPage
:deviceAbnormalRecordList="deviceAbnormalRecordList"
:deviceId="deviceId"
/>
<template #footer>
<n-button @click="doShowInner">
@ -229,6 +229,21 @@
</template>
</n-drawer-content>
</n-drawer>
<!--下发记录抽屉-->
<n-drawer v-model:show="deviceDispatchLogDrawerVisible" width="1800">
<n-drawer-content :title="title">
<DeviceDispatchLogPage
:deviceId = deviceId
/>
<template #footer>
<n-button @click="doShowInner">
取消
</n-button>
</template>
</n-drawer-content>
</n-drawer>
</div>
</template>
@ -256,7 +271,8 @@ import {SysUser, userApi} from '@/api/system'
import {DeviceAbnormalRecord, deviceAbnormalRecordApi} from "@/api/deviceAbnormalRecord.ts";
import DeviceAbnormalRecordPage from '@/views/biz/device/DeviceAbnomarlRecord.vue'
import DeviceOperationLogPage from "@/views/biz/device/DeviceOperationLog.vue";
import { issueRecordApi } from '@/api/issuerecord'
import DeviceDispatchLogPage from "@/views/biz/device/DeviceDispatchLog.vue";
const message = useMessage()
const dialog = useDialog()
const router = useRouter()
@ -276,6 +292,7 @@ const title = ref('')
//
const deviceIssueRecordList = ref<[]>([])
const deviceDispatchLogDrawerVisible = ref<Boolean>(false)
//
const deviceOperationLogDrawerVisible = ref<Boolean>(false)
@ -318,7 +335,9 @@ const defaultFormData: Device = {
status: 0,
deviceFlag: 'mes_equipment',
synEquipId: null as number | null,
deviceManagerList: null as any | null
deviceManagerList: null as any | null,
deviceManagers: null as [string] | null,
deviceManager: null as String | null
}
const formData = reactive<Device>({...defaultFormData})
@ -481,16 +500,23 @@ function goRealtimeBoard() {
//
function handleEdit(row: Device) {
Object.assign(formData, defaultFormData)
modalTitle.value = '编辑设备表'
Object.assign(formData, row)
console.log(formData);
const userIdList = []
if (row.deviceManager) {
let manager = row.deviceManager.split(',');
manager.forEach(item => {
userIdList.push(Number(item))
})
}
formData.deviceManagers = userIdList
modalVisible.value = true
}
//
async function handleSubmit() {
await formRef.value?.validate()
try {
const submitData = {...formData} as Device
@ -647,23 +673,29 @@ async function loadSection() {
//
async function handleUser() {
const res = await userApi.getEquipmentManager()
deviceManagerList.value = res
const res = await userApi.getPathList()
deviceManagerList.value = res.map((n:any)=>{
return {
label:n.username,
value:n.id
}
})
}
//
async function handleDeviceErrorLog(row: Device) {
deviceId.value = row.id
deviceAbnormalRecordDrawerVisible.value = true
title.value = row.deviceName+"异常记录"
deviceErrorLogList.value = row.abnormalRecordList
}
async function handleDeviceDispatchLog(row: Device) {
const deviceId = row.id
deviceIssueRecordList.value = await issueRecordApi.getDeviceDispatchLogList(deviceId)
deviceId.value = row.id
deviceDispatchLogDrawerVisible.value = true
title.value = row.deviceName+"设备下发记录"
}
async function deviceOperationLog(row: Device) {
@ -676,6 +708,7 @@ async function deviceOperationLog(row: Device) {
function doShowInner() {
deviceAbnormalRecordDrawerVisible.value = false
deviceOperationLogDrawerVisible.value = false
deviceDispatchLogDrawerVisible.value = false
}
onMounted(() => {