31 changed files with 2362 additions and 249 deletions
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
import { eamServer } from '../../index' |
||||
|
||||
export function getFirmwareList(params: PageParam) { |
||||
return eamServer({ |
||||
url: '/firmware/page', |
||||
method: 'get', |
||||
params, |
||||
}) |
||||
} |
||||
|
||||
export function deleteFirmware(id: string) { |
||||
return eamServer({ |
||||
url: '/firmware/delete', |
||||
method: 'post', |
||||
data: { id }, |
||||
}) |
||||
} |
||||
|
||||
export function createFirmware(data: any) { |
||||
return eamServer({ |
||||
url: '/firmware/upload', |
||||
method: 'post', |
||||
data, |
||||
headers: { 'Content-Type': 'multipart/form-data' }, |
||||
}) |
||||
} |
||||
|
||||
export function getSimpleFirmwareList(params: { type: number }) { |
||||
return eamServer({ |
||||
url: '/firmware/simple-list', |
||||
method: 'get', |
||||
params, |
||||
}) |
||||
} |
@ -0,0 +1,28 @@
@@ -0,0 +1,28 @@
|
||||
import { eamServer } from '../../index' |
||||
|
||||
interface IMaintenanceOV { |
||||
id?: number |
||||
content: string |
||||
maintainer?: string |
||||
maintenanceTime: string |
||||
status: number |
||||
} |
||||
export const createdMaintenance = (data: IMaintenanceOV) => |
||||
eamServer({ |
||||
url: '/maintenance/create', |
||||
method: 'post', |
||||
data, |
||||
}) |
||||
|
||||
export const updateMaintenance = (data: IMaintenanceOV) => |
||||
eamServer({ |
||||
url: '/maintenance/update', |
||||
method: 'post', |
||||
data, |
||||
}) |
||||
export const getMaintenanceList = (params: any) => |
||||
eamServer({ |
||||
url: '/maintenance/get-by-device-id', |
||||
method: 'get', |
||||
params, |
||||
}) |
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
import { eamServer } from '../../index' |
||||
|
||||
export interface IStorageOutParam { |
||||
id?: string |
||||
customerId: string |
||||
name: string |
||||
description: string |
||||
deviceId: number |
||||
price: string |
||||
} |
||||
|
||||
export const storageOutDevice = (params: IStorageOutParam) => |
||||
eamServer({ |
||||
url: `/device/out-storage`, |
||||
method: 'post', |
||||
data: params, |
||||
}) |
||||
|
||||
export const getStorageOutByDeviceId = (deviceId: number) => |
||||
eamServer({ |
||||
url: `/out-storage/get-by-device-id`, |
||||
method: 'get', |
||||
params: { deviceId }, |
||||
}) |
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
import { eamServer } from '../../index' |
||||
|
||||
export function getTaskList(params: PageParam) { |
||||
return eamServer({ |
||||
url: '/device/task/page', |
||||
method: 'get', |
||||
params, |
||||
}) |
||||
} |
||||
|
||||
export function getTaskDetails(id: string) { |
||||
return eamServer({ |
||||
url: '/device/task/details', |
||||
method: 'get', |
||||
params: { id }, |
||||
}) |
||||
} |
||||
|
||||
export function createTask(data: any) { |
||||
return eamServer({ |
||||
url: '/device/firmware/remote-update', |
||||
method: 'post', |
||||
data, |
||||
}) |
||||
} |
@ -0,0 +1,48 @@
@@ -0,0 +1,48 @@
|
||||
export enum DeviceStatus { |
||||
已注册, |
||||
测试中, |
||||
已入库, |
||||
已出库, |
||||
} |
||||
export const deviceTableCol = [ |
||||
{ label: '设备编号', prop: 'serialNo', minWidth: '16%' }, |
||||
{ label: '设备名称', prop: 'name', minWidth: '10%' }, |
||||
{ label: '设备类型', prop: 'categoryId', minWidth: '10%' }, |
||||
{ label: '设备状态', prop: 'status', minWidth: '10%' }, |
||||
{ label: '设备sn', prop: 'sn', minWidth: '10%' }, |
||||
{ label: '创建时间', prop: 'createTime', minWidth: '10%' }, |
||||
] |
||||
|
||||
export type OptAction = 'create' | 'update' | 'view' |
||||
export const collapses = [ |
||||
{ title: '基础信息', name: 'info' }, |
||||
{ title: '测试信息', name: 'test' }, |
||||
{ title: '出库信息', name: 'delivery' }, |
||||
{ title: '维修信息', name: 'maintain' }, |
||||
] |
||||
|
||||
export const openNotMsg = (msg: string) => { |
||||
ElNotification({ |
||||
title: 'Warning', |
||||
message: msg, |
||||
type: 'warning', |
||||
}) |
||||
} |
||||
|
||||
export const maintainStatus = [ |
||||
{ label: '待维修', value: 0 }, |
||||
{ label: '维修中', value: 1 }, |
||||
{ label: '已维修', value: 2 }, |
||||
] |
||||
export const testSheetStatus = [ |
||||
{ label: '未测试', value: 0 }, |
||||
{ label: '通过', value: 1 }, |
||||
{ label: '未通过', value: 2 }, |
||||
] |
||||
|
||||
export const testTableCol = [ |
||||
{ label: '测试内容', prop: 'content', minWidth: '10%' }, |
||||
{ label: '预计结果', prop: 'expectResult', minWidth: '10%' }, |
||||
{ label: '测试结果', prop: 'actualResult', minWidth: '20%' }, |
||||
{ label: '备注', prop: 'description', minWidth: '16%' }, |
||||
] |
@ -0,0 +1,215 @@
@@ -0,0 +1,215 @@
|
||||
<template> |
||||
<EdfsDialog |
||||
@on-close="onClone" |
||||
@on-save="onSave" |
||||
title="新建固件" |
||||
:is-show="isShow" |
||||
width="44%" |
||||
class="create-firmware-dlg" |
||||
> |
||||
<div class="dlg-body"> |
||||
<el-row> |
||||
<FormItemInput label="固件名称" v-model="formData.name" require /> |
||||
</el-row> |
||||
<el-row> |
||||
<FormItemInput label="固件版本" v-model="formData.version" require /> |
||||
</el-row> |
||||
<el-row> |
||||
<FormItemSelect |
||||
label="固件类型" |
||||
v-model="formData.type" |
||||
require |
||||
:options="getIntDictOptions('device_entity_type')" |
||||
keyTag="value" |
||||
valueTag="value" |
||||
labelTag="label" |
||||
/> |
||||
</el-row> |
||||
<!-- 固件文件 --> |
||||
<el-row class="upload"> |
||||
<span class="label" |
||||
><span data-v-fbd7b238="" class="require">*</span>固件文件:</span |
||||
> |
||||
<el-upload |
||||
v-model:fileList="fileList" |
||||
drag |
||||
action="" |
||||
:limit="1" |
||||
:on-exceed="handleExceed" |
||||
:auto-upload="false" |
||||
ref="upload" |
||||
class="upload-container" |
||||
> |
||||
<el-icon class="upload-icon"> |
||||
<IEpUploadFilled /> |
||||
</el-icon> |
||||
<div class="text">拖拽文件或者 <em>点击上传</em></div> |
||||
<template #tip v-if="!fileList.length"> |
||||
<div class="el-upload__tip">上传限制一个文件,新文件会覆盖旧文件</div> |
||||
</template> |
||||
</el-upload> |
||||
</el-row> |
||||
<el-row> |
||||
<FormItemInput label="固件描述" type="textarea" v-model="formData.description" /> |
||||
</el-row> |
||||
</div> |
||||
</EdfsDialog> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import { createFirmware } from '@/api/module/eam/device/firmware' |
||||
import { getTenant } from '@/api/module/system/tenant' |
||||
import EdfsDialog from '@/components/dashboard/Edfs-dialog.vue' |
||||
import FormItemInput from '@/components/dashboard/FormItemInput.vue' |
||||
import { isResError, useMessage } from '@/hooks/useMessage' |
||||
import FormItemSelect from '@/components/dashboard/FormItemSelect.vue' |
||||
import { getTenantId } from '@/utils/auth' |
||||
import { getIntDictOptions } from '@/utils/dict' |
||||
|
||||
const message = useMessage() |
||||
|
||||
import type { |
||||
UploadInstance, |
||||
UploadProps, |
||||
UploadRawFile, |
||||
UploadUserFile, |
||||
} from 'element-plus' |
||||
import { cloneDeep } from 'lodash' |
||||
|
||||
interface Props { |
||||
isShow: boolean |
||||
// action: operantAction |
||||
} |
||||
// const title = computed(() => |
||||
// props.action === 'create' ? '' : '' |
||||
// ) |
||||
const emits = defineEmits(['on-save', 'on-close']) |
||||
const props = withDefaults(defineProps<Props>(), { |
||||
isShow: false, |
||||
}) |
||||
|
||||
const fileList = ref<UploadUserFile[]>([]) |
||||
const data = { |
||||
name: '', |
||||
version: '', |
||||
description: '', |
||||
type: '', |
||||
} |
||||
const formData = ref(cloneDeep(data)) |
||||
const upload = ref<UploadInstance>() |
||||
const handleExceed: UploadProps['onExceed'] = files => { |
||||
upload.value!.clearFiles() |
||||
const file = files[0] as UploadRawFile |
||||
|
||||
upload.value!.handleStart(file) |
||||
} |
||||
|
||||
function validate() { |
||||
if (!formData.value.name) { |
||||
message.error('请输入固件名称') |
||||
return true |
||||
} |
||||
|
||||
if (!formData.value.version) { |
||||
message.error('请输入固件版本') |
||||
return true |
||||
} |
||||
|
||||
if (!formData.value.type) { |
||||
message.error('请选择固件类型') |
||||
return true |
||||
} |
||||
|
||||
if (!fileList.value.length) { |
||||
message.error('请上传固件文件') |
||||
return true |
||||
} |
||||
return false |
||||
} |
||||
|
||||
async function onSave() { |
||||
if (validate()) return |
||||
const data = new FormData() |
||||
data.append('path', getTenantId()) |
||||
data.append('file', fileList.value[0].raw as File) |
||||
data.append('name', formData.value.name) |
||||
data.append('version', formData.value.version) |
||||
data.append('type', formData.value.type) |
||||
data.append('description', formData.value.description) |
||||
const res = await createFirmware(data) |
||||
if (isResError(res)) return |
||||
emits('on-save') |
||||
clearData() |
||||
} |
||||
|
||||
function clearData() { |
||||
formData.value = cloneDeep(data) |
||||
fileList.value = [] |
||||
} |
||||
function onClone() { |
||||
clearData() |
||||
emits('on-close') |
||||
} |
||||
</script> |
||||
|
||||
<style scoped lang="scss"> |
||||
.create-firmware-dlg { |
||||
.dlg-body { |
||||
height: 470px; |
||||
} |
||||
.el-row { |
||||
height: 32px; |
||||
margin-bottom: 20px; |
||||
:deep(.label) { |
||||
margin-right: 10px; |
||||
} |
||||
span { |
||||
width: 110px; |
||||
height: 32px; |
||||
line-height: 32px; |
||||
text-align: right; |
||||
} |
||||
:deep(.el-radio-group) { |
||||
height: 100%; |
||||
} |
||||
:deep(.el-radio) { |
||||
height: 100%; |
||||
} |
||||
} |
||||
.require { |
||||
color: red; |
||||
margin-right: 4px; |
||||
} |
||||
.upload { |
||||
height: 156px; |
||||
:deep(.upload-container) { |
||||
width: calc(100% - 210px); |
||||
height: calc(100% - 20px); |
||||
} |
||||
:deep(.el-upload) { |
||||
height: 100%; |
||||
width: 100%; |
||||
} |
||||
:deep(.el-upload-dragger) { |
||||
height: 100%; |
||||
width: 100%; |
||||
padding-top: 30px; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.upload-icon { |
||||
font-size: 54px; |
||||
color: #c0c4cc; |
||||
} |
||||
.text { |
||||
color: #6c6c6c; |
||||
font-size: 14px; |
||||
text-align: center; |
||||
} |
||||
em { |
||||
color: #409eff; |
||||
cursor: pointer; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,183 @@
@@ -0,0 +1,183 @@
|
||||
<template> |
||||
<div class="firmware-management-wrap"> |
||||
<EdfsWrap class="firmware-table" title="固件列表"> |
||||
<template #title-right> |
||||
<div class="firmware-table-title"> |
||||
<EdfsButton |
||||
type="success" |
||||
inner-text="新增固件" |
||||
:icon="createIcon" |
||||
@click="addFirmware" |
||||
/> |
||||
</div> |
||||
</template> |
||||
<edfs-table |
||||
:data="dataList" |
||||
:highlight-current-row="true" |
||||
ref="tableRef" |
||||
row-class-name="row" |
||||
:page-size="pageSize" |
||||
:page-total="pageTotal" |
||||
class="table" |
||||
:current-page="pageIndex" |
||||
@pageCurrentChange="handleJump" |
||||
> |
||||
<template v-for="(col, idx) in tableColumns" :key="idx"> |
||||
<!-- <el-table-column |
||||
v-if="col.prop == 'status'" |
||||
:label="col.label" |
||||
:prop="col.prop" |
||||
:min-width="col.minWidth" |
||||
> |
||||
<template #default="scope"> |
||||
<div style="display: flex; align-items: center; column-gap: 4px"> |
||||
<img |
||||
:src="deviceStatusImgMap[scope.row.status]" |
||||
alt="" |
||||
width="16" |
||||
height="16" |
||||
/> |
||||
{{ getDictObj('device_entity_status', scope.row.status)?.label }} |
||||
</div> |
||||
</template> |
||||
</el-table-column> --> |
||||
|
||||
<el-table-column |
||||
v-if="col.prop == 'createTime'" |
||||
:label="col.label" |
||||
:prop="col.prop" |
||||
:min-width="col.width" |
||||
> |
||||
<template #default="scope"> |
||||
{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column |
||||
v-else |
||||
:label="col.label" |
||||
:prop="col.prop" |
||||
:min-width="col.width" |
||||
/> |
||||
</template> |
||||
|
||||
<el-table-column label="操作" min-width="14%"> |
||||
<template #default="scope"> |
||||
<!-- <EdfsButton |
||||
type="success" |
||||
link |
||||
inner-text="下载固件" |
||||
@click="onDownload(scope.row)" |
||||
/> --> |
||||
<EdfsButton |
||||
type="danger" |
||||
link |
||||
inner-text="删除" |
||||
@click="onDelete(scope.row.id)" |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
</edfs-table> |
||||
</EdfsWrap> |
||||
<createFirmwareDlg :is-show="isShowDlg" @on-close="onClose" @on-save="onSave" /> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import { tableColumns } from './utils' |
||||
import EdfsButton from '@/components/dashboard/Edfs-button/index.vue' |
||||
import EdfsTable from '@/components/dashboard/Edfs-table/index.vue' |
||||
import EdfsWrap from '@/components/dashboard/Edfs-wrap.vue' |
||||
import { useIcon } from '@/utils/useIcon' |
||||
import createFirmwareDlg from './components/create-firmware-dlg.vue' |
||||
import { deleteFirmware, getFirmwareList } from '@/api/module/eam/device/firmware' |
||||
import { isResError, useMessage } from '@/hooks/useMessage.js' |
||||
import dayjs from 'dayjs' |
||||
import download from '@/utils/download' |
||||
|
||||
const message = useMessage() |
||||
|
||||
const createIcon = useIcon({ icon: 'gravity-ui:plus' }) |
||||
const tableRef = ref<any>(null) |
||||
const dataList = ref([]) |
||||
const pageIndex = ref(1) |
||||
const pageSize = ref() |
||||
const pageTotal = ref(0) |
||||
const pageJump = ref(1) |
||||
|
||||
async function loadData() { |
||||
if (!pageSize.value) { |
||||
pageSize.value = tableRef.value.getSize() |
||||
} |
||||
const res = await getFirmwareList({ |
||||
pageNo: pageIndex.value, |
||||
pageSize: pageSize.value, |
||||
}) |
||||
if (isResError(res)) return |
||||
const { list, total } = res.data |
||||
dataList.value = list |
||||
pageTotal.value = total |
||||
} |
||||
watch(pageIndex, () => { |
||||
pageJump.value = pageIndex.value |
||||
loadData() |
||||
}) |
||||
|
||||
function handleJump(page: number) { |
||||
pageIndex.value = page |
||||
} |
||||
|
||||
async function onDelete(id: string) { |
||||
try { |
||||
await message.delConfirm() |
||||
const res = await deleteFirmware(id) |
||||
if (isResError(res)) return |
||||
message.success('删除成功') |
||||
loadData() |
||||
} catch (error) {} |
||||
} |
||||
|
||||
function onDownload(row: any) { |
||||
// download.word(row.downloadPath, row.name) |
||||
// const downA = document.createElement('a') |
||||
// downA.href = row.downloadPath |
||||
// downA.download = row.name |
||||
// downA.click() |
||||
// downA.remove() |
||||
} |
||||
|
||||
const isShowDlg = ref(false) |
||||
function addFirmware() { |
||||
isShowDlg.value = true |
||||
} |
||||
|
||||
function onClose() { |
||||
isShowDlg.value = false |
||||
} |
||||
|
||||
function onSave() { |
||||
isShowDlg.value = false |
||||
loadData() |
||||
} |
||||
|
||||
onMounted(() => { |
||||
loadData() |
||||
}) |
||||
</script> |
||||
|
||||
<style scoped lang="scss"> |
||||
.firmware-management-wrap { |
||||
width: 100%; |
||||
height: 100%; |
||||
.firmware-table { |
||||
height: 100%; |
||||
box-sizing: border-box; |
||||
|
||||
background: #fff; |
||||
padding-bottom: 0; |
||||
.table { |
||||
height: 100%; |
||||
width: 100%; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
export const tableColumns = [ |
||||
{ |
||||
label: '固件名称', |
||||
prop: 'name', |
||||
width: '10%', |
||||
}, |
||||
{ |
||||
label: '固件版本', |
||||
prop: 'version', |
||||
width: '10%', |
||||
}, |
||||
{ |
||||
label: '下载路径', |
||||
prop: 'downloadPath', |
||||
width: '30%', |
||||
}, |
||||
{ |
||||
label: '创建时间', |
||||
prop: 'createTime', |
||||
width: '20%', |
||||
}, |
||||
{ |
||||
label: '固件状态', |
||||
prop: 'status', |
||||
width: '10%', |
||||
}, |
||||
{ |
||||
label: '描述', |
||||
prop: 'description', |
||||
width: '20%', |
||||
}, |
||||
] |
@ -0,0 +1,308 @@
@@ -0,0 +1,308 @@
|
||||
<template> |
||||
<EdfsDialog |
||||
@on-close="onClone" |
||||
@on-save="onSave" |
||||
title="新建升级任务" |
||||
:is-show="isShow" |
||||
width="44%" |
||||
class="create-task-dlg" |
||||
> |
||||
<div class="dlg-body"> |
||||
<el-row> |
||||
<FormItemInput label="任务名称" v-model="formData.name" require /> |
||||
</el-row> |
||||
<el-row> |
||||
<span class="label">固件选择:</span> |
||||
<el-cascader |
||||
:props="cascaderFirmware" |
||||
v-model="firmwareSelect" |
||||
ref="firmwareCascaderRef" |
||||
:show-all-levels="false" |
||||
placeholder="请选择" |
||||
/> |
||||
</el-row> |
||||
<el-row v-if="isShowDeviceSelect"> |
||||
<!-- <span class="label">设备选择</span> |
||||
<el-cascader |
||||
style="flex: 1" |
||||
v-model="deviceSelect" |
||||
:props="cascaderDevice" |
||||
@change="devChange" |
||||
ref="deviceCascaderRef" |
||||
:show-all-levels="false" |
||||
popper-class="task-device-select-cascader" |
||||
placeholder="请选择" |
||||
collapse-tags |
||||
:max-collapse-tags="4" |
||||
collapse-tags-tooltip |
||||
@expand-change="changeSourceType" |
||||
/> --> |
||||
</el-row> |
||||
<el-row> |
||||
<span class="label">是否立即执行</span> |
||||
<el-switch |
||||
v-model="formData.executeNow" |
||||
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" |
||||
/> |
||||
</el-row> |
||||
<el-row v-if="!formData.executeNow"> |
||||
<span class="label">任务执行时间</span> |
||||
<el-date-picker |
||||
v-model="formData.executeTime" |
||||
type="datetime" |
||||
value-format="YYYY-MM-DD HH:mm" |
||||
format="YYYY-MM-DD HH:mm" |
||||
placeholder="Pick a day" |
||||
:disabled-date="disabledExecuteDate" |
||||
/> |
||||
</el-row> |
||||
<el-row> |
||||
<EdfsNumberInput labelName="监控超时" v-model="formData.monitorTimeout" require /> |
||||
</el-row> |
||||
<el-row> |
||||
<EdfsNumberInput labelName="重试次数" v-model="formData.retryCount" require /> |
||||
</el-row> |
||||
<el-row> |
||||
<EdfsNumberInput labelName="重试间隔" v-model="formData.retryInterval" require /> |
||||
</el-row> |
||||
</div> |
||||
</EdfsDialog> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import EdfsDialog from '@/components/dashboard/Edfs-dialog.vue' |
||||
import FormItemInput from '@/components/dashboard/FormItemInput.vue' |
||||
import { isResError, useMessage } from '@/hooks/useMessage' |
||||
import EdfsNumberInput from '@/components/dashboard/Edfs-number-item-input.vue' |
||||
import FormItemSelect from '@/components/dashboard/FormItemSelect.vue' |
||||
import type { CascaderProps, CascaderValue, ElCascader } from 'element-plus' |
||||
// import { getSimpleStationList } from '@/api/module/app/station' |
||||
// import { getSimpleDeviceList } from '@/api/module/app/device' |
||||
import { getIntDictOptions } from '@/utils/dict' |
||||
import { getSimpleFirmwareList } from '@/api/module/eam/device/firmware' |
||||
import { isEmpty } from '@/utils/is' |
||||
import { clone, cloneDeep } from 'lodash' |
||||
import { createTask } from '@/api/module/eam/device/task' |
||||
|
||||
const message = useMessage() |
||||
interface Props { |
||||
isShow: boolean |
||||
} |
||||
|
||||
const emits = defineEmits(['on-save', 'on-close']) |
||||
const props = withDefaults(defineProps<Props>(), { |
||||
isShow: false, |
||||
}) |
||||
|
||||
const firmwareSelect = ref<CascaderValue>([]) |
||||
const firmwareCascaderRef = ref<InstanceType<typeof ElCascader>>() |
||||
const cascaderFirmware: CascaderProps = { |
||||
lazy: true, |
||||
async lazyLoad(node, resolve) { |
||||
const { level } = node |
||||
|
||||
if (level === 0) { |
||||
const deviceTypes = getIntDictOptions('device_entity_type').map(item => ({ |
||||
value: item.value, |
||||
label: item.label, |
||||
isLeaf: false, |
||||
})) |
||||
resolve(deviceTypes) |
||||
} |
||||
if (level === 1) { |
||||
const res = await getSimpleFirmwareList({ |
||||
type: node.data?.value as number, |
||||
}) |
||||
const data = Array.isArray(res?.data) ? res.data : [] |
||||
const firmware = data.map((item: any) => ({ |
||||
value: item.id, |
||||
label: item.name, |
||||
isLeaf: true, |
||||
leaf: true, |
||||
})) |
||||
resolve(firmware) |
||||
} |
||||
}, |
||||
} |
||||
|
||||
const selectFirmwareType = ref() |
||||
watch(firmwareSelect, (value: any) => { |
||||
selectFirmwareType.value = value[0] ?? '' |
||||
formData.value.firmwareId = String(value[1]) ?? '' |
||||
}) |
||||
|
||||
const isShowDeviceSelect = ref(false) |
||||
watch( |
||||
() => selectFirmwareType.value, |
||||
() => { |
||||
isShowDeviceSelect.value = false |
||||
nextTick(() => { |
||||
isShowDeviceSelect.value = |
||||
!isEmpty(selectFirmwareType.value) && |
||||
typeof selectFirmwareType.value !== 'undefined' |
||||
}) |
||||
} |
||||
) |
||||
|
||||
// const deviceCascaderRef = ref<InstanceType<typeof ElCascader>>() |
||||
// const cascaderDevice: CascaderProps = { |
||||
// lazy: true, |
||||
// multiple: true, |
||||
// async lazyLoad(node, resolve) { |
||||
// const { level } = node |
||||
// if (level === 0) { |
||||
// const res = await getSimpleStationList() |
||||
// if (isResError(res)) return |
||||
// const data = Array.isArray(res?.data) ? res.data : [] |
||||
// const nodes = data.map((item: any) => ({ |
||||
// value: item.id, |
||||
// label: item.name, |
||||
// isLeaf: false, |
||||
// })) |
||||
// resolve(nodes) |
||||
// } |
||||
// if (level === 1) { |
||||
// const res = await getSimpleDeviceList({ |
||||
// siteId: node.data?.value as number, |
||||
// type: selectFirmwareType.value, |
||||
// }) |
||||
|
||||
// const data = Array.isArray(res?.data) ? res.data : [] |
||||
// const devices = data.map((item: any) => ({ |
||||
// value: item.sn, |
||||
// label: item.name, |
||||
// isLeaf: true, |
||||
// leaf: true, |
||||
// })) |
||||
// resolve(devices) |
||||
// } |
||||
// }, |
||||
// } |
||||
|
||||
const deviceSelect = ref<CascaderValue>([]) |
||||
watch(deviceSelect, (value: any) => { |
||||
formData.value.deviceSns = value.map((item: any) => item[1]) |
||||
}) |
||||
|
||||
function devChange() {} |
||||
|
||||
const cascaderTag = ref<any[]>([]) |
||||
function changeSourceType(selectItem: any) { |
||||
if (!cascaderTag.value.includes(selectItem[0])) { |
||||
deviceSelect.value = [] |
||||
} |
||||
cascaderTag.value = selectItem |
||||
} |
||||
|
||||
const form = { |
||||
name: '', |
||||
executeNow: false, // 立即执行 |
||||
executeTime: '', // 执行时间 |
||||
retryCount: 3, // 重试次数 |
||||
retryInterval: 1000, // 重试间隔 |
||||
monitorTimeout: 1000, // 监控超时 |
||||
firmwareId: '', // 固件ID |
||||
deviceSns: [], // 设备SN |
||||
} |
||||
const formData = ref(cloneDeep(form)) |
||||
|
||||
function validate() { |
||||
if (!formData.value.name) { |
||||
message.error('请输入任务名称') |
||||
return true |
||||
} |
||||
if (!formData.value.firmwareId) { |
||||
message.error('请选择固件') |
||||
return true |
||||
} |
||||
if (!formData.value.deviceSns.length) { |
||||
message.error('请选择设备') |
||||
return true |
||||
} |
||||
if (!formData.value.executeNow && !formData.value.executeTime) { |
||||
message.error('请选择执行时间') |
||||
return true |
||||
} |
||||
if (!formData.value.monitorTimeout) { |
||||
message.error('请输入监控超时') |
||||
return true |
||||
} |
||||
if (!formData.value.retryCount) { |
||||
message.error('请输入重试次数') |
||||
return true |
||||
} |
||||
if (!formData.value.retryInterval) { |
||||
message.error('请输入重试间隔') |
||||
return true |
||||
} |
||||
return false |
||||
} |
||||
|
||||
function disabledExecuteDate(time: Date) { |
||||
return time.getTime() < Date.now() - 8.64e7 |
||||
} |
||||
async function onSave() { |
||||
if (validate()) return |
||||
const res = await createTask(formData.value) |
||||
if (isResError(res)) return |
||||
emits('on-save') |
||||
clearData() |
||||
} |
||||
function onClone() { |
||||
clearData() |
||||
emits('on-close') |
||||
} |
||||
|
||||
function clearData() { |
||||
formData.value = cloneDeep(form) |
||||
firmwareSelect.value = [] |
||||
cascaderTag.value = [] |
||||
deviceSelect.value = [] |
||||
} |
||||
</script> |
||||
|
||||
<style lang="scss"> |
||||
.task-device-select-cascader { |
||||
.el-cascader-panel { |
||||
.el-cascader-menu:first-child { |
||||
.el-cascader-node { |
||||
.el-checkbox { |
||||
display: none !important; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</style> |
||||
|
||||
<style scoped lang="scss"> |
||||
.create-task-dlg { |
||||
.dlg-body { |
||||
max-height: 400px; |
||||
} |
||||
.el-row { |
||||
height: 32px; |
||||
width: 74%; |
||||
margin-bottom: 20px; |
||||
:deep(.label) { |
||||
margin-right: 10px; |
||||
} |
||||
span { |
||||
width: 110px; |
||||
height: 32px; |
||||
line-height: 32px; |
||||
text-align: right; |
||||
} |
||||
:deep(.el-radio-group) { |
||||
height: 100%; |
||||
} |
||||
:deep(.el-radio) { |
||||
height: 100%; |
||||
} |
||||
} |
||||
.require { |
||||
color: red; |
||||
margin-right: 4px; |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,244 @@
@@ -0,0 +1,244 @@
|
||||
<template> |
||||
<div class="details-drawer"> |
||||
<el-drawer |
||||
v-model="isShow" |
||||
:title="`${props.rowData.taskName}任务详情`" |
||||
direction="rtl" |
||||
size="64%" |
||||
> |
||||
<main class="drawer-box"> |
||||
<el-scrollbar> |
||||
<div class="device-status"> |
||||
<template v-for="(item, idx) in deviceDetails" :key="idx"> |
||||
<div class="device-info"> |
||||
<div class="title">站点名称:{{ item.siteName }}</div> |
||||
<div class="body"> |
||||
<div class="info"> |
||||
<div class="item"> |
||||
<span class="label">设备:</span><span>{{ item.deviceName }}</span> |
||||
</div> |
||||
<div class="item"> |
||||
<span class="label">状态:</span |
||||
><span>{{ TaskStatus[item.node] ?? '未开始' }}</span> |
||||
</div> |
||||
<div class="item" v-if="item.node === 1"> |
||||
<span class="label">原因:</span><span>{{ item.reason }}</span> |
||||
</div> |
||||
</div> |
||||
<div class="progress" v-if="!isEmpty(item.node)"> |
||||
<el-progress |
||||
type="circle" |
||||
v-if="item.node === 0" |
||||
:percentage="100" |
||||
:stroke-width="10" |
||||
color="#16a34a" |
||||
> |
||||
<div class="progress-content" style="color: #16a34a"> |
||||
<div> |
||||
<Icon icon="mingcute:check-fill" :size="20" /> |
||||
</div> |
||||
<span class="percentage-label">升级成功</span> |
||||
</div> |
||||
</el-progress> |
||||
<el-progress |
||||
type="circle" |
||||
v-if="item.node === 1" |
||||
:percentage="100" |
||||
:stroke-width="10" |
||||
color="#ef4444" |
||||
> |
||||
<div class="progress-content" style="color: #ef4444"> |
||||
<div> |
||||
<Icon icon="mingcute:close-fill" :size="20" /> |
||||
</div> |
||||
<span class="percentage-label">升级失败</span> |
||||
</div> |
||||
</el-progress> |
||||
<el-progress |
||||
type="circle" |
||||
v-if="item.node === 2" |
||||
:percentage="item.subNode" |
||||
:stroke-width="10" |
||||
color="#3b82f6" |
||||
/> |
||||
<el-progress |
||||
type="circle" |
||||
v-if="item.node === 3" |
||||
:percentage="item.subNode" |
||||
:stroke-width="10" |
||||
color="#f97316" |
||||
:indeterminate="true" |
||||
/> |
||||
<el-progress |
||||
type="circle" |
||||
v-if="item.node === 4" |
||||
:percentage="item.subNode" |
||||
:stroke-width="10" |
||||
color="#10b981" |
||||
:duration="6" |
||||
/> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
</div> |
||||
</el-scrollbar> |
||||
</main> |
||||
</el-drawer> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import { isResError } from '@/hooks/useMessage' |
||||
import { getTaskDetails } from '@/api/module/eam/device/task' |
||||
import { isEmpty } from '@/utils/is' |
||||
import Icon from '@/components/dashboard/Icon/src/Icon.vue' |
||||
enum TaskStatus { |
||||
'升级成功', |
||||
'升级失败', |
||||
'接收中...', |
||||
'校验中...', |
||||
'升级中...', |
||||
} |
||||
interface Props { |
||||
rowData: any |
||||
taskMap: any |
||||
} |
||||
const props = withDefaults(defineProps<Props>(), { |
||||
taskMap: new Map(), |
||||
}) |
||||
const isShow = defineModel<boolean>() |
||||
|
||||
const deviceDetails = ref<any>([]) |
||||
async function loadData() { |
||||
const res = await getTaskDetails(props.rowData.id) |
||||
if (!isResError(res)) { |
||||
deviceDetails.value = Array.isArray(res.data) ? res.data : [] |
||||
} |
||||
} |
||||
|
||||
function updateData(data: any[]) { |
||||
console.log('object', data) |
||||
for (const d of data) { |
||||
const find = deviceDetails.value.find((item: any) => item.deviceSn == d.deviceSn) |
||||
if (find) { |
||||
find.node = d.node |
||||
find.subNode = d.subNode |
||||
find.reason = d.reason |
||||
} |
||||
} |
||||
} |
||||
|
||||
onMounted(async () => { |
||||
await loadData() |
||||
const taskId = props.rowData.id |
||||
let data = props.taskMap.get(taskId) |
||||
data = data ? Array.from(data.values()) : [] |
||||
updateData(data) |
||||
}) |
||||
|
||||
defineExpose({ |
||||
updateData, |
||||
}) |
||||
</script> |
||||
|
||||
<style lang="scss" scoped> |
||||
.details-drawer { |
||||
font-size: 16px; |
||||
:deep(.el-overlay) { |
||||
// background-color: transparent !important; |
||||
} |
||||
// :deep(.el-drawer) { |
||||
// width: calc(100% - 280px) !important; |
||||
// width: 70%; |
||||
// } |
||||
:deep(.el-drawer__header) { |
||||
margin-bottom: 10px; |
||||
padding: 10px; |
||||
border-bottom: 1px solid #ccc; |
||||
} |
||||
:deep(.el-drawer__body) { |
||||
padding: 20px; |
||||
padding-top: 0; |
||||
} |
||||
:deep(.el-drawer__title) { |
||||
font-family: Alibaba-PuHuiTi-M; |
||||
font-size: 16px; |
||||
color: #4d4d4d; |
||||
line-height: 24px; |
||||
font-weight: 500; |
||||
} |
||||
.drawer-box { |
||||
width: 100%; |
||||
height: 100%; |
||||
.device-status { |
||||
width: 100%; |
||||
height: 100%; |
||||
display: flex; |
||||
flex-wrap: wrap; |
||||
column-gap: 20px; |
||||
row-gap: 24px; |
||||
.device-info { |
||||
width: 280px; |
||||
height: 192px; |
||||
background: #ffffff; |
||||
border: 1px solid #e9e9e9; |
||||
box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.09); |
||||
border-radius: 4px; |
||||
display: flex; |
||||
flex-direction: column; |
||||
box-sizing: border-box; |
||||
.title { |
||||
display: flex; |
||||
align-items: center; |
||||
height: 48px; |
||||
width: 100%; |
||||
background-color: #f1f1f1; |
||||
box-sizing: border-box; |
||||
font-family: Alibaba-PuHuiTi-M; |
||||
font-size: 16px; |
||||
color: #030303; |
||||
font-weight: 500; |
||||
justify-content: space-between; |
||||
padding: 0 12px; |
||||
} |
||||
.body { |
||||
padding: 10px; |
||||
display: flex; |
||||
column-gap: 14px; |
||||
flex: 1; |
||||
.info { |
||||
width: 130px; |
||||
} |
||||
.progress { |
||||
flex: 1; |
||||
.progress-content { |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
row-gap: 8px; |
||||
} |
||||
} |
||||
.item { |
||||
display: flex; |
||||
min-height: 32px; |
||||
.label { |
||||
color: #6a6a6a; |
||||
font-size: 14px; |
||||
flex: 0.5; |
||||
} |
||||
span { |
||||
word-wrap: break-word; |
||||
word-break: break-all; |
||||
white-space: normal; |
||||
font-size: 14px; |
||||
flex: 1; |
||||
color: #3c3c3c; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,372 @@
@@ -0,0 +1,372 @@
|
||||
<template> |
||||
<div class="task-management-wrap"> |
||||
<EdfsWrap class="task-table" title="任务列表"> |
||||
<template #title-right> |
||||
<div class="task-table-title"> |
||||
<EdfsButton |
||||
type="success" |
||||
inner-text="创建升级任务" |
||||
:icon="createIcon" |
||||
@click="addTask" |
||||
/> |
||||
</div> |
||||
</template> |
||||
<edfs-table |
||||
:data="dataList" |
||||
:highlight-current-row="true" |
||||
ref="tableRef" |
||||
row-class-name="row" |
||||
:page-size="pageSize" |
||||
:page-total="pageTotal" |
||||
class="table" |
||||
:current-page="pageIndex" |
||||
@pageCurrentChange="handleJump" |
||||
> |
||||
<template v-for="(col, idx) in tableColumns" :key="idx"> |
||||
<el-table-column |
||||
v-if="col.prop === 'createTime'" |
||||
:label="col.label" |
||||
:prop="col.prop" |
||||
:min-width="col.width" |
||||
> |
||||
<template #default="scope"> |
||||
{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column |
||||
v-else-if="col.prop === 'status'" |
||||
:label="col.label" |
||||
:prop="col.prop" |
||||
:min-width="col.width" |
||||
> |
||||
<template #default="scope"> |
||||
{{ taskStatusMap[scope.row.status] }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column |
||||
v-else-if="col.prop === 'executeTime'" |
||||
:label="col.label" |
||||
:prop="col.prop" |
||||
:min-width="col.width" |
||||
> |
||||
<template #default="scope"> |
||||
{{ dayjs(scope.row.executeTime).format('YYYY-MM-DD HH:mm:ss') }} |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column |
||||
v-else-if="col.prop === 'deviceUpgradeDetail'" |
||||
:label="col.label" |
||||
:prop="col.prop" |
||||
:min-width="col.width" |
||||
> |
||||
<template #default="scope"> |
||||
<div> |
||||
<div>升级中:{{ scope.row.processingCount }}</div> |
||||
<div>失败数量: {{ scope.row.failCount }}</div> |
||||
<div>升级完成: {{ scope.row.successCount }}</div> |
||||
</div> |
||||
</template> |
||||
</el-table-column> |
||||
<el-table-column |
||||
v-else |
||||
:label="col.label" |
||||
:prop="col.prop" |
||||
:min-width="col.width" |
||||
/> |
||||
</template> |
||||
|
||||
<el-table-column label="操作" min-width="8%"> |
||||
<template #default="scope"> |
||||
<EdfsButton |
||||
type="success" |
||||
link |
||||
v-if="scope.row.status === 1 || scope.row.status === 2" |
||||
inner-text="详情" |
||||
@click="onDetails(scope.row)" |
||||
/> |
||||
</template> |
||||
</el-table-column> |
||||
</edfs-table> |
||||
</EdfsWrap> |
||||
<createTaskDlg :isShow="isShowDlg" @on-close="onClose" @on-save="onSave" /> |
||||
<detailsDrawer |
||||
ref="detailsRef" |
||||
:rowData="rowData" |
||||
:taskMap="taskMap" |
||||
v-model="isShowDetails" |
||||
v-if="isShowDetails" |
||||
/> |
||||
</div> |
||||
</template> |
||||
<script setup lang="ts"> |
||||
import { |
||||
addListener, |
||||
removeListener, |
||||
type SocketMsgListener, |
||||
} from '@/tools/event/socketEvent' |
||||
import { tableColumns, taskStatusMap } from './utils' |
||||
import EdfsButton from '@/components/dashboard/Edfs-button/index.vue' |
||||
import EdfsTable from '@/components/dashboard/Edfs-table/index.vue' |
||||
import EdfsWrap from '@/components/dashboard/Edfs-wrap.vue' |
||||
import { useIcon } from '@/utils/useIcon' |
||||
import createTaskDlg from './components/create-task-dlg.vue' |
||||
import detailsDrawer from './components/details-drawer.vue' |
||||
import { isResError, useMessage } from '@/hooks/useMessage.js' |
||||
import dayjs from 'dayjs' |
||||
import { getTaskList } from '@/api/module/eam/device/task' |
||||
|
||||
const message = useMessage() |
||||
|
||||
const createIcon = useIcon({ icon: 'gravity-ui:plus' }) |
||||
const tableRef = ref<any>(null) |
||||
const dataList = ref<any>([]) |
||||
const pageIndex = ref(1) |
||||
const pageSize = ref() |
||||
const pageTotal = ref(0) |
||||
const pageJump = ref(1) |
||||
|
||||
type DeviceMap = Map<number, any> |
||||
type TaskMap = Map<number, DeviceMap> |
||||
|
||||
const taskMap: TaskMap = new Map<number, DeviceMap>() |
||||
async function loadData() { |
||||
if (!pageSize.value) { |
||||
pageSize.value = tableRef.value.getSize() |
||||
} |
||||
const res = await getTaskList({ |
||||
pageNo: pageIndex.value, |
||||
pageSize: pageSize.value, |
||||
}) |
||||
if (isResError(res)) return |
||||
const { list, total } = res.data |
||||
dataList.value = list |
||||
pageTotal.value = total |
||||
|
||||
updateTaskData() |
||||
} |
||||
|
||||
watch(pageIndex, () => { |
||||
pageJump.value = pageIndex.value |
||||
loadData() |
||||
}) |
||||
|
||||
function handleJump(page: number) { |
||||
pageIndex.value = page |
||||
} |
||||
|
||||
const isShowDlg = ref(false) |
||||
function addTask() { |
||||
isShowDlg.value = true |
||||
} |
||||
|
||||
function onClose() { |
||||
isShowDlg.value = false |
||||
} |
||||
|
||||
function onSave() { |
||||
isShowDlg.value = false |
||||
loadData() |
||||
} |
||||
|
||||
const rowData = ref<any>({}) |
||||
const isShowDetails = ref(false) |
||||
async function onDetails(row: any) { |
||||
rowData.value = row |
||||
isShowDetails.value = true |
||||
} |
||||
|
||||
onMounted(async () => { |
||||
await loadData() |
||||
addListener(socketMsgListener) |
||||
}) |
||||
|
||||
onBeforeUnmount(() => { |
||||
removeListener(socketMsgListener) |
||||
}) |
||||
const detailsRef = ref<any>(null) |
||||
|
||||
const tasksStatusMap = new Map() |
||||
const socketMsgListener: SocketMsgListener = { |
||||
onCmdPost: function (type: string, stationId: number, data?: any, time?: string) { |
||||
if (type === 'upgrade') { |
||||
const { deviceSn, taskId } = data |
||||
if (!taskId || !deviceSn) return |
||||
let deviceMap = taskMap.get(taskId) |
||||
if (!deviceMap) { |
||||
deviceMap = new Map<number, any>() |
||||
taskMap.set(taskId, deviceMap) |
||||
} |
||||
deviceMap.set(deviceSn, data) |
||||
|
||||
if (detailsRef.value && rowData.value?.id) { |
||||
const taskId = rowData.value?.id |
||||
let taskData = taskMap.get(taskId) |
||||
const dataArray = taskData ? Array.from(taskData.values()) : [] |
||||
detailsRef.value.updateData(dataArray) |
||||
} |
||||
} |
||||
if (type === 'upgrade-task' && data.id) { |
||||
tasksStatusMap.set(data.id, data) |
||||
updateTaskData() |
||||
} |
||||
}, |
||||
} |
||||
|
||||
function updateTaskData() { |
||||
for (const data of dataList.value) { |
||||
const taskData = tasksStatusMap.get(data.id) |
||||
if (!taskData) continue |
||||
data.status = taskData.status |
||||
data.processingCount = taskData.processingCount |
||||
data.failCount = taskData.failCount |
||||
data.successCount = taskData.successCount |
||||
} |
||||
} |
||||
|
||||
// let a = [ |
||||
// { |
||||
// type: 'upgrade', |
||||
// stationId: 1, |
||||
// time: 1726129158000, |
||||
// data: { |
||||
// id: 1, |
||||
// taskId: 32, |
||||
// deviceId: 1, |
||||
// node: 0, |
||||
// subNode: 10, |
||||
// reason: null, |
||||
// deviceSn: '4', |
||||
// tenantId: 162, |
||||
// createTime: 1725533993000, |
||||
// updateTime: 1725533993000, |
||||
// creator: '145', |
||||
// updater: '145', |
||||
// deleted: false, |
||||
// }, |
||||
// }, |
||||
// { |
||||
// type: 'upgrade', |
||||
// stationId: 1, |
||||
// time: 1726129158000, |
||||
// data: { |
||||
// id: 1, |
||||
// taskId: 32, |
||||
// deviceId: 1, |
||||
// node: 1, |
||||
// subNode: 10, |
||||
// reason: 'null', |
||||
// deviceSn: '5', |
||||
// tenantId: 162, |
||||
// createTime: 1725533993000, |
||||
// updateTime: 1725533993000, |
||||
// creator: '145', |
||||
// updater: '145', |
||||
// deleted: false, |
||||
// }, |
||||
// }, |
||||
// { |
||||
// type: 'upgrade', |
||||
// stationId: 1, |
||||
// time: 1726129158000, |
||||
// data: { |
||||
// id: 1, |
||||
// taskId: 32, |
||||
// deviceId: 1, |
||||
// node: 2, |
||||
// subNode: 10, |
||||
// reason: 'null', |
||||
// deviceSn: '6', |
||||
// tenantId: 162, |
||||
// createTime: 1725533993000, |
||||
// updateTime: 1725533993000, |
||||
// creator: '145', |
||||
// updater: '145', |
||||
// deleted: false, |
||||
// }, |
||||
// }, |
||||
// { |
||||
// type: 'upgrade', |
||||
// stationId: 1, |
||||
// time: 1726129158000, |
||||
// data: { |
||||
// id: 1, |
||||
// taskId: 1, |
||||
// deviceId: 1, |
||||
// node: 3, |
||||
// subNode: 10, |
||||
// reason: null, |
||||
// deviceSn: '6', |
||||
// tenantId: 162, |
||||
// createTime: 1725533993000, |
||||
// updateTime: 1725533993000, |
||||
// creator: '145', |
||||
// updater: '145', |
||||
// deleted: false, |
||||
// }, |
||||
// }, |
||||
// { |
||||
// type: 'upgrade', |
||||
// stationId: 1, |
||||
// time: 1726129158000, |
||||
// data: { |
||||
// id: 1, |
||||
// taskId: 1, |
||||
// deviceId: 1, |
||||
// node: 1, |
||||
// subNode: 10, |
||||
// reason: null, |
||||
// deviceSn: '6', |
||||
// tenantId: 162, |
||||
// createTime: 1725533993000, |
||||
// updateTime: 1725533993000, |
||||
// creator: '145', |
||||
// updater: '145', |
||||
// deleted: false, |
||||
// }, |
||||
// }, |
||||
// ] |
||||
// function test(type: string, stationId: number, data?: any, time?: number) { |
||||
// if (type === 'upgrade') { |
||||
// const { deviceSn, taskId } = data |
||||
// if (!taskId || !deviceSn) return |
||||
// // 存储设备状态 |
||||
// let deviceMap = taskMap.get(taskId) |
||||
// if (!deviceMap) { |
||||
// deviceMap = new Map<number, any>() |
||||
// taskMap.set(taskId, deviceMap) |
||||
// } |
||||
// deviceMap.set(deviceSn, data) |
||||
|
||||
// if (detailsRef.value && rowData.value?.id) { |
||||
// const taskId = rowData.value?.id |
||||
// let taskData = taskMap.get(taskId) |
||||
// const dataArray = taskData ? Array.from(taskData.values()) : [] |
||||
// detailsRef.value.updateData(dataArray) |
||||
// } |
||||
// } |
||||
// } |
||||
|
||||
// setInterval(() => { |
||||
// for (const item of a) { |
||||
// test(item.type, item.stationId, item.data, item.time) |
||||
// } |
||||
// }, 1000) |
||||
</script> |
||||
|
||||
<style scoped lang="scss"> |
||||
.task-management-wrap { |
||||
width: 100%; |
||||
height: 100%; |
||||
.task-table { |
||||
height: 100%; |
||||
box-sizing: border-box; |
||||
|
||||
background: #fff; |
||||
padding-bottom: 0; |
||||
.table { |
||||
height: 100%; |
||||
width: 100%; |
||||
} |
||||
} |
||||
} |
||||
</style> |
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
export const tableColumns = [ |
||||
{ |
||||
label: '任务名称', |
||||
prop: 'taskName', |
||||
width: '10%', |
||||
}, |
||||
{ |
||||
label: '固件名称', |
||||
prop: 'name', |
||||
width: '8%', |
||||
}, |
||||
{ |
||||
label: '固件版本', |
||||
prop: 'version', |
||||
width: '6%', |
||||
}, |
||||
|
||||
{ |
||||
label: '创建时间', |
||||
prop: 'createTime', |
||||
width: '18%', |
||||
}, |
||||
{ |
||||
label: '任务执行时间', |
||||
prop: 'executeTime', |
||||
width: '18%', |
||||
}, |
||||
{ |
||||
label: '升级详情', |
||||
prop: 'deviceUpgradeDetail', |
||||
width: '10%', |
||||
}, |
||||
{ |
||||
label: '任务状态', |
||||
prop: 'status', |
||||
width: '8%', |
||||
}, |
||||
] |
||||
|
||||
export const taskStatusMap = { |
||||
0: '未开始', |
||||
1: '进行中', |
||||
2: '已完成', |
||||
} |
@ -0,0 +1,87 @@
@@ -0,0 +1,87 @@
|
||||
<template> |
||||
<div class="device-dispose-warp"> |
||||
<div class="top-filter"> |
||||
<FormItemSelect |
||||
:options="[]" |
||||
placeholder="请选择" |
||||
keyTag="value" |
||||
labelTag="label" |
||||
:isShowLabel="false" |
||||
class="filter-select" |
||||
/> |
||||
<el-input class="filter-input" placeholder="请输入" /> |
||||
</div> |
||||
<div class="content-box"> |
||||
<div class="item-info"> |
||||
<div class="info"> |
||||
<div class="type"> |
||||
<div class="reason">处置原因</div> |
||||
<div class="name">报废</div> |
||||
</div> |
||||
<div class="describe"> |
||||
<div>添加人: 向向</div> |
||||
<div>添加时间: 2022-10-31 18:00:00</div> |
||||
</div> |
||||
</div> |
||||
<div class="operation"> |
||||
<EdfsButton link type="primary" :icon="editIcon" /> |
||||
<EdfsButton link type="danger" :icon="delIcon" style="margin-left: 0px" /> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script setup lang="ts"> |
||||
import FormItemSelect from '@/components/dashboard/FormItemSelect.vue' |
||||
import { useIcon } from '@/utils/useIcon' |
||||
const editIcon = useIcon({ icon: 'fluent:edit-16-regular' }) |
||||
const delIcon = useIcon({ icon: 'fluent:delete-16-regular' }) |
||||
</script> |
||||
|
||||
<style scoped lang="scss"> |
||||
.device-dispose-warp { |
||||
.top-filter { |
||||
display: flex; |
||||
height: 32px; |
||||
.filter-select { |
||||
flex: 0.7; |
||||
margin-right: 4px; |
||||
} |
||||
.filter-input { |
||||
flex: 1; |
||||
} |
||||
} |
||||
.content-box { |
||||
width: 100%; |
||||
height: calc(100% - 32px); |
||||
.item-info { |
||||
border-bottom: 1px solid var(--el-border-color); |
||||
padding: 10px 0; |
||||
display: flex; |
||||
.info { |
||||
.type { |
||||
display: flex; |
||||
column-gap: 6px; |
||||
} |
||||
.describe { |
||||
display: flex; |
||||
column-gap: 6px; |
||||
color: var(--text-desc); |
||||
} |
||||
border-left: 2px solid #048b87; |
||||
padding-left: 6px; |
||||
} |
||||
.operation { |
||||
flex: 1; |
||||
display: flex; |
||||
justify-content: end; |
||||
:deep(.el-button) { |
||||
margin-top: auto; |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
} |
||||
</style> |
Loading…
Reference in new issue