Browse Source

feat: aibox下事件转发

lvkun 2 years ago
parent
commit
a19f56cb4e

+ 31 - 6
src/api/cvs/aibox.ts

@@ -23,6 +23,14 @@ export const dimensionAiBox = (data: Partial<CVS.AiBox.AiBox>) => {
   })
 }
 
+export const aiboxLevelUp = (params: {devId: string, aiId: string, version: string, file: any}) => {
+  return request<string>({
+    url: `/aiBox/updateModel/${params.devId}/${params.aiId}/${params.version}`,
+    method: 'POST',
+    data: params.file
+  })
+}
+
 export const getTaskByClientId = (clientId: string) => {
   return request<CVS.AiBox.Task[]>({
     url: `/aiBox/task/${clientId}`,
@@ -87,9 +95,26 @@ export const getAiBoxForward = () => {
   })
 }
 
-// export const addAiBoxForward = () => {
-//   return request<CVS.AiBox.Forward[]>({
-//     url: '/aiBox/event/forward',
-//     method: 'POST'
-//   })
-// }
+export const addAiBoxForward = (data: CVS.AiBox.Forward) => {
+  return request<string>({
+    url: '/aiBox/event/forward',
+    method: 'POST',
+    data
+  })
+}
+
+export const updateAiBoxForward = (data: CVS.AiBox.Forward) => {
+  return request<string>({
+    url: '/aiBox/event/forward',
+    method: 'PUT',
+    data
+  })
+}
+
+export const delAiBoxForward = (id: string, data) => {
+  return request<string>({
+    url: '/aiBox/event/forward/' + id,
+    method: 'DELETE',
+    data
+  })
+}

+ 24 - 2
src/components/FormPro/components/indext.tsx

@@ -29,6 +29,10 @@ export const SelectTsx = defineComponent({
     request: {
       type: Function,
       default: () => {}
+    },
+    keys: {
+      type: Object,
+      default: () => {}
     }
   },
   emits: ['update:modelValue'],
@@ -44,7 +48,25 @@ export const SelectTsx = defineComponent({
       value: any,
       key: string
     }[]) => {
-      list.value = r
+      const keysMap = new Map()
+
+      const optionsKeys = Object.keys(props.keys)
+      optionsKeys.forEach(key => keysMap.set(key, props.keys[key]))
+      console.log('r:', r)
+
+      if (optionsKeys.length !== 0) {
+        list.value = r.map(item => {
+          const _data = {}
+          Object.keys(item).forEach(key => {
+            _data[key] = [keysMap.get(key)]
+          })
+          return _data
+        }) as any
+
+        console.log('list.value:', list.value)
+      } else {
+        list.value = r
+      }
     })
 
     const onInput = (value: string) => context.emit('update:modelValue', value)
@@ -52,7 +74,7 @@ export const SelectTsx = defineComponent({
     return () => (
       <a-select value={props.modelValue} onChange={(value: string) => onInput(value)}>
        {
-        list.value.map(item => <a-select-option key={item.key} value={item.value}>{item.name}</a-select-option>)
+          list.value && list.value.map(item => <a-select-option key={item.key} value={item.value}>{item.name}</a-select-option>)
        }
       </a-select>
     )

+ 18 - 5
src/components/MicroComponents/index.tsx

@@ -97,6 +97,14 @@ export const SelectTsx = defineComponent({
     request: {
       type: Function,
       default: () => {}
+    },
+    keys: {
+      type: Object as PropType<{key: string, name: string, value: string}>,
+      default: () => {}
+    },
+    styles: {
+      type: Object,
+      default: () => {}
     }
   },
   emits: ['update:value'],
@@ -118,9 +126,9 @@ export const SelectTsx = defineComponent({
     const onInput = (value: string) => context.emit('update:value', value)
 
     return () => (
-      <a-select value={props.modelValue} allowClear onChange={(value: string) => onInput(value)}>
+      <a-select style={{ width: '170px', ...props.styles }} value={props.modelValue} allowClear onChange={(value: string) => onInput(value)}>
        {
-        list.value.map(item => <a-select-option key={item.key} value={item.value}>{item.name}</a-select-option>)
+        list.value.map(item => <a-select-option key={item[props.keys.key]} value={item[props.keys.value]}>{item[props.keys.name]}</a-select-option>)
        }
       </a-select>
     )
@@ -142,11 +150,16 @@ export const InputTsx = defineComponent({
     mode: {
       type: String as PropType<'normal' | 'edit'>,
       default: 'normal'
+    },
+    value: {
+      type: String,
+      required: true,
+      default: ''
     }
   },
   emits: ['update:value', 'submit'],
   setup (props, ctx) {
-    console.log('props.modelValue:', props.modelValue)
+    console.log('props.modelValue:', props.value)
 
     const editing = ref<boolean>(false)
 
@@ -162,7 +175,7 @@ export const InputTsx = defineComponent({
         {
 
           props.mode === 'normal'
-            ? <Input style={{ minWidth: '170px' }} placeholder={props.placeholder} onChange={(e) => onInput(e.target.value!)} />
+            ? <Input style={{ minWidth: '170px' }} value={props.value} placeholder={props.placeholder} onChange={(e) => onInput(e.target.value!)} />
             : <>
               <Space>
                 {
@@ -215,7 +228,7 @@ export const CopyTsx = defineComponent({
       <a-tooltip
         title='复制'
       >
-        <CopyTwoTone style="font-size: 20px;" onClick={onCopy}/>
+        <CopyTwoTone style="font-size: 18px;" onClick={onCopy}/>
       </a-tooltip>
     )
   }

+ 2 - 1
src/components/RealView/index.less

@@ -41,7 +41,8 @@
     background-color: #fff;
     position: absolute;
     right: 0;
-    bottom: 0;
+    bottom: 60px;
     padding-left: 18px;
+    z-index: 100;
   }
 }

+ 9 - 2
src/components/RealView/index.tsx

@@ -20,11 +20,15 @@ const RealView = defineComponent({
     footer: {
       type: Boolean,
       default: false
+    },
+    title: {
+      type: String,
+      default: ''
     }
   },
   emits: ['cancel', 'tabChang', 'ok'],
   setup (props, ctx) {
-    const { open, tabKey, tabsList, footer } = toRefs(props)
+    const { open, tabKey, tabsList, footer, title } = toRefs(props)
 
     const cancel = () => ctx.emit('cancel')
 
@@ -48,7 +52,10 @@ const RealView = defineComponent({
               <Row class='header' >
                 <div class="back-button" onClick={() => cancel()} >
                   <LeftOutlined style={{ fontSize: '18px', color: '#ccc' }} />
-                  <span style={{ fontSize: '18px' }} >返回</span>
+                  <a-space>
+                    <span style={{ fontSize: '18px' }} >返回</span>
+                    <span style={{ fontSize: '18px' }} > { title.value }</span>
+                  </a-space>
                 </div>
               </Row>
               <div class="tabs" >

+ 49 - 11
src/controller/cvs/aiboxController.ts

@@ -1,20 +1,34 @@
-import { dimensionAiBox, getAiBoxEvent, getAiBoxList, getAiBoxPage, getStream, getSys, getTaskByClientId, reboot, refreshStream, refreshSys, refreshTask } from '@/api/cvs/aibox'
+import { addAiBoxForward, aiboxLevelUp, delAiBoxForward, dimensionAiBox, getAiBoxEvent, getAiBoxForward, getAiBoxList, getAiBoxPage, getStream, getSys, getTaskByClientId, reboot, refreshStream, refreshSys, refreshTask, updateAiBoxForward } from '@/api/cvs/aibox'
+import { updateForward } from '@/api/iot/rule'
 import { message } from 'ant-design-vue'
 
 export class AiboxController {
   static eventType: {EventType: CVS.AiBox.eventType, EventName: string}[] = [
-    { EventType: 0, EventName: '人脸识别' },
-    { EventType: 1, EventName: '人流统计' },
-    { EventType: 2, EventName: '明烟明火' },
-    { EventType: 3, EventName: '抽烟打电话' },
-    { EventType: 4, EventName: '口罩检测' },
-    { EventType: 5, EventName: '安全帽检测' },
-    { EventType: 6, EventName: '越线监测' },
-    { EventType: 7, EventName: '区域围栏' },
-    { EventType: 8, EventName: '反光衣检测' },
-    { EventType: 9, EventName: '电动车检测' }
+    { EventType: '0', EventName: '人脸识别' },
+    { EventType: '1', EventName: '人流统计' },
+    { EventType: '2', EventName: '明烟明火' },
+    { EventType: '3', EventName: '抽烟打电话' },
+    { EventType: '4', EventName: '口罩检测' },
+    { EventType: '5', EventName: '安全帽检测' },
+    { EventType: '6', EventName: '越线监测' },
+    { EventType: '7', EventName: '区域围栏' },
+    { EventType: '8', EventName: '反光衣检测' },
+    { EventType: '9', EventName: '电动车检测' }
   ]
 
+  static eventTypeMap = new Map([
+    ['0', '人脸识别'],
+    ['1', '人流统计'],
+    ['2', '明烟明火'],
+    ['3', '抽烟打电话'],
+    ['4', '口罩检测'],
+    ['5', '安全帽检测'],
+    ['6', '越线监测'],
+    ['7', '区域围栏'],
+    ['8', '反光衣检测'],
+    ['9', '电动车检测']
+  ])
+
   static async page (params: COMMON.API.QueryParams & {name?: string, state: 'OFFLINE' | 'ONLINE'}) {
     return await getAiBoxPage(params)
   }
@@ -31,6 +45,11 @@ export class AiboxController {
     code === 200 ? message.success('修改成功') : message.error(msg)
   }
 
+  static async levelUp (params: {devId: string, aiId: string, version: string, file: any}) {
+    const { code, data } = await aiboxLevelUp(params)
+    code === 200 && data ? message.success('升级成功') : message.error('升级失败')
+  }
+
   static async taskById (clientId: string) {
     const { code, data } = await getTaskByClientId(clientId)
     if (code === 200) {
@@ -72,4 +91,23 @@ export class AiboxController {
   static async event (params: {devId: string, eventType: CVS.AiBox.eventType, start: string, end: string}) {
     return await getAiBoxEvent(params)
   }
+
+  static async forward () {
+    return await getAiBoxForward()
+  }
+
+  static async addForward (data: CVS.AiBox.Forward) {
+    const { code, msg } = await addAiBoxForward(data)
+    code === 200 ? message.success('新增成功') : message.error(msg)
+  }
+
+  static async updateForward (data: CVS.AiBox.Forward) {
+    const { code, msg } = await updateAiBoxForward(data)
+    code === 200 ? message.success('修改成功') : message.error(msg)
+  }
+
+  static async delForward (id: string, _data: CVS.AiBox.Forward) {
+    const { code, msg, data } = await delAiBoxForward(id, _data)
+    code === 200 && data ? message.success('删除成功') : message.error('删除失败')
+  }
 }

+ 140 - 0
src/pages/cvs/edge/forward.vue

@@ -1,8 +1,148 @@
 <template>
 <a-card title="事件转发" >
+  <template #extra >
+    <a-tooltip>
+      <template #title v-if="forwardList.length === 2" >最多拥有两个转发中的事件</template>
+      <a-button type="primary" @click="openRealViewDialog('add')" :disabled="forwardList.length === 2" >新增</a-button>
+  </a-tooltip>
+  </template>
 </a-card>
+
+<a-spin :spinning="spinning" >
+  <a-card style="margin-top: 20px;" :title="'转发' + (index + 1)" v-for="(item, index) in forwardList" :key="item.id">
+    <template #extra >
+      <a-space>
+        <a-popconfirm
+          title="确定要删除这个转发事件吗"
+          ok-text="Yes"
+          cancel-text="No"
+          @confirm="delforawrd(item)"
+        >
+        <a-button >删除</a-button>
+        </a-popconfirm>
+
+        <a-button type="primary" @click="openRealViewDialog('update', item)">修改</a-button>
+      </a-space>
+    </template>
+    <a-descriptions :title="'id: ' + item.id">
+      <a-descriptions-item label="创建时间">{{dayjs(item.createAt).format('YYYY/MM/DD HH:MM:ss')}}</a-descriptions-item>
+      <a-descriptions-item label="事件类型">{{item.forwardType}}</a-descriptions-item>
+      <a-descriptions-item label="Live">{{item.forwardConfig.defaultTimeout}}</a-descriptions-item>
+      <a-descriptions-item label="端点地址">{{item.forwardConfig.endpointUrl}}</a-descriptions-item>
+      <a-descriptions-item label="请求类型">{{item.forwardConfig.requestMethod}}</a-descriptions-item>
+      <a-descriptions-item label="请求头">{{item.forwardConfig.requestHeaders ? item.forwardConfig.requestHeaders : '-' }}</a-descriptions-item>
+    </a-descriptions>
+  </a-card>
+</a-spin>
+
+<RealView
+  :open="visible"
+  @cancel="visible = false"
+  :title=" opraState === 'add' ? '新增转发' : '修改转发'"
+  tab-key="base"
+  :tabs-list="[{ key: 'base', tab: '基础信息' }]"
+  footer
+  @ok="ok"
+>
+    <a-form  style="width: 100%;" :labelCol="{span: 3}" :wrapperCol="{span: 14}" >
+      <a-card title="基本配置" >
+        <a-form-item label="转发类型" v-bind="validateInfos.deviceName"  >
+          <a-radio-group v-model:value="forwardState.forwardType" button-style="solid">
+            <a-radio-button value="HTTP">HTTP</a-radio-button>
+            <a-radio-button value="KAFKA">KAFKA</a-radio-button>
+          </a-radio-group>
+        </a-form-item>
+      </a-card>
+      <a-card title="详细配置"  style="margin-top: 20px;">
+        <a-form-item label="转发类型" v-bind="validateInfos.deviceName"  >
+          <a-radio-group v-model:value="forwardState.forwardConfig.forwardType" button-style="solid">
+            <a-radio-button value="HTTP">HTTP</a-radio-button>
+            <a-radio-button value="KAFKA">KAFKA</a-radio-button>
+          </a-radio-group>
+        </a-form-item>
+        <a-form-item label="端点地址" v-bind="validateInfos.endpointUrl"  >
+          <InputTsx allowClear placeholder="请输入端点地址" v-model:value="forwardState.forwardConfig.endpointUrl" />
+        </a-form-item>
+        <a-form-item label="端点地址"  >
+          <a-radio-group v-model:value="forwardState.forwardConfig.requestMethod" button-style="solid">
+            <a-radio-button value="GET">GET</a-radio-button>
+            <a-radio-button value="POST">POST</a-radio-button>
+          </a-radio-group>
+        </a-form-item>
+        <a-form-item label="默认时间"   >
+          <a-input-number id="inputNumber" v-model:value="forwardState.forwardConfig.defaultTimeout" :min="1" />
+        </a-form-item>
+      </a-card>
+    </a-form>
+
+</RealView>
 </template>
+
 <script lang='ts' setup >
+import { RealView } from '@/components/RealView/index'
+import { AiboxController } from '@/controller'
+import { onMounted, ref, reactive } from 'vue'
+import { Form } from 'ant-design-vue'
+import { InputTsx } from '@/components/MicroComponents'
+import dayjs from 'dayjs'
+
+const useForm = Form.useForm
+
+const forwardList = ref<CVS.AiBox.Forward[]>([])
+
+const visible = ref<boolean>(false)
+
+const spinning = ref(false)
+
+const opraState = ref<'add' | 'update'>('add')
+
+const forwardState = reactive({
+  forwardType: 'HTTP',
+  forwardConfig: {
+    forwardType: 'HTTP', // HTTP 和KAFKA
+    endpointUrl: '',
+    requestMethod: 'GET',
+    requestHeaders: {},
+    defaultTimeout: 10
+  }
+})
+
+const { resetFields, validate, validateInfos } = useForm(forwardState, {
+  endpointUrl: [{ required: true, message: '请填写端点地址' }]
+})
+
+const delforawrd = async (record: CVS.AiBox.Forward) => {
+  await AiboxController.delForward(record.id as unknown as string, record)
+  getAiBoxForward()
+}
+
+const getAiBoxForward = async () => {
+  spinning.value = true
+  const { data } = await AiboxController.forward()
+  spinning.value = false
+  forwardList.value = data
+}
+
+const openRealViewDialog = (type: 'add' | 'update', record = {}) => {
+  resetFields(record)
+  console.log('record:', record)
+
+  opraState.value = type
+  visible.value = true
+}
+
+const ok = () => {
+  validate().then(async () => {
+    opraState.value === 'add' ? await AiboxController.addForward(forwardState as any) : await AiboxController.updateForward(forwardState as any)
+    visible.value = false
+    getAiBoxForward()
+  }).catch(e => e)
+}
+
+onMounted(() => {
+  getAiBoxForward()
+})
+
 </script>
 <style lang='less' scoped >
 </style>

+ 85 - 4
src/pages/cvs/edge/list.vue

@@ -8,7 +8,10 @@
   >
     <template #render="{column, record}" >
       <template v-if="column.key === 'clientId'" >
-        <a @click="getSys(record)">{{record.clientId}}</a>
+        <a-space>
+          <a @click="getSys(record)">{{record.clientId}}</a>
+          <CopyTsx :text="record.clientId" />
+        </a-space>
       </template>
       <template v-if="column.key === 'state'" >
         <div style="display: flex;align-items: center;" >
@@ -16,8 +19,11 @@
           <div>{{record.state==='ONLINE'?'在线':'离线'}}</div>
         </div>
       </template>
+      <template  v-if="column.key === 'ts'" >
+        {{ record.ts? dayjs(record.ts).format('YYYY/MM/DD HH:mm:ss') : '-' }}
+      </template>
       <template  v-if="column.key === 'createAt'" >
-        {{ dayjs(record.createAt).format('YYYY/MM/DD HH:mm:ss') }}
+        {{ record.createAt ? dayjs(record.createAt).format('YYYY/MM/DD HH:mm:ss') : '-'}}
       </template>
       <template  v-if="column.key === 'updateAt'" >
         {{ record.updateAt ? dayjs(record.updateAt).format('YYYY/MM/DD HH:mm:ss') : '-' }}
@@ -28,6 +34,7 @@
           <a @click="pushTask(record)">任务</a>
           <a @click="pushVideo(record)">视频</a>
           <a @click="reboot(record)">重启</a>
+          <a @click="openlevelUpModal(record)">算子升级</a>
         </a-space>
 
       </template>
@@ -51,13 +58,46 @@
     <a-form-item label="设备状态" >{{sys?.devState}}</a-form-item>
   </a-form>
   </modal-pro>
+
+  <modal-pro
+    style="width: 700px;"
+    label="算子升级"
+    :open="levelUpVisble"
+    @cancel="levelUpVisble = false"
+    @ok="levelUpOk"
+  >
+    <a-form  style="width: 100%;" :labelCol="{span: 3}" :wrapperCol="{span: 14}" >
+        <a-form-item label="算法" v-bind="validateInfos.aiId"  >
+          <SelectTsx
+            v-model:value="aiboxState.aiId"
+            :request="async () => await  OperatorController.list()"
+            :keys="{
+              name: 'aiName',
+              value: 'aiId',
+              key: 'aiId'
+            }"
+          />
+        </a-form-item>
+
+        <a-form-item label="版本号" v-bind="validateInfos.version"  >
+          <InputTsx  placeholder="请填写版本号" v-model:value="aiboxState.version" />
+        </a-form-item>
+
+        <a-form-item label="压缩包" v-bind="validateInfos.file"  >
+          <UploadPro action="/cvs/file/upload" accept=".zip,.tar,.gz,.tgz" @done="uploadDone" />
+        </a-form-item>
+    </a-form>
+  </modal-pro>
 </a-card>
 </template>
 <script lang='ts' setup >
-import { AiboxController, SpaceController } from '@/controller'
+import { AiboxController, OperatorController, SpaceController } from '@/controller'
 import dayjs from 'dayjs'
-import { ref } from 'vue'
+import { onMounted, reactive, ref } from 'vue'
 import { useRouter } from 'vue-router'
+import { Form } from 'ant-design-vue'
+import { CopyTsx, InputTsx, SelectTsx } from '@/components/MicroComponents'
+import UploadPro from '@/components/UploadPro'
 
 const router = useRouter()
 
@@ -72,11 +112,21 @@ const columns = [
     dataIndex: 'name',
     key: 'name'
   },
+  {
+    title: '协议',
+    dataIndex: 'protocol',
+    key: 'protocol'
+  },
   {
     title: '状态',
     dataIndex: 'state',
     key: 'state'
   },
+  {
+    title: '连接时间',
+    dataIndex: 'ts',
+    key: 'ts'
+  },
   {
     title: '创建时间',
     dataIndex: 'createAt',
@@ -98,6 +148,26 @@ const sys = ref<Partial<CVS.AiBox.Sys> & {clientId: string}>()
 
 const sysVisible = ref<boolean>(false)
 
+const levelUpVisble = ref(false)
+const aiboxState = reactive({
+  devId: '11',
+  aiId: '',
+  version: '',
+  file: ''
+})
+
+const useForm = Form.useForm
+
+const { resetFields, validate, validateInfos } = useForm(aiboxState, {
+  file: [{ required: true, message: '请上传文件' }],
+  version: [{ required: true, message: '请填写版本号' }],
+  aiId: [{ required: true, message: '请选择升级算法' }]
+})
+
+const uploadDone = (url) => {
+  aiboxState.file = url
+}
+
 const getSys = async (record: CVS.AiBox.AiBox) => {
   sys.value = Object.assign({}, { ...await AiboxController.sys(record.clientId), clientId: record.clientId })
   sysVisible.value = true
@@ -115,6 +185,17 @@ const pushVideo = (record: CVS.AiBox.AiBox) => {
   router.push({ path: '/cvs/edge/video', query: { clientId: record.clientId } })
 }
 
+const levelUpOk = async () => {
+  AiboxController.levelUp({ ...aiboxState })
+}
+
+const openlevelUpModal = (record: CVS.AiBox.AiBox) => {
+  console.log(record)
+
+  resetFields(record)
+  levelUpVisble.value = true
+}
+
 </script>
 <style lang='less' scoped >
 </style>

+ 49 - 8
src/pages/cvs/edge/manage.vue

@@ -3,17 +3,34 @@
 
   <table-pro
     :service="AiboxController.event"
+    :serviceParams="serviceParams"
     :columns="columns"
+    ref="tableProDom"
   >
   <template #search >
-    <SelectTsx
-      :request="async () => (await SpaceController.devicePage({page: 1, pageSize: 10, deviceName: ''})).data"
-      :keys="{
-        name: 'deviceName',
-        value: 'deviceId',
-        key: 'deviceId'
-      }"
-    />
+    <a-space>
+      <SelectTsx
+        v-model:value="serviceParams.devId"
+        :request="async () => (await SpaceController.devicePage({page: 1, pageSize: 10, deviceName: ''})).data"
+        :keys="{
+          name: 'deviceName',
+          value: 'deviceId',
+          key: 'deviceId'
+        }"
+      />
+      <SelectTsx
+        v-model:value="serviceParams.eventType"
+        :request="async () => await AiboxController.eventType"
+        :keys="{
+          name: 'EventName',
+          value: 'EventType',
+          key: 'EventType'
+        }"
+      />
+      <a-range-picker v-model:value="times" format="YYYY/MM/DD'" />
+      <a-button type="primary" @click="search" >搜索</a-button>
+    </a-space>
+
   </template>
     <template #render="{column, record}" >
       <template v-if="column.key === 'EventType'" >
@@ -33,6 +50,7 @@
 import { AiboxController, SpaceController } from '@/controller'
 import { SelectTsx } from '@/components/MicroComponents'
 import dayjs from 'dayjs'
+import { ref, watch } from 'vue'
 
 const columns = [
   {
@@ -62,6 +80,29 @@ const columns = [
   }
 ]
 
+const tableProDom = ref()
+
+const times = ref()
+
+const serviceParams = ref({
+  devId: '',
+  eventType: '',
+  start: '',
+  end: ''
+})
+
+watch(
+  () => times.value,
+  () => {
+    serviceParams.value.start = new Date(times.value[0]).getTime() as unknown as string
+    serviceParams.value.end = new Date(times.value[1]).getTime() as unknown as string
+  }
+)
+
+const search = () => {
+  tableProDom.value.reload()
+}
+
 </script>
 <style lang='less' scoped >
 </style>

+ 4 - 4
src/router/index.ts

@@ -407,16 +407,16 @@ const cvs = {
           component: () => import('@/pages/cvs/edge/video.vue')
         },
         {
-          path: '/cvs/ai/manage',
+          path: '/cvs/edge/manage',
           name: 'AI事件管理',
           icon: '',
-          component: () => import('@/pages/cvs/ai/manage.vue')
+          component: () => import('@/pages/cvs/edge/manage.vue')
         },
         {
-          path: '/cvs/ai/forward',
+          path: '/cvs/edge/forward',
           name: 'AI事件转发',
           icon: '',
-          component: () => import('@/pages/cvs/ai/forward.vue')
+          component: () => import('@/pages/cvs/edge/forward.vue')
         }
       ]
     },

+ 5 - 7
src/type/cvs.d.ts

@@ -175,7 +175,7 @@ declare namespace CVS {
       'devID': string
     }
 
-    type eventType = 0 | 1 | 2 | 3 | 4 | 5 |6 |7 |8 | 9
+    type eventType = '0' | '1' | '2' | '3' | '4' | '5' |'6' |'7' |'8' | '9'
 
     interface Event {
       'saveTs': number,
@@ -196,17 +196,15 @@ declare namespace CVS {
     }
 
     interface Forward {
-      'createAt': number,
-      'updateAt': null,
-      'id': number,
+      'createAt'?: number,
+      'updateAt'?: null,
+      'id'?: number,
       'forwardType': 'HTTP' | 'KAFKA', // 转发类型 HTTP KAFKA
       'forwardConfig': { // 转发配置
         'forwardType': string,
         'endpointUrl': null,
         'requestMethod': string,
-        'requestHeaders': {
-          'Accept': string
-        },
+        'requestHeaders': Record<string, string>,
         'defaultTimeout': number
       }
     }