Browse Source

feat: 固件升级

master
wangqi 2 months ago
parent
commit
b204694713
  1. 2
      .env.development
  2. 33
      components.d.ts
  3. 2
      src/api/module/eam/device/firmware.ts
  4. 13
      src/api/module/eam/device/index.ts
  5. 6
      src/api/module/eam/device/task.ts
  6. 119
      src/pages/deviceInfo/components/BasicInfo.vue
  7. 17
      src/pages/deviceInfo/components/data-filter.vue
  8. 4
      src/pages/deviceInfo/index.vue
  9. 4
      src/pages/deviceInfo/utils.ts
  10. 2
      src/pages/deviceStorage/utils.ts
  11. 7
      src/pages/deviceTest/testPlan/components/InfoDlg.vue
  12. 7
      src/pages/layout.vue
  13. 11
      src/pages/ota/firmware/components/create-firmware-dlg.vue
  14. 252
      src/pages/ota/upgradeTask/components/create-task-dlg.vue
  15. 9
      src/pages/ota/upgradeTask/index.vue
  16. 3
      src/pages/system/deviceField/components/CategoryDlg.vue

2
.env.development

@ -1,2 +1,2 @@
VITE_BASE_URL = 'http://192.168.1.3:48080' VITE_BASE_URL = 'http://192.168.1.3:48080'
VITE_SOCKET_SERVER = 'http://192.168.1.3:7080' VITE_SOCKET_SERVER = 'http://192.168.1.3:48080'

33
components.d.ts vendored

@ -21,10 +21,20 @@ declare module 'vue' {
EdfsTable: typeof import('./src/components/dashboard/Edfs-table/index.vue')['default'] EdfsTable: typeof import('./src/components/dashboard/Edfs-table/index.vue')['default']
EdfsWrap: typeof import('./src/components/dashboard/Edfs-wrap.vue')['default'] EdfsWrap: typeof import('./src/components/dashboard/Edfs-wrap.vue')['default']
Editor: typeof import('./src/components/dashboard/Editor/src/Editor.vue')['default'] Editor: typeof import('./src/components/dashboard/Editor/src/Editor.vue')['default']
ElAvatar: typeof import('element-plus/es')['ElAvatar']
ElButton: typeof import('element-plus/es')['ElButton'] ElButton: typeof import('element-plus/es')['ElButton']
ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup'] ElButtonGroup: typeof import('element-plus/es')['ElButtonGroup']
ElCard: typeof import('element-plus/es')['ElCard']
ElCascader: typeof import('element-plus/es')['ElCascader']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCol: typeof import('element-plus/es')['ElCol']
ElCollapse: typeof import('element-plus/es')['ElCollapse']
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider'] ElDivider: typeof import('element-plus/es')['ElDivider']
ElDrawer: typeof import('element-plus/es')['ElDrawer']
ElDropdown: typeof import('element-plus/es')['ElDropdown'] ElDropdown: typeof import('element-plus/es')['ElDropdown']
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem'] ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu'] ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
@ -32,20 +42,40 @@ declare module 'vue' {
ElFormItem: typeof import('element-plus/es')['ElFormItem'] ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElHeader: typeof import('element-plus/es')['ElHeader'] ElHeader: typeof import('element-plus/es')['ElHeader']
ElIcon: typeof import('element-plus/es')['ElIcon'] ElIcon: typeof import('element-plus/es')['ElIcon']
ElImageViewer: typeof import('element-plus/es')['ElImageViewer']
ElInput: typeof import('element-plus/es')['ElInput'] ElInput: typeof import('element-plus/es')['ElInput']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElLink: typeof import('element-plus/es')['ElLink']
ElMenu: typeof import('element-plus/es')['ElMenu'] ElMenu: typeof import('element-plus/es')['ElMenu']
ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
ElOption: typeof import('element-plus/es')['ElOption']
ElPagination: typeof import('element-plus/es')['ElPagination'] ElPagination: typeof import('element-plus/es')['ElPagination']
ElPopover: typeof import('element-plus/es')['ElPopover'] ElPopover: typeof import('element-plus/es')['ElPopover']
ElProgress: typeof import('element-plus/es')['ElProgress']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElRow: typeof import('element-plus/es')['ElRow']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSpace: typeof import('element-plus/es')['ElSpace']
ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane'] ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs'] ElTabs: typeof import('element-plus/es')['ElTabs']
ElTag: typeof import('element-plus/es')['ElTag']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree']
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect']
ElUpload: typeof import('element-plus/es')['ElUpload']
Form: typeof import('./src/components/dashboard/Form/src/Form.vue')['default'] Form: typeof import('./src/components/dashboard/Form/src/Form.vue')['default']
FormItemInput: typeof import('./src/components/dashboard/FormItemInput.vue')['default'] FormItemInput: typeof import('./src/components/dashboard/FormItemInput.vue')['default']
FormItemSelect: typeof import('./src/components/dashboard/FormItemSelect.vue')['default'] FormItemSelect: typeof import('./src/components/dashboard/FormItemSelect.vue')['default']
Icon: typeof import('./src/components/dashboard/Icon/src/Icon.vue')['default'] Icon: typeof import('./src/components/dashboard/Icon/src/Icon.vue')['default']
IconSelect: typeof import('./src/components/dashboard/Icon/src/IconSelect.vue')['default'] IconSelect: typeof import('./src/components/dashboard/Icon/src/IconSelect.vue')['default']
IEpUploadFilled: typeof import('~icons/ep/upload-filled')['default']
ImageViewer: typeof import('./src/components/dashboard/ImageViewer/src/ImageViewer.vue')['default'] ImageViewer: typeof import('./src/components/dashboard/ImageViewer/src/ImageViewer.vue')['default']
InputPassword: typeof import('./src/components/dashboard/InputPassword/src/InputPassword.vue')['default'] InputPassword: typeof import('./src/components/dashboard/InputPassword/src/InputPassword.vue')['default']
LegendItem: typeof import('./src/components/map_tool/legend/LegendItem.vue')['default'] LegendItem: typeof import('./src/components/map_tool/legend/LegendItem.vue')['default']
@ -63,4 +93,7 @@ declare module 'vue' {
XButton: typeof import('./src/components/dashboard/XButton/src/XButton.vue')['default'] XButton: typeof import('./src/components/dashboard/XButton/src/XButton.vue')['default']
XTextButton: typeof import('./src/components/dashboard/XButton/src/XTextButton.vue')['default'] XTextButton: typeof import('./src/components/dashboard/XButton/src/XTextButton.vue')['default']
} }
export interface ComponentCustomProperties {
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
}
} }

2
src/api/module/eam/device/firmware.ts

@ -26,7 +26,7 @@ export function createFirmware(data: any) {
}) })
} }
export function getSimpleFirmwareList(params: { type: number }) { export function getSimpleFirmwareList(params: { type: string }) {
return eamServer({ return eamServer({
url: '/firmware/simple-list', url: '/firmware/simple-list',
method: 'get', method: 'get',

13
src/api/module/eam/device/index.ts

@ -16,17 +16,21 @@ export interface IDevice {
testSheetId: number testSheetId: number
testSheetStatus: string testSheetStatus: string
testSheetDetail: string testSheetDetail: string
currentFirmwareId: string
targetFirmwareId: string
} }
export interface IDeviceOV { export interface IDeviceOV {
id?: number id?: number
name: string name?: string
categoryId: string categoryId: string
templateId: string templateId: string
serialNo?: string serialNo?: string
sn: string sn: string
description: string description: string
cost: string cost: string
currentFirmwareId: string
targetFirmwareId: string
} }
export const operantDevice = (type: OperantAction, data: IDeviceOV) => { export const operantDevice = (type: OperantAction, data: IDeviceOV) => {
@ -82,6 +86,13 @@ export const getDeviceSummaryByStatus = () => {
}) })
} }
export const getSimpleDeviceList = (params: { categoryId: string }) =>
eamServer({
url: `/device/simple-list`,
method: 'get',
params,
})
// ============== 测试工单相关 ============== // ============== 测试工单相关 ==============
export const operantDeviceTestSheet = (type: OperantAction, params: any) => { export const operantDeviceTestSheet = (type: OperantAction, params: any) => {

6
src/api/module/eam/device/task.ts

@ -2,7 +2,7 @@ import { eamServer } from '../../index'
export function getTaskList(params: PageParam) { export function getTaskList(params: PageParam) {
return eamServer({ return eamServer({
url: '/device/task/page', url: '/task/page',
method: 'get', method: 'get',
params, params,
}) })
@ -10,7 +10,7 @@ export function getTaskList(params: PageParam) {
export function getTaskDetails(id: string) { export function getTaskDetails(id: string) {
return eamServer({ return eamServer({
url: '/device/task/details', url: '/task/details',
method: 'get', method: 'get',
params: { id }, params: { id },
}) })
@ -18,7 +18,7 @@ export function getTaskDetails(id: string) {
export function createTask(data: any) { export function createTask(data: any) {
return eamServer({ return eamServer({
url: '/device/firmware/remote-update', url: '/firmware/remote-update',
method: 'post', method: 'post',
data, data,
}) })

119
src/pages/deviceInfo/components/BasicInfo.vue

@ -13,16 +13,6 @@
> >
</el-input> </el-input>
</div> </div>
<div class="from-row">
<div class="label">设备名称:</div>
<el-input
class="input"
v-model="params.name"
:disabled="disabled"
placeholder="请输入设备名称"
clearable
/>
</div>
<div class="from-row"> <div class="from-row">
<div class="label">设备SN:</div> <div class="label">设备SN:</div>
@ -34,8 +24,6 @@
clearable clearable
/> />
</div> </div>
</div>
<div class="group-box">
<div class="from-row"> <div class="from-row">
<div class="label">设备类别:</div> <div class="label">设备类别:</div>
<el-cascader <el-cascader
@ -47,9 +35,30 @@
checkStrictly: true, checkStrictly: true,
value: 'id', value: 'id',
label: 'name', label: 'name',
emitPath: false,
}" }"
/> />
</div> </div>
</div>
<div class="group-box">
<div class="from-row">
<div class="label">设备固件:</div>
<el-select
v-model="params.targetFirmwareId"
placeholder="请选择固件"
style="flex: 1"
:disabled="disabled ? true : isEmpty(params.categoryId)"
class="input"
@visible-change="loadFirmwareList"
>
<el-option
v-for="item in firmwareList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</div>
<div class="from-row"> <div class="from-row">
<div class="label">测试模板:</div> <div class="label">测试模板:</div>
<FormItemSelect <FormItemSelect
@ -75,6 +84,15 @@
</div> </div>
</div> </div>
<div class="group-box"> <div class="group-box">
<div class="from-row">
<div class="label">当前固件:</div>
<number-input
class="input"
:disabled="true"
v-model="params.currentFirmwareId"
placeholder="设备暂无固件"
/>
</div>
<div class="from-row"> <div class="from-row">
<div class="label">备注:</div> <div class="label">备注:</div>
<el-input <el-input
@ -83,7 +101,7 @@
type="textarea" type="textarea"
v-model="params.description" v-model="params.description"
placeholder="请输入备注" placeholder="请输入备注"
:autosize="{ minRows: 5, maxRows: 4 }" :autosize="{ minRows: 3, maxRows: 4 }"
resize="none" resize="none"
/> />
</div> </div>
@ -95,6 +113,13 @@
v-if="isShowSaveButton" v-if="isShowSaveButton"
@click="onSave" @click="onSave"
/> />
<EdfsButton
inner-text="固件升级"
type="primary"
class="save-button"
v-if="isShowFirmwareUpgradeButton"
@click="onFirmwareUpgrade"
/>
</div> </div>
</div> </div>
</template> </template>
@ -103,15 +128,17 @@
import { isEmpty } from '@/utils/is' import { isEmpty } from '@/utils/is'
import numberInput from '@/components/dashboard/Edfs-number-item-input.vue' import numberInput from '@/components/dashboard/Edfs-number-item-input.vue'
import EdfsButton from '@/components/dashboard/Edfs-button/index.vue' import EdfsButton from '@/components/dashboard/Edfs-button/index.vue'
import { getSimpleFirmwareList } from '@/api/module/eam/device/firmware'
import FormItemSelect from '@/components/dashboard/FormItemSelect.vue' import FormItemSelect from '@/components/dashboard/FormItemSelect.vue'
import { operantDevice, type IDevice, type IDeviceOV } from '@/api/module/eam/device' import { operantDevice, type IDevice, type IDeviceOV } from '@/api/module/eam/device'
import { cloneDeep } from 'lodash' import { cloneDeep } from 'lodash'
import { isResError, useMessage } from '@/hooks/useMessage' import { isResError, useMessage } from '@/hooks/useMessage'
import { getDeviceTempSimpleList } from '@/api/module/eam/device/template' import { getDeviceTempSimpleList } from '@/api/module/eam/device/template'
import { getCategoryTree, type ICategoryTree } from '@/api/module/eam/device/category' import { getCategoryTree, type ICategoryTree } from '@/api/module/eam/device/category'
import { useRoute } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import type { OptAction } from '../utils' import type { OptAction } from '../utils'
const route = useRoute() const route = useRoute()
const router = useRouter()
const action = route.query.action as OptAction const action = route.query.action as OptAction
const message = useMessage() const message = useMessage()
const props = defineProps<{ const props = defineProps<{
@ -122,20 +149,29 @@ const props = defineProps<{
const emit = defineEmits(['on-save']) const emit = defineEmits(['on-save'])
const paramsData: IDeviceOV = { const paramsData: IDeviceOV = {
name: '', currentFirmwareId: '',
categoryId: '', categoryId: '',
templateId: '', templateId: '',
sn: '', sn: '',
serialNo: '', serialNo: '',
description: '', description: '',
cost: '', cost: '',
targetFirmwareId: '',
} }
const isShowSaveButton = computed(() => { const isShowSaveButton = computed(() => {
if(action === 'view') return false if (action === 'view') return false
return props.info?.status === undefined ? true : props.info.status < 2 return props.info?.status === undefined ? true : props.info.status < 2
}) })
const isShowFirmwareUpgradeButton = computed(() => {
if (action === 'view') return false
return props.info?.status === undefined
? false
: props.info.status >= 1 && props.info.targetFirmwareId
})
const params = ref(cloneDeep(paramsData)) const params = ref(cloneDeep(paramsData))
async function onSave() { async function onSave() {
@ -144,9 +180,6 @@ async function onSave() {
const type = !!params.value.serialNo ? 'update' : 'create' const type = !!params.value.serialNo ? 'update' : 'create'
const options = cloneDeep(params.value) const options = cloneDeep(params.value)
if (type === 'update') options.id = props.info?.id if (type === 'update') options.id = props.info?.id
options.categoryId = Array.isArray(options.categoryId)
? options.categoryId[options.categoryId.length - 1]
: options.categoryId
const res = await operantDevice(type, options) const res = await operantDevice(type, options)
if (isResError(res)) return if (isResError(res)) return
message.success('基础信息提交成功') message.success('基础信息提交成功')
@ -162,34 +195,40 @@ watch(
params.value[key] = info[key] ?? '' params.value[key] = info[key] ?? ''
} }
} }
console.log(params.value)
}, },
{ immediate: true } { immediate: true }
) )
watch(
() => params.value.categoryId,
val => {
params.value.targetFirmwareId = ''
}
)
function validate() { function validate() {
if (isEmpty(params.value.name)) { if (isEmpty(params.value.targetFirmwareId)) {
message.error('设备名称不能为空') message.error('请选择固件')
return false return false
} }
if (isEmpty(params.value.sn)) { if (isEmpty(params.value.sn)) {
message.error('设备SN不能为空') message.error('请输入设备SN')
return false return false
} }
if (isEmpty(params.value.categoryId)) { if (isEmpty(params.value.categoryId)) {
message.error('设备类别不能为空') message.error('请选择设备类别')
return false return false
} }
if (isEmpty(params.value.templateId)) { if (isEmpty(params.value.templateId)) {
message.error('测试模板不能为空') message.error('请选择测试模板')
return false return false
} }
if (isEmpty(params.value.cost)) { if (isEmpty(params.value.cost)) {
message.error('设备成本不能为空') message.error('请输入设备成本')
return false return false
} }
@ -212,6 +251,34 @@ async function loadDeviceTypeTree() {
categoryTreeData.value = res.data categoryTreeData.value = res.data
} }
} }
const firmwareList = ref<any[]>([])
async function loadFirmwareList(value: boolean) {
if (!value) return
if (isEmpty(params.value.categoryId)) {
message.error('请选择设备类别')
return
}
const res = await getSimpleFirmwareList({ type: params.value.categoryId as any })
if (!isResError(res)) {
firmwareList.value = res.data
}
}
function onFirmwareUpgrade() {
if (!props.info) return
router.push({
path: '/ota/upgradeTask',
query: {
type: 'create',
categoryId: props.info.categoryId,
deviceSn: props.info.sn,
firmwareId: props.info.targetFirmwareId,
},
})
}
onMounted(() => { onMounted(() => {
loadDeviceTypeTree() loadDeviceTypeTree()
loadTemplateList() loadTemplateList()

17
src/pages/deviceInfo/components/data-filter.vue

@ -37,8 +37,8 @@
<el-checkbox v-model="checkbox.serialNo" size="large" /> <el-checkbox v-model="checkbox.serialNo" size="large" />
</div> </div>
<div class="item"> <div class="item">
<el-input placeholder="请输入设备名称" v-model="filterData.name" /> <el-input placeholder="请输入设备sn" v-model="filterData.sn" />
<el-checkbox v-model="checkbox.name" size="large" /> <el-checkbox v-model="checkbox.sn" size="large" />
</div> </div>
<div class="item"> <div class="item">
@ -67,6 +67,7 @@
checkStrictly: true, checkStrictly: true,
value: 'id', value: 'id',
label: 'name', label: 'name',
emitPath: false,
}" }"
/> />
<el-checkbox v-model="checkbox.categoryId" size="large" /> <el-checkbox v-model="checkbox.categoryId" size="large" />
@ -109,16 +110,16 @@ type FilterKeys = keyof typeof filterData.value
const filterData = ref({ const filterData = ref({
startDay: '', startDay: '',
endDay: '', endDay: '',
name: '', sn: '',
status: '', status: '',
serialNo: '', serialNo: '',
categoryId: [], categoryId: '',
}) })
const checkbox = ref<Record<FilterKeys, boolean>>({ const checkbox = ref<Record<FilterKeys, boolean>>({
startDay: false, startDay: false,
endDay: false, endDay: false,
name: false, sn: false,
serialNo: false, serialNo: false,
status: false, status: false,
categoryId: false, categoryId: false,
@ -147,14 +148,16 @@ function onReset() {
filterData.value = { filterData.value = {
startDay: '', startDay: '',
endDay: '', endDay: '',
name: '', sn: '',
status: '',
serialNo: '', serialNo: '',
categoryId: [], categoryId: [],
} }
checkbox.value = { checkbox.value = {
startDay: false, startDay: false,
endDay: false, endDay: false,
name: false, sn: false,
status: false,
serialNo: false, serialNo: false,
categoryId: false, categoryId: false,
} }

4
src/pages/deviceInfo/index.vue

@ -130,9 +130,7 @@ const getList = async () => {
} }
loading.value = true loading.value = true
const options = Object.assign({}, queryParams, filter.value, { const options = Object.assign({}, queryParams, filter.value)
categoryId: filter.value.categoryId?.[filter.value.categoryId.length - 1],
})
const res = await getDevicePage(options) const res = await getDevicePage(options)

4
src/pages/deviceInfo/utils.ts

@ -5,11 +5,11 @@ export enum DeviceStatus {
, ,
} }
export const deviceTableCol = [ export const deviceTableCol = [
{ label: '设备sn', prop: 'sn', minWidth: '10%' },
{ label: '设备编号', prop: 'serialNo', minWidth: '16%' }, { label: '设备编号', prop: 'serialNo', minWidth: '16%' },
{ label: '设备名称', prop: 'name', minWidth: '10%' }, // { label: '设备名称', prop: 'name', minWidth: '10%' },
{ label: '设备类型', prop: 'categoryName', minWidth: '10%' }, { label: '设备类型', prop: 'categoryName', minWidth: '10%' },
{ label: '设备状态', prop: 'status', minWidth: '10%' }, { label: '设备状态', prop: 'status', minWidth: '10%' },
{ label: '设备sn', prop: 'sn', minWidth: '10%' },
{ label: '创建时间', prop: 'createTime', minWidth: '10%' }, { label: '创建时间', prop: 'createTime', minWidth: '10%' },
] ]

2
src/pages/deviceStorage/utils.ts

@ -1,5 +1,5 @@
export const tableCol = [ export const tableCol = [
{ label: '设备名称', prop: 'deviceName', minWidth: '10%' }, // { label: '设备名称', prop: 'deviceName', minWidth: '10%' },
{ label: '设备sn', prop: 'sn', minWidth: '10%' }, { label: '设备sn', prop: 'sn', minWidth: '10%' },
{ label: '库存状态', prop: 'status', minWidth: '10%' }, { label: '库存状态', prop: 'status', minWidth: '10%' },
{ label: '客户', prop: 'customerName', minWidth: '14%' }, { label: '客户', prop: 'customerName', minWidth: '14%' },

7
src/pages/deviceTest/testPlan/components/InfoDlg.vue

@ -22,6 +22,7 @@
checkStrictly: true, checkStrictly: true,
value: 'id', value: 'id',
label: 'name', label: 'name',
emitPath: false,
}" }"
clearable clearable
/> />
@ -86,9 +87,7 @@ async function onSave() {
if (!validate()) return if (!validate()) return
loading.value = true loading.value = true
const params = cloneDeep(formData.value) const params = cloneDeep(formData.value)
params.categoryId = Array.isArray(params.categoryId)
? params.categoryId[params.categoryId.length - 1]
: params.categoryId
let res let res
if (props.action === 'create') { if (props.action === 'create') {
res = await createdDeviceTemp(params) res = await createdDeviceTemp(params)
@ -109,7 +108,7 @@ function validate() {
return false return false
} }
if (formData.value.categoryId.length === 0) { if (isEmpty(formData.value.categoryId)) {
message.error('请选择设备类型') message.error('请选择设备类型')
return false return false
} }

7
src/pages/layout.vue

@ -111,6 +111,7 @@ import Avatar from './avatar.png'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useTheme } from '@/utils/useTheme' import { useTheme } from '@/utils/useTheme'
import { THEME_KEY, INIT_OPTIONS_KEY } from 'vue-echarts' import { THEME_KEY, INIT_OPTIONS_KEY } from 'vue-echarts'
import { openSocket, closeSocket } from '@/pages/socket_server/index'
import { registerTheme } from 'echarts/core' import { registerTheme } from 'echarts/core'
const { theme, toggle } = useTheme() const { theme, toggle } = useTheme()
import { customDark, customLight } from '@/utils/dark' import { customDark, customLight } from '@/utils/dark'
@ -121,6 +122,8 @@ provide(INIT_OPTIONS_KEY, {
devicePixelRatio: 2, devicePixelRatio: 2,
}) })
openSocket()
const route = useRoute() const route = useRoute()
const breadcrumbItems = computed(() => { const breadcrumbItems = computed(() => {
@ -236,7 +239,9 @@ async function loginOut() {
} catch {} } catch {}
} }
onUnmounted(() => {
closeSocket()
})
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

11
src/pages/ota/firmware/components/create-firmware-dlg.vue

@ -23,11 +23,12 @@
class="input" class="input"
v-model="formData.type" v-model="formData.type"
:options="categoryTreeData" :options="categoryTreeData"
style="flex: 1;" style="flex: 1"
:props="{ :props="{
checkStrictly: true, checkStrictly: true,
value: 'id', value: 'id',
label: 'name', label: 'name',
emitPath: false,
}" }"
/> />
</el-row> </el-row>
@ -69,7 +70,7 @@ import EdfsDialog from '@/components/dashboard/Edfs-dialog.vue'
import FormItemInput from '@/components/dashboard/FormItemInput.vue' import FormItemInput from '@/components/dashboard/FormItemInput.vue'
import { isResError, useMessage } from '@/hooks/useMessage' import { isResError, useMessage } from '@/hooks/useMessage'
import FormItemSelect from '@/components/dashboard/FormItemSelect.vue' import FormItemSelect from '@/components/dashboard/FormItemSelect.vue'
import { getTenantId } from '@/utils/auth' // import { getTenantId } from '@/utils/auth'
import { getIntDictOptions } from '@/utils/dict' import { getIntDictOptions } from '@/utils/dict'
const message = useMessage() const message = useMessage()
@ -122,7 +123,7 @@ function validate() {
return true return true
} }
if (formData.value.type.length < 1) { if (!formData.value.type) {
message.error('请选择固件类型') message.error('请选择固件类型')
return true return true
} }
@ -139,11 +140,11 @@ async function onSave() {
if (validate()) return if (validate()) return
loading.value = true loading.value = true
const data = new FormData() const data = new FormData()
data.append('path', getTenantId()) // data.append('path', getTenantId())
data.append('file', fileList.value[0].raw as File) data.append('file', fileList.value[0].raw as File)
data.append('name', formData.value.name) data.append('name', formData.value.name)
data.append('version', formData.value.version) data.append('version', formData.value.version)
data.append('type', formData.value.type[formData.value.type.length - 1]) data.append('type', formData.value.type)
data.append('description', formData.value.description) data.append('description', formData.value.description)
const res = await createFirmware(data) const res = await createFirmware(data)
loading.value = false loading.value = false

252
src/pages/ota/upgradeTask/components/create-task-dlg.vue

@ -11,39 +11,63 @@
<el-row> <el-row>
<FormItemInput label="任务名称" v-model="formData.name" require /> <FormItemInput label="任务名称" v-model="formData.name" require />
</el-row> </el-row>
<el-row> <el-row>
<span class="label">固件选择</span> <span class="label"> <span class="require">*</span>设备类别: </span>
<el-cascader <el-cascader
:props="cascaderFirmware" v-model="formData.type"
v-model="firmwareSelect" :options="categoryTreeData"
ref="firmwareCascaderRef" style="flex: 1"
:show-all-levels="false" :props="{
placeholder="请选择" checkStrictly: true,
value: 'id',
label: 'name',
emitPath: false,
}"
/> />
</el-row> </el-row>
<el-row v-if="isShowDeviceSelect"> <el-row v-if="typeof formData.type !== 'undefined'">
<!-- <span class="label">设备选择</span> <span class="label"> <span class="require">*</span>设备: </span>
<el-cascader <el-select
style="flex: 1" v-model="formData.deviceSns"
v-model="deviceSelect" multiple
:props="cascaderDevice"
@change="devChange"
ref="deviceCascaderRef"
:show-all-levels="false"
popper-class="task-device-select-cascader"
placeholder="请选择"
collapse-tags collapse-tags
style="flex: 1"
:max-collapse-tags="4" :max-collapse-tags="4"
collapse-tags-tooltip collapse-tags-tooltip
@expand-change="changeSourceType" placeholder="请选择设备"
/> --> @visible-change="loadDeviceList"
>
<el-option
v-for="item in deviceList"
:key="item.sn"
:label="item.sn"
:value="item.sn"
/>
</el-select>
</el-row>
<el-row v-if="typeof formData.type !== 'undefined'">
<span class="label"> <span class="require">*</span>固件选择: </span>
<el-select
v-model="formData.firmwareId"
placeholder="请选择固件"
style="flex: 1"
:disabled="false"
class="input"
@visible-change="loadFirmwareList"
>
<el-option
v-for="item in firmwareList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-row> </el-row>
<el-row> <el-row>
<span class="label">是否立即执行</span> <span class="label">是否立即执行</span>
<el-switch <el-switch v-model="formData.executeNow" />
v-model="formData.executeNow"
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
/>
</el-row> </el-row>
<el-row v-if="!formData.executeNow"> <el-row v-if="!formData.executeNow">
<span class="label">任务执行时间</span> <span class="label">任务执行时间</span>
@ -74,135 +98,32 @@ import EdfsDialog from '@/components/dashboard/Edfs-dialog.vue'
import FormItemInput from '@/components/dashboard/FormItemInput.vue' import FormItemInput from '@/components/dashboard/FormItemInput.vue'
import { isResError, useMessage } from '@/hooks/useMessage' import { isResError, useMessage } from '@/hooks/useMessage'
import EdfsNumberInput from '@/components/dashboard/Edfs-number-item-input.vue' import EdfsNumberInput from '@/components/dashboard/Edfs-number-item-input.vue'
import FormItemSelect from '@/components/dashboard/FormItemSelect.vue' import { getSimpleDeviceList } from '@/api/module/eam/device/index'
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 { getSimpleFirmwareList } from '@/api/module/eam/device/firmware'
import { isEmpty } from '@/utils/is' import { cloneDeep } from 'lodash'
import { clone, cloneDeep } from 'lodash'
import { createTask } from '@/api/module/eam/device/task' import { createTask } from '@/api/module/eam/device/task'
import { getCategoryTree, type ICategoryTree } from '@/api/module/eam/device/category'
import { useRoute } from 'vue-router'
const route = useRoute()
const message = useMessage() const message = useMessage()
interface Props { interface Props {
isShow: boolean isShow: boolean
} }
const emits = defineEmits(['on-save', 'on-close']) const emits = defineEmits(['on-save', 'on-close'])
const props = withDefaults(defineProps<Props>(), { withDefaults(defineProps<Props>(), {
isShow: false, 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 = { const form = {
name: '', name: undefined,
executeNow: false, // executeNow: false, //
executeTime: '', // executeTime: undefined, //
retryCount: 3, // retryCount: 3, //
retryInterval: 1000, // retryInterval: 1000, //
monitorTimeout: 1000, // monitorTimeout: 1000, //
firmwareId: '', // ID firmwareId: undefined, // ID
deviceSns: [], // SN type: undefined, //
deviceSns: [], //
} }
const formData = ref(cloneDeep(form)) const formData = ref(cloneDeep(form))
@ -211,14 +132,15 @@ function validate() {
message.error('请输入任务名称') message.error('请输入任务名称')
return true return true
} }
if (!formData.value.firmwareId) { if (!formData.value.type) {
message.error('请选择固件') message.error('请选择设备类别')
return true return true
} }
if (!formData.value.deviceSns.length) { if (!formData.value.firmwareId) {
message.error('请选择设备') message.error('请选择固件')
return true return true
} }
if (!formData.value.executeNow && !formData.value.executeTime) { if (!formData.value.executeNow && !formData.value.executeTime) {
message.error('请选择执行时间') message.error('请选择执行时间')
return true return true
@ -255,10 +177,49 @@ function onClone() {
function clearData() { function clearData() {
formData.value = cloneDeep(form) formData.value = cloneDeep(form)
firmwareSelect.value = []
cascaderTag.value = []
deviceSelect.value = []
} }
const categoryTreeData = ref<ICategoryTree[]>([])
async function loadDeviceTypeTree() {
const res = await getCategoryTree()
if (!isResError(res)) {
categoryTreeData.value = res.data
}
}
const firmwareList = ref<any[]>([])
async function loadFirmwareList(value: boolean) {
if (!value) return
const res = await getSimpleFirmwareList({ type: formData.value.type as any })
if (!isResError(res)) {
firmwareList.value = res.data
}
}
const deviceList = ref<any[]>([])
async function loadDeviceList(value: boolean) {
if (!value) return
const res = await getSimpleDeviceList({ categoryId: formData.value.type as any })
if (!isResError(res)) {
deviceList.value = res.data
}
}
onMounted(async () => {
await loadDeviceTypeTree()
if (route.query.categoryId) {
formData.value.type = Number(route.query.categoryId)
await loadFirmwareList(true)
await loadDeviceList(true)
}
if (route.query.deviceSn) {
formData.value.deviceSns = [route.query.deviceSn]
}
if (route.query.firmwareId) {
formData.value.firmwareId = Number(route.query.firmwareId)
}
})
</script> </script>
<style lang="scss"> <style lang="scss">
@ -277,9 +238,6 @@ function clearData() {
<style scoped lang="scss"> <style scoped lang="scss">
.create-task-dlg { .create-task-dlg {
.dlg-body {
max-height: 400px;
}
.el-row { .el-row {
height: 32px; height: 32px;
width: 74%; width: 74%;

9
src/pages/ota/upgradeTask/index.vue

@ -113,8 +113,9 @@ import createTaskDlg from './components/create-task-dlg.vue'
import detailsDrawer from './components/details-drawer.vue' import detailsDrawer from './components/details-drawer.vue'
import { isResError, useMessage } from '@/hooks/useMessage.js' import { isResError, useMessage } from '@/hooks/useMessage.js'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { useRoute} from 'vue-router'
import { getTaskList } from '@/api/module/eam/device/task' import { getTaskList } from '@/api/module/eam/device/task'
const route = useRoute()
const message = useMessage() const message = useMessage()
const createIcon = useIcon({ icon: 'gravity-ui:plus' }) const createIcon = useIcon({ icon: 'gravity-ui:plus' })
@ -174,10 +175,14 @@ async function onDetails(row: any) {
rowData.value = row rowData.value = row
isShowDetails.value = true isShowDetails.value = true
} }
const queryType = route.query.type
onMounted(async () => { onMounted(async () => {
await loadData() await loadData()
addListener(socketMsgListener) addListener(socketMsgListener)
if(queryType === 'create') {
addTask()
}
}) })
onBeforeUnmount(() => { onBeforeUnmount(() => {
@ -351,6 +356,8 @@ function updateTaskData() {
// test(item.type, item.stationId, item.data, item.time) // test(item.type, item.stationId, item.data, item.time)
// } // }
// }, 1000) // }, 1000)
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

3
src/pages/system/deviceField/components/CategoryDlg.vue

@ -20,6 +20,7 @@
checkStrictly: true, checkStrictly: true,
value: 'id', value: 'id',
label: 'name', label: 'name',
emitPath: false,
}" }"
clearable clearable
/> />
@ -115,7 +116,7 @@ function formatterParams(params: CategoryOV): CategoryOV {
let obj = {} as CategoryOV let obj = {} as CategoryOV
for (const key of [...Object.keys(createFrom), 'id'] as (keyof CategoryOV)[]) { for (const key of [...Object.keys(createFrom), 'id'] as (keyof CategoryOV)[]) {
if (params[key] !== undefined) { if (params[key] !== undefined) {
obj[key] = key === 'pid' ? params[key][params.pid.length - 1] : params[key] obj[key] = params[key]
} }
} }
return obj return obj

Loading…
Cancel
Save