소스 검색

feat: 转发规则

lvkun 3 년 전
부모
커밋
24e03b3ebe

+ 145 - 0
src/api/iot/rule.ts

@@ -0,0 +1,145 @@
+import request from '@/service/request'
+
+/**
+ * 此函数根据给定的查询参数检索转发规则列表。
+ * @param params - `params` 参数是一个 `IOT.API.RULE.QueryParams` 类型的对象,它包含 API
+ * 请求的查询参数以检索转发规则列表。这些参数可能包括页码、页面大小、排序标准和过滤标准等内容。
+ * @returns `getForwardRuleList` 函数返回一个解析为 `IOT.API.RULE.Rule` 对象数组的 Promise。通过使用指定 URL、HTTP 方法和 API
+ * 请求的查询参数的对象调用“request”函数来返回 Promise。
+ */
+export const getForwardRulePage = (params: IOT.API.RULE.ForwardRuleQueryParams) => {
+  return request<IOT.API.RULE.ForwardRule[]>({
+    url: '/forwardRule/page',
+    method: 'GET',
+    params
+  })
+}
+
+/**
+ * 此函数发送一个 POST 请求以添加具有给定数据的转发规则。
+ * @param data -
+ * 参数“data”是一个类型为“IOT.API.RULE.ForwardRuleQueryParams”的对象,其中包含创建转发规则所需的数据。此数据可能包括规则的源地址和目标地址、端口和协议等信息。
+ * @returns `addForwardRule` 函数返回一个解析为字符串的 Promise。
+ */
+export const addForwardRule = (data: IOT.API.RULE.ForwardRuleBody) => {
+  return request<string>({
+    url: '/forwardRule',
+    method: 'POST',
+    data
+  })
+}
+
+/**
+ * 此函数使用 GET 请求通过其 ID 检索转发规则。
+ * @param {string} id - `id` 参数是一个字符串,表示转发规则的唯一标识符。此函数使用此标识符发出 GET 请求以检索具有指定“id”的转发规则。
+ * @returns 正在返回一个名为 getForwardById 的函数。此函数采用字符串参数“id”,并使用“request”函数向“/forwardRule/”端点发出 GET 请求。
+ * `request` 函数返回解析为字符串的 Promise。
+ */
+export const getForwardById = (id: string) => {
+  return request<IOT.API.RULE.ForwardRule>({
+    url: `/forwardRule/${id}`,
+    method: 'GET',
+    id
+  })
+}
+
+/**
+ * 此函数使用 PUT 请求更新转发规则。
+ * @param data - `data` 参数是 `IOT.API.RULE.ForwardRuleQueryParams` 类型的对象,其中包含更新转发规则所需的信息。此对象可能包含规则
+ * ID、源地址和目标地址以及转发规则的任何其他相关配置选项等属性
+ * @returns `updateForward` 函数返回一个解析为字符串的 Promise。
+ */
+export const updateForward = (data: IOT.API.RULE.ForwardRuleQueryParams) => {
+  return request<string>({
+    url: '/forwardRule/',
+    method: 'PUT',
+    data
+  })
+}
+
+/**
+ * 函数 delForward 发送删除请求以删除具有指定 ID 的转发规则。
+ * @param {string} id - `id`参数是一个字符串,表示需要删除的转发规则的唯一标识。
+ * @returns `delForward` 函数返回一个解析为字符串的 Promise。该字符串表示在向“/forwardRule/”端点发送 DELETE 请求后服务器的响应。
+ */
+export const delForward = (id: string) => {
+  return request<string>({
+    url: `/forwardRule/${id}`,
+    method: 'DELETE'
+  })
+}
+
+/**
+ * 此函数发送 GET 请求以根据提供的状态参数检索转发规则的计数。
+ * @param {boolean} status - `status` 参数是一个布尔值,用作过滤器以检索活动或非活动转发规则的计数。如果 `status` 为
+ * `true`,函数将返回活跃转发规则的计数,如果 `status` 为 `false`,则返回
+ * @returns 函数 getForwardCount 返回解析为数字的
+ * Promise。该数字表示具有指定状态的转发规则的计数。通过以指定状态作为参数向“/forwardRule/count”端点发出 GET 请求来获取计数。
+ */
+export const getForwardCount = (status: boolean) => {
+  return request<number>({
+    url: '/forwardRule/count',
+    method: 'GET',
+    params: { status }
+  })
+}
+
+/**
+ * 此函数使用 PUT 请求更新转发规则的状态。
+ * @param params - `params` 对象包含两个属性:
+ * @returns 函数 updateForwardStatus 返回一个解析为数字的 Promise。
+ */
+export const updateForwardStatus = (params: {id: string, status: boolean}) => {
+  return request<number>({
+    url: '/forwardRule/status',
+    method: 'PUT',
+    params
+  })
+}
+
+export const addLink = (data: IOT.API.RULE.LinkRuleBody) => {
+  return request<IOT.API.RULE.LinkRule[]>({
+    url: '/linkRule',
+    method: 'POST',
+    data
+  })
+}
+
+export const getLinkPage = (params: {page: number, pageSize: number, ruleLabel?: string}) => {
+  return request<IOT.API.RULE.LinkRule[]>({
+    url: '/linkRule',
+    method: 'GET',
+    params
+  })
+}
+
+export const getLinkCount = (params: {status: boolean}) => {
+  return request<Number>({
+    url: '/linkRule/count',
+    method: 'GET',
+    params
+  })
+}
+
+export const updateLinkStatus = (data: {status: boolean, id: string}) => {
+  return request<Number>({
+    url: '/linkRule/status',
+    method: 'PUT',
+    data
+  })
+}
+
+export const delLink = (id: string) => {
+  return request<Number>({
+    url: `/linkRule/${id}`,
+    method: 'DELETE'
+  })
+}
+
+export const updateLink = (data: IOT.API.RULE.LinkRuleBody) => {
+  return request<Number>({
+    url: '/linkRule',
+    method: 'PUT',
+    data
+  })
+}

+ 18 - 0
src/components/FormPro/components/indext.tsx

@@ -44,6 +44,8 @@ export const SelectTsx = defineComponent({
       value: any,
       key: string
     }[]) => {
+      console.log('select-tsx:', r)
+
       list.value = r
     })
 
@@ -58,3 +60,19 @@ export const SelectTsx = defineComponent({
     )
   }
 })
+
+export const TextareaTsx = defineComponent({
+  name: 'textarea-tsx',
+  props: {
+    modelValue: {
+      type: Object,
+      required: true,
+      default: () => ({})
+    }
+  },
+  emits: ['update:modelValue'],
+  setup (props, context) {
+    const onInput = (value: string) => context.emit('update:modelValue', value)
+    return () => <a-textarea value={props.modelValue} allow-clear onChange={(e: any) => onInput(e.target.value)}/>
+  }
+})

+ 27 - 12
src/components/FormPro/index.vue

@@ -1,7 +1,6 @@
 <template>
   <a-form
-    :labelCol="{span: 4}"
-    :wrapperCol="{span: 14}"
+    v-bind="formItemLayout"
     :layout="props.layout"
     autocomp
     lete="off"
@@ -12,23 +11,24 @@
       :label="item.label"
       v-bind="validateInfos[item.key]"
     >
-      <input-tsx v-if="item.type === 'input'"  v-model="modelRef[item.key]" />
-      <select-tsx  v-else-if="item.type === 'select'"  :request="item.request" v-model="modelRef[item.key]" :on-change="(e) => onChange(e, item.key)"  />
+      <input-tsx v-if="item.type === 'input'" :style="{width: props.itemWidth}"  v-model="modelRef[item.key]" />
+      <select-tsx  v-else-if="item.type === 'select'" :style="{width: props.itemWidth}" :request="item.request" v-model="modelRef[item.key]" :on-change="(e) => onChange(e, item.key)"  />
+      <textarea-tsx  v-else-if="item.type === 'textarea'"  :style="{width: props.itemWidth}" v-model="modelRef[item.key]"  />
     </a-form-item>
     <!-- <a-form-item>
       <slot name="reset" > <a-button @click="resetForm">重置</a-button></slot>
-    </a-form-item>
-    <a-form-item>
-      <slot name="search" > <a-button type="primary">搜索</a-button></slot>
     </a-form-item> -->
+    <a-form-item>
+      <slot name="search" > <a-button type="primary" @click="search">搜索</a-button></slot>
+    </a-form-item>
   </a-form>
 
 </template>
 
 <script lang='ts' setup >
-import { onMounted, reactive, toRaw } from 'vue'
+import { computed, onMounted, reactive, toRaw } from 'vue'
 import { Form } from 'ant-design-vue'
-import { InputTsx, SelectTsx } from './components/indext'
+import { InputTsx, SelectTsx, TextareaTsx } from './components/indext'
 
 /**
  * 将submit的提交抛出去
@@ -57,10 +57,11 @@ export interface ColumnsProps {
 }
 
 export interface FormProProps {
-  reset: boolean // 是否开启一键reset表单
-  search: boolean // 是否开启搜索功能
+  reset?: boolean // 是否开启一键reset表单
+  search?: boolean // 是否开启搜索功能
   validate: boolean // 是否开启验证功能
-  layout: 'horizontal' | 'vertical' | 'inline', // 布局方式 默认横向布局
+  layout?: 'horizontal' | 'vertical' | 'inline', // 布局方式 默认横向布局
+  itemWidth: string // 每个表单控件的长度
   formProps?: FormItemProps[] // 表单props
   columnsProps?: ColumnsProps[] // 与table表格一起传入的时候, 便于从table表格中筛选
   [key: string]: any
@@ -73,6 +74,15 @@ enum ComponentTypeEnum {
 
 const componentTypes: COMMON.COMPONENTS.ComType[] = ['input', 'select', 'datepick']
 
+const formItemLayout = computed(() => {
+  return props.layout === 'horizontal'
+    ? {
+        labelCol: { span: 4 },
+        wrapperCol: { span: 14 }
+      }
+    : {}
+})
+
 const getLablePrefix = (key: COMMON.COMPONENTS.ComType) => {
   switch (key) {
     case 'input':
@@ -130,6 +140,11 @@ const onChange = (record: any, key: string) => {
 
 const { resetFields, validate, validateInfos } = useForm(modelRef, rulesRef)
 
+const search = async () => {
+  const r = await onSubmit()
+  emit('search', r)
+}
+
 const onSubmit = () => {
   return new Promise((resolve, reject) => {
     validate()

+ 1 - 0
src/controller/index.ts

@@ -5,3 +5,4 @@ export { ModelAttrController } from './iot/modelAttr'
 export { ModelCmdController } from './iot/modelCmd'
 export { EventController } from './iot/event'
 export { DeviceContriller } from './iot/device'
+export { RuleController } from './iot/rule'

+ 42 - 0
src/controller/iot/rule.ts

@@ -0,0 +1,42 @@
+import { addForwardRule, delForward, getForwardRulePage, updateForwardStatus } from '@/api/iot/rule'
+import { SubjectEventEnum, SubjectResourceEnum } from '@/enum/common'
+import { message } from 'ant-design-vue'
+
+export class RuleController {
+  static SubjectResourceMap = new Map([
+    [SubjectResourceEnum.DEVICE, { name: '设备', key: SubjectResourceEnum.DEVICE }],
+    [SubjectResourceEnum.DEVICE_ATTRIBUTE, { name: '设备属性', key: SubjectResourceEnum.DEVICE_ATTRIBUTE }],
+    [SubjectResourceEnum.DEVICE_STATUS, { name: '设备状态', key: SubjectResourceEnum.DEVICE_STATUS }],
+    [SubjectResourceEnum.MODEL, { name: '模型', key: SubjectResourceEnum.MODEL }]
+  ])
+
+  static SubjectEventMap = new Map([
+    [SubjectEventEnum.DEVICE_CREATE, { name: '设备创建', key: SubjectEventEnum.DEVICE_CREATE }],
+    [SubjectEventEnum.DEVICE_DELETE, { name: '设备删除', key: SubjectEventEnum.DEVICE_DELETE }],
+    [SubjectEventEnum.DEVICE_ATTRIBUTE_REPORT, { name: '设备属性上报', key: SubjectEventEnum.DEVICE_ATTRIBUTE_REPORT }],
+    [SubjectEventEnum.DEVICE_STATUS_UPDATE, { name: '设备状态变更', key: SubjectEventEnum.DEVICE_STATUS_UPDATE }],
+    [SubjectEventEnum.MODEL_CREATE, { name: '模型创建', key: SubjectEventEnum.MODEL_CREATE }],
+    [SubjectEventEnum.MODEL_DELETE, { name: '模型删除', key: SubjectEventEnum.MODEL_DELETE }]
+  ])
+
+  /** 转发规则 分页获取转发规则 */
+  static async pageForward (params: IOT.API.RULE.ForwardRuleQueryParams) {
+    return await getForwardRulePage(params)
+  }
+
+  /** 转发规则 新增 */
+  static async postForward (data: IOT.API.RULE.ForwardRuleBody) {
+    await addForwardRule(data)
+    message.success('新增转发规则成功')
+  }
+
+  static async delForward (id: string) {
+    await delForward(id)
+    message.success('删除成功')
+  }
+
+  static async updateForwardStatus (params: { id: string, status: boolean}) {
+    await updateForwardStatus(params)
+    params.status ? message.success('规则已启动') : message.success('规则已停止')
+  }
+}

+ 16 - 0
src/enum/common.ts

@@ -36,3 +36,19 @@ export enum DeviceMsgEnum {
   'TIMEOUT' = 'TIMEOUT', // 超时
   'FAILED' = 'FAILED', // 失败
 }
+
+export enum SubjectResourceEnum {
+  'DEVICE' = 'DEVICE',
+  'DEVICE_ATTRIBUTE' = 'DEVICE_ATTRIBUTE',
+  'DEVICE_STATUS' = 'DEVICE_STATUS',
+  'MODEL' = 'MODEL'
+}
+
+export enum SubjectEventEnum {
+  'DEVICE_CREATE' = 'DEVICE_CREATE',
+  'DEVICE_DELETE' = 'DEVICE_DELETE',
+  'DEVICE_ATTRIBUTE_REPORT' = 'DEVICE_ATTRIBUTE_REPORT',
+  'DEVICE_STATUS_UPDATE' = 'DEVICE_STATUS_UPDATE',
+  'MODEL_CREATE' = 'MODEL_CREATE',
+  'MODEL_DELETE' = 'MODEL_DELETE'
+}

+ 4 - 4
src/pages/Iot/device/components/subDevice.vue

@@ -67,8 +67,8 @@
     @close="state.visible = false"
     @ok="ok"
   >
-      <form-proo
-        ref="formPro"
+      <form-pro
+        ref="formProo"
         validate
         :columnsProps="columns"
       />
@@ -87,7 +87,7 @@ const route = useRoute()
 const router = useRouter()
 const emit = defineEmits(['goDetail'])
 
-const formPro = ref('')
+const formProo = ref('')
 
 const deviceId = route.query.id as string
 
@@ -176,7 +176,7 @@ const subDeviceState = reactive({
 })
 
 const ok = async () => {
-  const submitState = await formPro.value.onSubmit()
+  const submitState = await formProo.value.onSubmit()
   console.log('submitState:', submitState)
   DeviceContriller.postSub({ ...submitState, gatewayId: deviceId })
   state.visible = false

+ 11 - 6
src/pages/Iot/device/group.vue

@@ -112,7 +112,7 @@
         <a-table
           :rowKey="record => record.id"
           :columns="groupDeviceColumns"
-          :loading='state.loading'
+          :loading='state.tableLoading'
           :data-source="state.groupDeviceDataSource"
           :row-selection="{
             selectedRowKeys: state.selectedRowKeys,
@@ -173,9 +173,9 @@
     <a-col>
       <a-table
           :rowKey="record => record.id"
-          style="margin-top: 10px;"
-          :loading="state.loading"
-          :columns="columns"
+          style="margin-top: 10px;width: 688px;"
+          :loading="state.tableLoading"
+          :columns="groupDeviceColumns"
           :data-source="state.groupDateSource"
           :row-selection="{
             selectedRowKeys: state.selectedRowKeys,
@@ -385,6 +385,7 @@ const state = reactive<{
   groupDeviceDataSource: IOT.API.DEVICE.Device[]
   queryParams: any,
   loading: boolean,
+  tableLoading: boolean
   drawerVisible: boolean
   selectedRowKeys: string[],
   groupModalVisible: boolean,
@@ -399,6 +400,7 @@ const state = reactive<{
   treeActiveKey: '',
   selectTree: {},
   loading: false,
+  tableLoading: false,
   groupModalVisible: false,
 
   drawerVisible: false,
@@ -427,7 +429,7 @@ const { resetFields, validate, validateInfos } = useForm(groupState, reactive({
 const delBind = async (ids: []) => {
   const params = (ids.length ? ids : state.selectedRowKeys).map(item => {
     return {
-      deviceGroupId: state.treeActiveKey,
+      deviceGroupId: state.treeActiveKey[0],
       deviceId: item
     }
   })
@@ -440,7 +442,7 @@ const bindDevice = async () => {
   const params = state.selectedRowKeys.map(item => {
     return {
       deviceId: item,
-      deviceGroupId: state.treeActiveKey
+      deviceGroupId: state.treeActiveKey[0]
     }
   })
   await DeviceContriller.postGroupBindDevice(params)
@@ -492,6 +494,7 @@ const changeTreeActiveKey = (id: string, e?: TouchEvent) => {
   e && e.stopPropagation && e.stopPropagation()
   state.treeActiveKey = id
   console.log(state.treeActiveKey)
+  getDeviceByGroup()
 }
 
 const addDevicegroup = (e: TouchEvent) => {
@@ -500,11 +503,13 @@ const addDevicegroup = (e: TouchEvent) => {
 }
 
 const getDeviceByGroup = async () => {
+  state.tableLoading = true
   const { data, sum } = await DeviceContriller.getDeviceByGroup({
     page: 1,
     pageSize: 200,
     deviceGroupId: state.treeActiveKey
   })
+  state.tableLoading = false
   state.groupDeviceDataSource = data
 }
 

+ 314 - 0
src/pages/Iot/rule/forwardRule.vue

@@ -0,0 +1,314 @@
+<template>
+<a-card>
+  <a-row justify="space-between" >
+    <a-col :span="18" >
+      <form-pro
+        search
+        :formProps="formPropsSearch"
+        layout="inline"
+        itemWidth="170px"
+        @search="search"
+      >
+
+      </form-pro>
+    </a-col>
+    <a-col>
+      <a-button type="primary" @click="state.visible = true" >创建规则</a-button>
+    </a-col>
+  </a-row>
+
+  <a-table
+    style="margin-top: 20px;"
+    :columns="columns"
+    :data-source="state.dataSource"
+    :loading="state.loading"
+    :pagenation="{}"
+  >
+    <template #bodyCell="{column, record}" >
+      <template v-if="column.key === 'subjectResource'" >
+        {{RuleController.SubjectResourceMap.get(record.subjectResource)?.name}}
+      </template>
+      <template v-if="column.key === 'subjectEvent'" >
+        {{RuleController.SubjectEventMap.get(record.subjectEvent)?.name}}
+      </template>
+      <template v-if="column.key === 'status'" >
+        <a-switch
+          v-model:checked="record.status"
+          checked-children="运行中"
+          un-checked-children="已停止"
+          @click="changeStatus(record)"
+        />
+      </template>
+      <template v-if="column.key === 'action'" >
+        <a-space>
+              <a-popconfirm
+                  title="确实要删除吗?"
+                  ok-text="确定"
+                  cancel-text="取消"
+                  @confirm="delForwardRule(record.id)"
+                >
+                  <a>删除</a>
+                </a-popconfirm>
+        </a-space>
+      </template>
+    </template>
+  </a-table>
+</a-card>
+
+<!-- 创建规则 -->
+<modal-pro
+  width="1000px"
+  label="创建规则"
+  :visible="state.visible"
+  @cancel="state.visible = false"
+  @ok="ok('visible')"
+>
+    <a-steps :current="state.stepCount">
+        <a-step title="设置转发数据" ></a-step>
+        <a-step title="设置转发目标"  />
+        <a-step title="启动规则"/>
+    </a-steps>
+    <div style="margin: 20px 0px;" >
+      <div v-if="state.stepCount === 0" >针对部分类型数据提供的快速配置,将引导您完成简单的业务设置。您也可以直接编辑过滤语句,实现更复杂的查询要求</div>
+      <div v-else-if="state.stepCount === 1" >您可以设置将数据转发至华为云其他服务或私有服务器。</div>
+      <div v-else >完成完整的规则定义后,您就可以控制规则的运行,以实现数据转发。</div>
+    </div>
+    <form-pro
+      v-if="state.stepCount == 0"
+      validate
+      :formProps="formProps"
+      ref="formProo"
+    />
+    <div v-if="state.stepCount == 1" >
+      <a-row>
+        <a-col>
+          <a-space>
+            <a-button type="primary" @click="state.targetVisible = true">添加</a-button>
+          </a-space>
+        </a-col>
+      </a-row>
+    </div>
+    <div v-if="state.stepCount == 2" >
+      <a-button>启动规则</a-button>
+    </div>
+</modal-pro>
+
+<modal-pro
+  label="转发目标"
+  :visible="state.targetVisible"
+  @cancel="state.targetVisible = false"
+  @ok="ok('targetVisible')"
+>
+  <a-select
+    style="width: 100%;"
+  >
+    <a-select-option
+      v-for="item in forwardTatget"
+      :key="item.key"
+      :value="item.key"
+    >
+      {{item.name}}
+    </a-select-option>
+  </a-select>
+</modal-pro>
+</template>
+
+<script lang='ts' setup >
+import { onMounted, reactive, ref, toRefs } from 'vue'
+import { RuleController } from '@/controller/index'
+import type { FormItemProps } from '@/components/FormPro/index.vue'
+
+const columns = [
+  {
+    title: '规则名称',
+    dataIndex: 'ruleLabel'
+  },
+  {
+    title: '规则ID',
+    dataIndex: 'id'
+  },
+  {
+    title: '数据来源',
+    dataIndex: 'subjectResource',
+    key: 'subjectResource'
+  },
+  {
+    title: '触发事件',
+    dataIndex: 'subjectEvent',
+    key: 'subjectEvent'
+  },
+  {
+    title: '状态',
+    dataIndex: 'status',
+    key: 'status'
+  },
+  {
+    title: '操作',
+    dataIndex: 'action',
+    key: 'action'
+  }
+]
+
+const formProps: FormItemProps[] = [
+  {
+    label: '规则名称',
+    key: 'ruleLabel',
+    type: 'input',
+    rules: true,
+    value: ''
+  },
+  {
+    label: '数据来源',
+    key: 'subjectResource',
+    type: 'select',
+    rules: true,
+    request: async () => await Array.from(RuleController.SubjectResourceMap, ([key, value]) => ({ ...value, value: value.key }))
+  },
+  {
+    label: '触发事件',
+    key: 'subjectEvent',
+    type: 'select',
+    rules: true,
+    request: async () => await Array.from(RuleController.SubjectEventMap, ([key, value]) => ({ ...value, value: value.key }))
+  },
+  {
+    label: '规则描述',
+    key: 'ruleDescription',
+    type: 'textarea',
+    rules: false,
+    value: ''
+  }
+]
+
+const formPropsSearch: FormItemProps[] = [
+  {
+    label: '规则名称',
+    key: 'ruleLabel',
+    type: 'input',
+    rules: false,
+    value: ''
+  },
+  {
+    label: '规则ID',
+    key: 'ruleId',
+    type: 'input',
+    rules: false,
+    value: ''
+  },
+  {
+    label: '数据来源',
+    key: 'subjectResource',
+    type: 'select',
+    rules: false,
+    request: async () => await Array.from(RuleController.SubjectResourceMap, ([key, value]) => ({ ...value, value: value.key }))
+  },
+  {
+    label: '触发事件',
+    key: 'subjectEvent',
+    type: 'select',
+    rules: false,
+    request: async () => await Array.from(RuleController.SubjectEventMap, ([key, value]) => ({ ...value, value: value.key }))
+  },
+  {
+    label: '状态',
+    key: 'status',
+    type: 'select',
+    rules: false,
+    request: async () => {
+      const getData = () => {
+        return [
+          { name: '所有状态', key: '', value: '' },
+          { name: '运行中', key: 'status', value: true },
+          { name: '未启动', key: 'status', value: false }
+        ]
+      }
+      return await getData()
+    }
+  }
+]
+
+const forwardTatget = [
+  { name: 'RabbitMQ', key: 'RabbitMQ' },
+  { name: 'Kafka', key: 'Kafka' },
+  { name: 'HTTP编码', key: 'HTTP编码' }
+]
+
+const formProo = ref('')
+
+let queryParams = reactive({
+  page: 1,
+  pageSize: 10,
+  total: 0,
+  ruleId: '',
+  ruleLabel: '',
+  status: '',
+  subjectEvent: '',
+  subjectResource: ''
+})
+
+const state = reactive({
+  loading: false,
+  dataSource: [],
+  visible: false,
+  targetVisible: false,
+  stepCount: 1
+})
+
+let forwardState = reactive({})
+
+const search = (record) => {
+  console.log('search', record)
+  queryParams = { ...queryParams, ...record }
+  getForwardList()
+}
+
+const changeStatus = async (record) => {
+  console.log(record.status)
+
+  // return
+  await RuleController.updateForwardStatus({ id: record.id, status: record.status })
+}
+
+/** 提交转发规则 */
+const ok = async (visibleKey: string) => {
+  if (state.stepCount === 0) {
+    const r1 = await formProo.value.onSubmit()
+    if (r1) {
+      state.stepCount++
+      forwardState = toRefs({ ...forwardState, ...r1 })
+      console.log(forwardState)
+    }
+  }
+
+  if (state.stepCount === 1) {
+    if (state.targetVisible) {
+      state.targetVisible = false
+    } else {
+      state.stepCount++
+    }
+  }
+
+  if (state.stepCount >= 3) {
+    console.log('出发提交规则')
+  }
+}
+
+const delForwardRule = async (id: string) => {
+  await RuleController.delForward(id)
+  getForwardList()
+}
+
+const getForwardList = async () => {
+  state.loading = true
+  const { data, sum } = await RuleController.pageForward(queryParams)
+  state.loading = false
+  state.dataSource = data
+  queryParams.total = sum
+}
+
+onMounted(() => {
+  getForwardList()
+})
+</script>
+<style lang='less' scoped >
+</style>

+ 9 - 0
src/pages/Iot/rule/linkRule.vue

@@ -0,0 +1,9 @@
+<template>
+<a-card>
+  linkage
+</a-card>
+</template>
+<script lang='ts' setup >
+</script>
+<style lang='less' scoped >
+</style>

+ 17 - 0
src/router/index.ts

@@ -53,6 +53,23 @@ const routes: Array<ROUTER.RoutesProps> = [
             component: () => import('@/pages/iot/device/group.vue')
           }
         ]
+      },
+      {
+        path: '/rule',
+        name: '规则',
+        redirect: '/rule/forward',
+        children: [
+          {
+            path: '/rule/forward',
+            name: '转发规则',
+            component: () => import('@/pages/iot/rule/forwardRule.vue')
+          },
+          {
+            path: '/rule/linkage',
+            name: '联动规则',
+            component: () => import('@/pages/iot/rule/linkRule.vue')
+          }
+        ]
       }
 
       // {

+ 1 - 1
src/type/common.d.ts

@@ -14,7 +14,7 @@ declare namespace COMMON {
     }
 
     namespace COMPONENTS {
-      type ComType = 'input' | 'select' | 'datepick'
+      type ComType = 'input' | 'select' | 'datepick' | 'textarea'
     }
 
 }

+ 48 - 1
src/type/iot.d.ts

@@ -174,5 +174,52 @@ declare namespace IOT {
         endTime: string
       }
     }
+
+    namespace RULE {
+
+      interface ForwardRuleQueryParams {
+        page: number,
+        pageSize: number,
+        ruleLabel?: string,
+        id: string,
+        subjectResource: SubjectResourceEnum,
+        subjectEvent: SubjectEventEnum,
+        status: boolean,
+      }
+
+      interface ForwardRuleBody {
+        subjectResource: SubjectResourceEnum,
+        subjectEvent: SubjectEventEnum,
+        ruleLabel: string,
+        ruleDescription?: string,
+        forwardRuleTargets: Array
+      }
+
+      interface ForwardRule {
+        'id': null,
+        'ruleLabel': string,
+        'ruleDescription': string,
+        'subjectResource': SubjectResourceEnum,
+        'subjectEvent': SubjectEventEnum,
+        'entityId': null,
+        'forwardRuleTargets': null,
+        'status': false
+      }
+
+      interface LinkRuleBody {
+        ruleLabel: string
+        ruleDescription: string
+        conditionLogic: string
+        conditions: Array
+        actions: Array
+      }
+
+      interface LinkRule {
+        'ruleLabel': string,
+        'ruleDescription': string,
+        'conditionLogic': string,
+        'conditions': Array
+        actions: Array
+    }
   }
-}
+}

+ 1 - 1
src/utils/UsePro.ts

@@ -10,7 +10,7 @@ export default function (app: App) {
   app.component('modal-pro', ModalPro)
   app.component('sider-pro', SiderPro)
   app.component('table-pro', TablePro)
-  app.component('form-proo', FormPro) // 别问问什么是oo, 问就是这样比较帅
+  app.component('form-pro', FormPro) // 别问问什么是oo, 问就是这样比较帅
   app.component('l-row', RowPro)
   app.component('l-col', ColPro)
 }