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

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, synEquipId?: number | null,
createTime:string, createTime:string,
updateTime:string updateTime:string
abnormalRecordList:[] abnormalRecordList:[],
deviceManagers:[]
deviceManager:string
} }
export interface DeviceRealtimeVO { export interface DeviceRealtimeVO {

View File

@ -16,7 +16,7 @@ export interface DeviceAbnormalRecord {
stationName?: string stationName?: string
abnormalType?: string abnormalType?: number
abnormalTypeName?: string abnormalTypeName?: string
@ -53,7 +53,7 @@ export interface DeviceAbnormalRecord {
// 设备异常记录表 API // 设备异常记录表 API
export const deviceAbnormalRecordApi = { 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 }) return request({ url: '/biz/deviceAbnormalRecord/page', method: 'get', params })
}, },

View File

@ -45,7 +45,7 @@ export interface IssueRecord {
// 下发记录表 API // 下发记录表 API
export const issueRecordApi = { 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 }) 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"> <script setup lang="ts">
import {DeviceAbnormalRecord} from "@/api/deviceAbnormalRecord.ts"; import {DeviceAbnormalRecord} from "@/api/deviceAbnormalRecord.ts";
import {DataTableColumns, NDataTable, NTag} from "naive-ui"; import {DataTableColumns, NButton, NDataTable, NIcon, NSpace, NTag} from "naive-ui";
import {h, onMounted, ref} from "vue"; import {h, onMounted, reactive, ref} from "vue";
import {dictDataApi} from "@/api/org.ts"; 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 deviceNormalRecordOptions = ref<{ label: string; value: any;class:any }[]>([])
const props = defineProps<{ const props = defineProps({
deviceAbnormalRecordList: DeviceAbnormalRecord[] 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: 'abnormalType',align: 'center' }, render(row) {
{ title: '异常级别', key: 'abnormalLevel',align: 'center'}, 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: 'abnormalDesc',align: 'center' },
{ title: '异常时间', key: 'abnormalTime',align: 'center' }, { title: '异常时间', key: 'abnormalTime',align: 'center' },
{ title: '处理状态', key: 'status',align: 'center', { title: '处理状态', key: 'status',align: 'center',
@ -34,23 +91,159 @@
const data = await dictDataApi.listByType('device_abnormal_status') 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 })) deviceNormalRecordOptions.value = data.map(d => ({ label: d.dictLabel, value: (Number(d.dictValue) || d.dictValue),class: d.listClass }))
}catch {} }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(()=>{ onMounted(()=>{
load()
loadDictOptions() loadDictOptions()
}) })
</script> </script>
<template> <template>
<n-card> <div>
<n-data-table <n-button @click="doShowInner" v-if="showSearchInput">
:columns="deviceAbnormalRecordColums" <n-icon size="20" :depth="3">
size="small" <ArrowDown/>
:data="props.deviceAbnormalRecordList" </n-icon>
remote 展开
:scroll-x="600" </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>
<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> </template>
<style scoped> <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: '操作类型', title: '操作类型',
key: 'operationType' key: 'operationTypeName'
}, },
{ {
title: '操作人员', title: '操作人员',
key: 'nickname' key: 'userName'
}, },
{ {
title: '操作时间', title: '操作时间',
key: 'createTime' 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(()=>{ onMounted(()=>{
getDeviceList() getDeviceList()
@ -149,17 +185,17 @@ onMounted(()=>{
type="date" /> type="date" />
</n-form-item> </n-form-item>
</n-gi> </n-gi>
<n-gi> <!-- <n-gi>-->
<n-form-item label="操作类型"> <!-- <n-form-item label="操作类型">-->
<n-select <!-- <n-select-->
v-model:value="searchForm.operationType" <!-- v-model:value="searchForm.operationType"-->
:options="optionTypeList" <!-- :options="optionTypeList"-->
placeholder="请选择设备类型" <!-- placeholder="请选择设备类型"-->
clearable <!-- clearable-->
style="width: 200px" <!-- style="width: 200px"-->
/> <!-- />-->
</n-form-item> <!-- </n-form-item>-->
</n-gi> <!-- </n-gi>-->
<n-gi> <n-gi>
<n-form-item label="操作人员"> <n-form-item label="操作人员">
<n-select <n-select
@ -208,9 +244,25 @@ onMounted(()=>{
<n-data-table <n-data-table
:columns="columns" :columns="columns"
:data="data" :data="data"
:pagination="pagination"
:bordered="false" :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> </n-card>
</div> </div>

View File

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