diff --git a/src/api/device.ts b/src/api/device.ts
new file mode 100644
index 0000000..d4ceacb
--- /dev/null
+++ b/src/api/device.ts
@@ -0,0 +1,82 @@
+import axios from 'axios';
+
+export interface DeviceRecord {
+  size: number;
+  current: number;
+  name?: string;
+  clientId?: string;
+  productId?: number;
+  status?: string;
+  isOnline?: boolean;
+  pageable?: string;
+}
+
+export interface DeviceCreateRecord {
+  num?: number;
+  prefix?: string;
+  name?: string;
+  hardwareVersion: string;
+  firmwareVersion: string;
+  extendParams: string;
+  properties: string;
+  productId: number;
+}
+
+export interface DeviceEventRecord {
+  id: number;
+  clientId: string;
+  serveName: string;
+  params: string;
+}
+
+// 分页查询
+export function queryDeviceList(data: DeviceRecord) {
+  return axios({
+    url: '/api/rest/device',
+    method: 'get',
+    params: data,
+  });
+}
+
+// 查看详情
+export function queryDeviceDetail(id: number) {
+  return axios.get(`/api/rest/device/${id}`);
+}
+
+// 新增
+export function createDevice(data: DeviceCreateRecord) {
+  return axios.post(`/api/rest/device`, data);
+}
+
+// 修改
+export function updateDevice(id: number, data: DeviceCreateRecord) {
+  return axios.put(`/api/rest/device/${id}`, data);
+}
+// 删除
+export function deleteDevice(id: number) {
+  return axios.delete(`/api/rest/device/${id}`);
+}
+
+// 查询上报
+export function queryDeviceReport(clientId: number) {
+  return axios({
+    url: `/api/rest/device/record/photo`,
+    method: 'get',
+    params: clientId,
+  });
+}
+
+// 批量创建
+export function createDeviceBatch(data: DeviceCreateRecord) {
+  return axios.post(`/api/rest/device/batch`, data);
+}
+
+// 手动触发事件
+export function triggerEvent(data: DeviceEventRecord) {
+  return axios({
+    url: `/api/rest/device/event`,
+    method: 'post',
+    data,
+  });
+}
+
diff --git a/src/api/message.ts b/src/api/message.ts
index e2d60ee..ff4cbd2 100644
--- a/src/api/message.ts
+++ b/src/api/message.ts
@@ -18,9 +18,10 @@ export function queryMessageList() {
 }
 
 interface MessageStatus {
-  ids: number[];
+  ids: string[];
 }
 
+// 批量设置消息已读
 export function setMessageStatus(data: MessageStatus) {
   return axios.post<MessageListType>('/api/message/read', data);
 }
diff --git a/src/api/product.ts b/src/api/product.ts
new file mode 100644
index 0000000..3a841e0
--- /dev/null
+++ b/src/api/product.ts
@@ -0,0 +1,63 @@
+import axios from 'axios';
+
+export interface ProductRecord {
+  size: number;
+  current: number;
+  name?: string;
+  pageable?: string;
+  type?: string;
+  links?: string;
+}
+
+export interface ProductCreateRecord {
+  name: string;
+  model: string;
+  type?: string;
+  link?: string;
+  remark?: string;
+  params:[{
+   name: string;
+   identifier: string;
+   type: string;
+   dataType: string;
+  }];
+}
+
+
+// 分页查询
+export function queryProductList(data: ProductRecord) {
+  return axios({
+    url: '/api/rest/product',
+    method: 'get',
+    params: data,
+  });
+}
+// 模糊查询获取产品列表
+export function queryProductListAll(data: ProductRecord) {
+  return axios({
+    url: '/api/rest/product/fuzzy',
+    method: 'get',
+    params: data,
+  });
+}
+
+// 查看详情
+export function queryProductDetail(id: number) {
+  return axios.get(`/api/rest/product/${id}`);
+}
+
+// 新增
+export function createProduct(data: ProductCreateRecord) {
+  return axios.post(`/api/rest/product`, data);
+}
+
+// 修改
+export function updateProduct(id: number, data: ProductCreateRecord){
+  return axios.patch(`/api/rest/product/${id}`, data);
+}
+
+// 删除
+  export function deleteProduct(id: number) {
+    return axios.delete(`/api/rest/product/${id}`);
+  }
+
diff --git a/src/mock/index.ts b/src/mock/index.ts
index ae390f6..97d9cc4 100644
--- a/src/mock/index.ts
+++ b/src/mock/index.ts
@@ -5,21 +5,10 @@ import './message-box';
 
 import '@/views/dashboard/workplace/mock';
 
-import '@/views/dashboard/monitor/mock';
 
-import '@/views/list/card/mock';
-import '@/views/list/search-table/mock';
-
-import '@/views/form/step/mock';
-
-import '@/views/profile/basic/mock';
-
-import '@/views/visualization/data-analysis/mock';
-import '@/views/visualization/multi-dimension-data-analysis/mock';
-
-import '@/views/user/info/mock';
 import '@/views/user/setting/mock';
 
+
 Mock.setup({
   timeout: '600-1000',
 });
diff --git a/src/router/routes/modules/iot.ts b/src/router/routes/modules/iot.ts
new file mode 100644
index 0000000..d5067ef
--- /dev/null
+++ b/src/router/routes/modules/iot.ts
@@ -0,0 +1,41 @@
+import { DEFAULT_LAYOUT } from '../base';
+import { AppRouteRecordRaw } from '../types';
+
+const IOT: AppRouteRecordRaw = {
+  path: '/iot',
+  name: 'iot',
+  component: DEFAULT_LAYOUT,
+  meta: {
+    locale: 'menu.iot',
+    title: '物联网管理',
+    icon: 'icon-empty',
+    requiresAuth: true,
+    order: 1,
+  },
+  children: [
+    {
+      path: 'device',
+      name: 'Device',
+      component: () => import('@/views/iot/device/index.vue'),
+      meta: {
+        // locale: 'menu.system.role',
+        title: '设备管理',
+        requiresAuth: true,
+        permissions: ['*'],
+      },
+    },
+    {
+      path: 'product',
+      name: 'Product',
+      component: () => import('@/views/iot/product/index.vue'),
+      meta: {
+        // locale: 'menu.system.dept',
+        title: '产品管理',
+        requiresAuth: true,
+        permissions: ['*'],
+      },
+    },
+  ],
+};
+
+export default IOT;
diff --git a/src/router/routes/modules/notification.ts b/src/router/routes/modules/notification.ts
deleted file mode 100644
index fa81e16..0000000
--- a/src/router/routes/modules/notification.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-import { DEFAULT_LAYOUT } from '../base';
-import { AppRouteRecordRaw } from '../types';
-
-const NOTIFICATION: AppRouteRecordRaw = {
-  path: '/notification',
-  name: 'notification',
-  component: DEFAULT_LAYOUT,
-  meta: {
-    locale: '通知管理',
-    requiresAuth: true,
-    icon: 'icon-message', // 设置图标
-    order: 0, // 排序路由菜单项。如果设置该值,值越高,越靠前
-  },
-  children: [
-    {
-      path: 'notice',
-      name: 'notice',
-      component: () => import('@/views/notification/notice/index.vue'),
-      meta: {
-        locale: '公告通知',
-        requiresAuth: true,
-        permissions: ['*'],
-      },
-    },
-    {
-      path:'noticeSet',
-      name:'noticeSet',
-      component: () => import('@/views/notification/noticeSet/index.vue'),
-      meta:{
-        locale: '公告管理',
-        requiresAuth: true,
-        permissions: ['*'],
-      }
-    }
-  ],
-};
-export default NOTIFICATION;
-
diff --git a/src/router/routes/modules/system.ts b/src/router/routes/modules/system.ts
index 201eb0b..681bcb4 100644
--- a/src/router/routes/modules/system.ts
+++ b/src/router/routes/modules/system.ts
@@ -27,9 +27,10 @@ const SYSTEM: AppRouteRecordRaw = {
       name: 'Role',
       component: () => import('@/views/system/role/index.vue'),
       meta: {
-        locale: 'menu.system.role',
+        // locale: 'menu.system.role',
+        title: '角色管理',
         requiresAuth: true,
-        permissions: ['admin'],
+        permissions: ['*'],
       },
     },
     {
@@ -37,9 +38,10 @@ const SYSTEM: AppRouteRecordRaw = {
       name: 'Dept',
       component: () => import('@/views/system/dept/index.vue'),
       meta: {
-        locale: 'menu.system.dept',
+        // locale: 'menu.system.dept',
+        title: '部门管理',
         requiresAuth: true,
-        permissions: ['admin'],
+        permissions: ['*'],
       },
     },
     {
@@ -47,19 +49,52 @@ const SYSTEM: AppRouteRecordRaw = {
       name: 'User',
       component: () => import('@/views/system/user/index.vue'),
       meta: {
-        locale: 'menu.system.user',
+        // locale: 'menu.system.user',
+        title: '用户管理',
         requiresAuth: true,
-        permissions: ['admin'],
+        permissions: ['*'],
       },
     },
     {
       path: 'authority',
-      name: 'authority',
+      name: 'Authority',
       component: () => import('@/views/system/authority/index.vue'),
       meta: {
-        locale: '权限管理',
+        // locale: '权限管理',
+        title: '权限管理',
         requiresAuth: true,
-        permissions: ['admin'],
+        permissions: ['*'],
+      },
+    },
+    {
+      path:'bulletin',
+      name:'Bulletin',
+      component: () => import('@/views/system/bulletin/index.vue'),
+      meta:{
+        title: '公告管理',
+        requiresAuth: true,
+        permissions: ['*'],
+      },
+    },
+    {
+      path:'message',
+      name:'Message',
+      component: () => import('@/views/system/message/index.vue'),
+      meta:{
+        title: '消息管理',
+        requiresAuth: true,
+        permissions: ['*'],
+      },
+    },
+    {
+      path: 'detail/:id',
+      name: 'Detail',
+      component: () => import('@/views/system/bulletin/components/detail.vue'),
+      meta: {
+        title: '公告详情',
+        requiresAuth: true,
+        showInMenu: false,
+        permissions: ['*'],
       },
     },
   ],
diff --git a/src/store/modules/auth/index.ts b/src/store/modules/auth/index.ts
index a663423..a56a24a 100644
--- a/src/store/modules/auth/index.ts
+++ b/src/store/modules/auth/index.ts
@@ -46,9 +46,6 @@ import {
       async updateAuth(params: AuthRecord) {
         return update(params);
       },
-      async getAuthDetail(id: string) {
-        return getDetail(id);
-      },
     },
   });
 
diff --git a/src/views/iot/device/components/device-edit.vue b/src/views/iot/device/components/device-edit.vue
new file mode 100644
index 0000000..368b786
--- /dev/null
+++ b/src/views/iot/device/components/device-edit.vue
@@ -0,0 +1,249 @@
+<template>
+  <a-button v-if="props.isCreate" type="primary" @click="handleClick">
+    <template #icon><icon-plus /></template>
+    新建
+  </a-button>
+  <a-button
+    v-if="!props.isCreate"
+    type="outline"
+    size="small"
+    :style="{ marginRight: '10px', padding: '7px' }"
+    @click="handleClick"
+  >
+    <template #icon><icon-edit /></template>
+    修改
+  </a-button>
+
+  <a-modal
+    width="900px"
+    :visible="visible"
+    @cancel="handleCancel"
+  >
+    <template #title>{{ modalTitle }}</template>
+    <DynamicForm :prem="formSystem" />
+
+    <template #footer>
+      <a-button class="editor-button"  @click="handleCancel">取消</a-button>
+      <a-button class="editor-button"  type="primary" @click="handleSubmit">确定</a-button>
+    </template>
+  </a-modal>
+</template>
+
+<script lang="ts" setup>
+  import useVisible from '@/hooks/visible';
+  import { computed, defineEmits, PropType, ref, shallowRef, onBeforeUnmount, reactive } from 'vue';
+  import { CreateRecord } from '@/api/user';
+  import { FormInstance } from '@arco-design/web-vue/es/form';
+  import { Message } from '@arco-design/web-vue';
+  import { useMessageStore } from '@/store';
+  import DynamicForm from '@/components/dynamic-form/index.vue';
+  import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
+  import { IEditorConfig } from '@wangeditor/editor'
+  import '@wangeditor/editor/dist/css/style.css'
+
+  const props = defineProps({
+    prem: {
+      type: Object as PropType<CreateRecord>,
+    },
+    isCreate: Boolean,
+  });
+  // 部门树模态框状态
+  const deptVisible=ref(false);
+  const emit = defineEmits(['refresh']);
+  const modalTitle = computed(() => {
+    return props.isCreate ? '创建设备' : '编辑设备';
+  });
+  const { visible, setVisible } = useVisible(false);
+  const checkKeys = ref<number[]>([]);
+
+  const CreateRef = ref<FormInstance>();
+  const formData = ref<any>({
+    ...props.prem,
+  });
+  const messageStore = useMessageStore();
+  const editorRef = shallowRef()
+  const selectedIds= ref<string[]>([]);
+  const columns = computed<any[]>(()=>[
+    {
+      title: '操作',
+      dataIndex: 'key',
+      slotName: 'key',
+    },
+    {
+      title: '用户',
+      dataIndex: 'title',
+    },
+  ])
+
+  const formSystem = ref(
+    {
+      productId:{
+        label: '产品ID',
+        component: 'input',
+        type:'text'
+      },
+      name:{
+        label: '设备名称',
+        component: 'input',
+        type:'text'
+      },
+      hardwareVersion:{
+        label: '硬件版本',
+        component: 'input',
+        type:'text'
+      },
+      firmwareVersion:{
+        label: '固件版本',
+        component: 'input',
+        type:'text'
+      },
+      extendParams:{
+        label: '扩展属性',
+        component: 'input',
+        type:'text'
+      },
+      properties:{
+        label: '设备物模型属性',
+        component: 'input',
+        type:'text'
+      },
+    },
+  );
+  const deptTreeData = reactive([
+    {
+      key: '1',
+      title: '总部门',
+      children: [
+        {
+          key: '2',
+          title: '部门1',
+          members: [
+            { key: '101', title: '成员1' },
+            { key: '102', title: '成员2' }
+          ]
+        },
+        {
+          key: '3',
+          title: '部门2',
+          members: [
+            { key: '201', title: '成员3' },
+            { key: '202', title: '成员4' }
+          ]
+        },
+        {
+          key: '4',
+          title: '部门3',
+          members: [
+            { key: '203', title: '成员5' },
+            { key: '204', title: '成员6' }
+          ]
+        }
+      ]
+    }
+  ]);
+  const selectedDepartmentMembers: any = ref([]);
+  const renderData = ref<any[]>([]);
+  // 部门树查询
+  const queryDeptTree= async ()=>{
+    deptVisible.value = true;
+  }
+
+  // 广度优先遍历树,获取选中的成员
+  const getSelectedMembers = (treeData: any[], selectedKeys: string[]) => {
+    const queue = [...treeData];
+    const selectedMembers: any[] = [];
+    while (queue.length > 0) {
+      const node = queue.shift()!;
+      if (selectedKeys.includes(node.key)) {
+        if (node.members) {
+          selectedMembers.push(...node.members);
+        }
+      }
+      if (node.children) {
+        queue.push(...node.children);
+      }
+    }
+    return selectedMembers;
+  }
+
+  // 组件被点击
+  const handleClick = () => {
+    setVisible(true);
+  };
+
+  const editorConfig: Partial<IEditorConfig> = { placeholder: '请输入内容...',MENU_CONF:{
+      // 隐藏菜单
+      hide: ['code', 'table', 'emoticon', 'uploadImage', 'video', 'todo', 'specialChar'],
+      // 配置上传图片
+      uploadImage: {
+        base64LimitSize: 1024 * 1024,
+        // server: '/api/rest/bulletin/1/add',
+      }
+    }
+  }
+  // 提交
+  const handleSubmit = async () => {
+    const valid = await CreateRef.value?.validate();
+    if (!valid) {
+      formData.value.permissionIds = checkKeys.value;
+      // 新增
+      if (props.isCreate) {
+        // formData.value.username = formData.value.email;
+        const res = await messageStore.createMessage(formData.value);
+        if (res.status === 200) {
+          Message.success({
+            content: '新建成功',
+            duration: 5 * 1000,
+          });
+          emit('refresh');
+          setVisible(false);
+        }
+        CreateRef.value?.resetFields();
+      }
+    }
+  };
+
+  // 组件销毁时,也及时销毁编辑器
+  onBeforeUnmount(() => {
+    const editor = editorRef.value
+    if (editor == null) return
+    editor.destroy()
+  })
+
+  // 关闭
+  const handleCancel = async () => {
+    checkKeys.value = [];
+    setVisible(false);
+  };
+
+  // 设备模态框提交
+  const deptTreeSubmit = () => {
+    deptVisible.value = false;
+    formData.value.userIds = selectedIds.value;
+    console.log(formData.value.userIds);
+  };
+</script>
+
+<style scoped>
+  .fullscreen-toolbar {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 50px; /* 根据需要调整高度 */
+    z-index: 999;
+    background-color: white;
+  }
+  .fullscreen-editor {
+    position: fixed;
+    top: 50px; /* 根据 toolbar 的高度调整 */
+    left: 0;
+    width: 100%;
+    height: calc(100% - 50px); /* 减去 toolbar 的高度 */
+    z-index: 999;
+    background-color: white;
+  }
+  .editor-button{
+    position: static
+  }
+</style>
diff --git a/src/views/iot/device/index.vue b/src/views/iot/device/index.vue
new file mode 100644
index 0000000..76dee0e
--- /dev/null
+++ b/src/views/iot/device/index.vue
@@ -0,0 +1,374 @@
+<template>
+  <div class="container">
+    <Breadcrumb :items="['系统管理', '公告设置']" />
+    <a-card class="general-card" title=" ">
+      <a-row>
+        <a-col :flex="1">
+          <a-form
+            :model="formModel"
+            :label-col-props="{ span: 6 }"
+            :wrapper-col-props="{ span: 18 }"
+            label-align="right"
+          >
+            <a-row :gutter="18">
+              <a-col :span="9">
+                <a-form-item
+                  field="name"
+                  label='名称'
+                >
+                  <a-input
+                    v-model="formModel.name"
+                    style="width: 360px"
+                    placeholder='请输入设备名称'
+                  />
+                </a-form-item>
+              </a-col>
+              <a-col :span="10">
+                <a-form-item field="status" label='状态'>
+                  <a-input
+                    v-model="formModel.status"
+                    style="width: 360px"
+                    placeholder='请输入设备状态'
+                  />
+                </a-form-item>
+              </a-col>
+              <a-col :span="9">
+                <a-form-item
+                  field="isOnline"
+                  label='在线'
+                >
+                  <a-select
+                    v-model="formModel.isOnline"
+                    style="width: 360px"
+                    placeholder='请选择是否在线'
+                    :options="statusOptions"
+                  />
+                </a-form-item>
+              </a-col>
+
+
+
+            </a-row>
+          </a-form>
+        </a-col>
+        <a-divider style="height: 84px" direction="vertical" />
+        <a-col :flex="'86px'" style="text-align: right">
+          <a-space direction="vertical" :size="18">
+            <a-button type="primary" @click="search">
+              <template #icon>
+                <icon-search />
+              </template>
+              查询
+            </a-button>
+            <a-button @click="reset">
+              <template #icon>
+                <icon-refresh />
+              </template>
+              重置
+            </a-button>
+          </a-space>
+        </a-col>
+      </a-row>
+      <a-divider style="margin-top: 0" />
+      <a-row>
+        <a-col :span="12">
+          <a-space>
+            <DeviceEdit ref="createUserRef" :is-create="true" @refresh="search" />
+          </a-space>
+        </a-col>
+        <a-col
+          :span="12"
+          style="
+            display: flex;
+            align-items: center;
+            justify-content: end;
+            padding-bottom: 20px;
+          "
+        >
+          <a-tooltip content='刷新'>
+            <div class="action-icon" @click="search">
+              <icon-refresh size="18" />
+            </div>
+          </a-tooltip>
+
+          <a-dropdown @select="handleSelectDensity">
+            <a-tooltip content='密度'>
+              <div class="action-icon"><icon-line-height size="18" /></div>
+            </a-tooltip>
+            <template #content>
+              <a-doption
+                v-for="item in densityList"
+                :key="item.value"
+                :value="item.value"
+                :class="{ active: item.value === size }"
+              >
+                <span>{{ item.name }}</span>
+              </a-doption>
+            </template>
+          </a-dropdown>
+
+          <a-tooltip content='列设置'>
+            <a-popover
+              trigger="click"
+              position="bl"
+              @popup-visible-change="popupVisibleChange"
+            >
+              <div class="action-icon"><icon-settings size="18" /></div>
+              <template #content>
+                <div id="tableSetting">
+                  <div
+                    v-for="(item, index) in showColumns"
+                    :key="item.dataIndex"
+                    class="setting"
+                  >
+                    <div style="margin-right: 4px; cursor: move">
+                      <icon-drag-arrow />
+                    </div>
+                    <div>
+                      <a-checkbox
+                        v-model="item.checked"
+                        @change="
+                          handleChange($event, item as TableColumnData, index)
+                        "
+                      >
+                      </a-checkbox>
+                    </div>
+                    <div class="title">
+                      {{ item.title === '#' ? '序列号' : item.title }}
+                    </div>
+                  </div>
+                </div>
+              </template>
+            </a-popover>
+          </a-tooltip>
+        </a-col>
+      </a-row>
+
+      <a-table
+        row-key="id"
+        :loading="loading"
+        :pagination="false"
+        :columns="(cloneColumns as TableColumnData[])"
+        :data="renderData"
+        :bordered="false"
+        :size="size"
+        style="margin-bottom: 40px"
+        @page-change="onPageChange"
+      >
+        <template #id="{ record }">
+          <span>{{ record.id }}</span>
+        </template>
+        <template #online="{ record }">
+          {{ record.online == true? '是' : '否' }}
+        </template>
+        <template #operations="{ record }">
+          <a-button
+            type="outline"
+            size="small"
+            status="success"
+            style="padding: 7px; margin-right: 10px"
+            @click="openDetail(record.id)"
+          >
+            <template #icon><icon-list /></template>
+            详情
+          </a-button>
+        </template>
+      </a-table>
+      <a-pagination
+        style="float: right; position: relative; right: 1px; bottom: 25px"
+        :total="pagination.total"
+        :size="size"
+        show-total
+        show-jumper
+        show-page-size
+        @page-size-change="onSizeChange"
+        @change="onPageChange"
+      />
+    </a-card>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import { computed, onMounted, ref, watch } from 'vue';
+  import useLoading from '@/hooks/loading';
+  import usePagination from '@/hooks/pagination';
+  import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
+  import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
+  import { useBulletinStore } from '@/store';
+  import useTableOption from '@/hooks/table-option';
+  import { Message } from '@arco-design/web-vue';
+  import { useRouter } from 'vue-router';
+  import { DeviceRecord, queryDeviceList } from '@/api/device';
+  import DeviceEdit from '@/views/iot/device/components/device-edit.vue';
+
+  const generateFormModel = () => {
+    return {
+      name:'',
+      status:'',
+      isOnline:'',
+    };
+  };
+
+  const { loading, setLoading } = useLoading(true);
+  const { pagination,setPagination } = usePagination();
+  const renderData = ref<[]>([]);
+  const formModel = ref(generateFormModel());
+  const router = useRouter();
+  const {
+    cloneColumns,
+    showColumns,
+    densityList,
+    size,
+    handleSelectDensity,
+    handleChange,
+    popupVisibleChange,
+    deepClone,
+  } = useTableOption();
+
+  const bulletinStore = useBulletinStore();
+
+  const columns = computed<TableColumnData[]>(() => [
+    {
+      title: 'ID',
+      dataIndex: 'id',
+      slotName: 'id',
+      width: 60,
+    },
+    {
+      title: '名称',
+      dataIndex: 'name',
+    },
+    {
+      title: '状态',
+      dataIndex: 'state',
+      slotName: 'state',
+    },
+    {
+      title: '在线状态',
+      dataIndex: 'online',
+      slotName:'online',
+      sortable: {
+        sortDirections: ['ascend', 'descend'],
+      },
+    },
+    {
+      title: '操作',
+      dataIndex: 'operations',
+      slotName: 'operations',
+    },
+  ]);
+  const statusOptions = computed<SelectOptionData[]>(() => [
+    {
+      label: '是',
+      value: 'true',
+    },
+    {
+      label: '否',
+      value: 'false',
+    },
+  ]);
+
+  // 获取设备列表
+  const fetchData = async (
+    params = { size: 10, current: 1 }
+  ) => {
+    setLoading(true);
+    try {
+      const res: any = await queryDeviceList(params);
+      renderData.value = res.data.records;
+      setPagination(res.data);
+    } catch (err) {
+      // you can report use errorHandler or other
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  // 查询
+  const search = () => {
+    fetchData({
+      ...pagination,
+      ...formModel.value,
+    } as unknown as DeviceRecord);
+  };
+
+  // 分页发生改变
+  const onPageChange = (current: number) => {
+    pagination.page = current;
+    pagination.current = current;
+    search();
+  };
+
+  // 数据条数改变
+  const onSizeChange = (Size: number) => {
+    pagination.size = Size;
+    search();
+  };
+
+
+  // 重置
+  const reset = () => {
+    formModel.value = generateFormModel();
+  };
+
+  // 打开详情
+  function openDetail(id:number): void{
+    const url = router.resolve({
+      name: 'Detail',
+      params: {id}
+    }).href;
+    router.push(url);
+  };
+
+  // 删除
+  const handleDelete = async (id: number) => {
+    const res = await bulletinStore.removeBulletin(id);
+    if (res.status === 200) {
+      Message.success({
+        content: '删除成功',
+        duration: 5 * 1000,
+      });
+      search();
+    }
+  };
+  onMounted(() => {
+    search();
+  });
+  watch(() => columns.value, deepClone, { deep: true, immediate: true });
+</script>
+
+
+<style scoped lang="less">
+  .container {
+    padding: 0 20px 20px 20px;
+  }
+
+  :deep(.arco-table-th) {
+    &:last-child {
+      .arco-table-th-item-title {
+        margin-left: 16px;
+      }
+    }
+  }
+
+  .action-icon {
+    margin-left: 12px;
+    cursor: pointer;
+  }
+
+  .active {
+    color: #0960bd;
+    background-color: #e3f4fc;
+  }
+
+  .setting {
+    display: flex;
+    align-items: center;
+    width: 200px;
+
+    .title {
+      margin-left: 12px;
+      cursor: pointer;
+    }
+  }
+</style>
\ No newline at end of file
diff --git a/src/views/iot/product/index.vue b/src/views/iot/product/index.vue
new file mode 100644
index 0000000..e69de29
diff --git a/src/views/login/components/login-form.vue b/src/views/login/components/login-form.vue
index c0a4df1..b3a8aeb 100644
--- a/src/views/login/components/login-form.vue
+++ b/src/views/login/components/login-form.vue
@@ -1,6 +1,6 @@
 <template>
   <div class="login-form-wrapper">
-    <div class="login-form-title">{{ $t('login.form.title') }}</div>
+    <div class="login-form-title">物联网网关系统</div>
     <!--    <div class="login-form-sub-title">{{ $t('login.form.title') }}</div>-->
     <!--    <div class="login-form-sub-title">请先登录</div>-->
     <div class="login-form-error-msg">{{ errorMessage }}</div>
diff --git a/src/views/notification/noticeSet/components/notice-edit.vue b/src/views/notification/noticeSet/components/notice-edit.vue
deleted file mode 100644
index 368fda7..0000000
--- a/src/views/notification/noticeSet/components/notice-edit.vue
+++ /dev/null
@@ -1,214 +0,0 @@
-<template>
-  <a-button v-if="props.isCreate" type="primary">
-    <template #icon><icon-plus /></template>
-    新建
-  </a-button>
-  <a-button
-    v-if="!props.isCreate"
-    type="outline"
-    size="small"
-    :style="{ marginRight: '10px', padding: '7px' }"
-  >
-    <template #icon><icon-edit /></template>
-    修改
-  </a-button>
-
-  <a-modal
-    width="700px"
-    :visible="visible"
-    @ok="handleSubmit"
-    @cancel="handleCancel"
-  >
-    <template #title>{{ modalTitle }}</template>
-    <a-form ref="CreateRef" :model="formData" :style="{ width: '650px' }">
-      <a-form-item
-        field="title"
-        :label="$t('标题')"
-        :validate-trigger="['change', 'input']"
-        :rules="[
-          { required: true, message: '' },
-          {
-            match: /^[a-zA-Z0-9\u4e00-\u9fa5]{1,20}$/,
-            message: '',
-          },
-        ]"
-      >
-        <a-input
-          v-model="formData.title"
-          :placeholder="$t('请输入公告标题')"
-        />
-        <!--          v-if="props.isCreate"-->
-<!--        <div v-else>{{ formData.title }}</div>-->
-      </a-form-item>
-      <a-form-item
-        field="email"
-        :label="$t('作者')"
-        :rules="[
-          {
-            required: true,
-            type: 'email',
-            message: t('user.info.email.required'),
-          },
-        ]"
-        :validate-trigger="['change', 'input']"
-      >
-        <a-input
-          v-model="formData.email"
-          :placeholder="$t('请输入作者')"
-        />
-      </a-form-item>
-      <a-form-item
-        field="phone"
-        :label="$t('发布范围')"
-        :rules="[
-          { required: true, message: t('user.info.phone.required') },
-          { match: /^1[3-9]\d{9}$/, message: t('user.info.phone.format') },
-        ]"
-        :validate-trigger="['change', 'input']"
-      >
-        <a-input
-          v-model="formData.phone"
-          :placeholder="$t('请选择范围')"
-        />
-      </a-form-item>
-      <a-form-item
-        field="password"
-        :label="$t('发布时间')"
-        :validate-trigger="['change', 'input']"
-        :rules="[{ required: true, message: t('user.info.password.required') }]"
-      >
-        <!--        v-if="isCreate"-->
-        <a-input
-          v-model="formData.password"
-          :placeholder="$t('请选择发布时间')"
-        />
-      </a-form-item>
-      <a-form-item field="nickName" :label="$t('公告内容')">
-        <a-textarea default-value="请输入内容" :auto-size="{
-    minRows:2,
-    maxRows:5
-  }" style="margin-top: 20px" v-model="formData.content"/>
-      </a-form-item>
-    </a-form>
-  </a-modal>
-</template>
-
-<script lang="ts" setup>
-import { useI18n } from 'vue-i18n';
-import useVisible from '@/hooks/visible';
-import { computed, PropType, ref } from 'vue';
-import { CreateRecord } from '@/api/user';
-import { FormInstance } from '@arco-design/web-vue/es/form';
-import { deptList } from '@/api/dept';
-import { Message } from '@arco-design/web-vue';
-import { useUserStore } from '@/store';
-
-const props = defineProps({
-  prem: {
-    type: Object as PropType<CreateRecord>,
-  },
-  isCreate: Boolean,
-});
-const { t } = useI18n();
-const modalTitle = computed(() => {
-  return props.isCreate ? t('新增公告') : t('编辑公告');
-});
-const { visible, setVisible } = useVisible(false);
-const checkKeys = ref<number[]>([]);
-
-const CreateRef = ref<FormInstance>();
-
-const formData = ref<any>({
-
-});
-
-let formDifer = {};
-const userStore = useUserStore();
-
-// 部门数据
-const deptOptions = ref();
-const getDeptData = async () => {
-  const res = await deptList();
-  deptOptions.value = res.data.records;
-};
-// 角色数据
-// const roleOptions = ref();
-// const getRoleData = async () => {
-//   const res = await queryRoleList('');
-//   roleOptions.value = res.data.records.filter((item: any) => {
-//     return item.enabled !== false;
-//   });
-// };
-
-// 组件被点击
-// const handleClick = () => {
-//   getDeptData();
-//   // getRoleData();
-//   const userId = props.prem?.id;
-//   // 编辑
-//   if (!props.isCreate && userId) {
-//     formData.value = props.prem;
-//     formDifer = { ...props.prem };
-//   }
-//   setVisible(true);
-// };
-
-// 做出只修改的部分
-const diffDataForm = (newData: any, oldData: any) => {
-  const result = {}; // 报错修改的字段内容
-  Object.keys(oldData).forEach((key) => {
-    if (oldData[key] !== newData[key]) {
-      result[key] = newData[key];
-    }
-  });
-  return result;
-};
-
-// 提交
-const handleSubmit = async () => {
-  const valid = await CreateRef.value?.validate();
-  if (!valid) {
-    formData.value.permissionIds = checkKeys.value;
-    // 新增
-    if (props.isCreate) {
-      // formData.value.username = formData.value.email;
-      const res = await userStore.createUser(formData.value);
-      if (res.status === 200) {
-        Message.success({
-          content: t('create.sucess'),
-          duration: 5 * 1000,
-        });
-      }
-      CreateRef.value?.resetFields();
-    } else {
-      // 编辑
-      formDifer = diffDataForm(formData.value, formDifer);
-      if (Object.keys(formDifer).length === 0) {
-        Message.success({
-          content: t('unmodified'),
-          duration: 3 * 1000,
-        });
-      } else {
-        formDifer.id = formData.value.id;
-        const res = await userStore.updateUser(formDifer);
-        if (res.status === 200) {
-          Message.success({
-            content: t('modify.sucess'),
-            duration: 5 * 1000,
-          });
-        }
-      }
-    }
-    checkKeys.value = [];
-    setVisible(false);
-  }
-};
-
-// 关闭
-const handleCancel = async () => {
-  checkKeys.value = [];
-  setVisible(false);
-};
-</script>
-
-<style scoped></style>
diff --git a/src/views/system/role/components/role-table.vue b/src/views/system/role/components/role-table.vue
deleted file mode 100644
index ddfaf6e..0000000
--- a/src/views/system/role/components/role-table.vue
+++ /dev/null
@@ -1,132 +0,0 @@
-<template>
-    <a-table row-key="id" :loading="loading" :pagination="false" :columns="columns" :data="data" :bordered="false"
-        :size="size" style="margin-bottom: 40px" @pageChange="onPageChange">
-        <template #index="{ rowIndex }">
-            {{ rowIndex + 1 }}
-        </template>
-        <template #createTime="{ record }">
-            {{ dayjs(record.createTime).format('YYYY-MM-DD') }}
-        </template>
-        <template #enabled="{ record }">
-            <a-switch :model-value="record.enabled" :checked-value="true" :unchecked-value="false"
-                @change="enabledStatus(record)" />
-        </template>
-        <template #operations="{ record }">
-            <!-- 编辑 -->
-            <RoleEdit ref="editRef" :prem="record" :is-create="false" @refresh="fetchData" />
-            <a-popconfirm :content="t('Confirm the deletion of this role')" type="error" @ok="handleDelete(record)">
-                <a-button type="outline" size="small" status="danger" style="padding: 7px">
-                    <template #icon><icon-delete /></template>
-                    删除
-                </a-button>
-            </a-popconfirm>
-        </template>
-    </a-table>
-</template>
-
-<script lang="ts" setup>
-import { defineProps, defineEmits} from 'vue';
-import dayjs from 'dayjs';
-import { useI18n } from 'vue-i18n';
-import { Message } from '@arco-design/web-vue';
-import { useRoleStore } from '@/store';
-import { RoleRecord } from '@/api/role';
-// import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
-import RoleEdit from './role-edit.vue';
-
-const roleStore = useRoleStore();
-const props = defineProps({
-    loading: Boolean,
-    data: Array,
-    size: String,
-});
-
-const { t } = useI18n();
-const emit = defineEmits(['pageChange', 'refresh','search']);
-// 表格头部
-// const columns = computed<TableColumnData[]>(() => [
-//   {
-//     title: t('roleTable.columns.index'),
-//     dataIndex: 'index',
-//     slotName: 'index',
-//   },
-//   {
-//     title: t('roleTable.columns.name'),
-//     dataIndex: 'name',
-//     sortable: {
-//       sortDirections: ['ascend', 'descend'],
-//     },
-//   },
-//   {
-//     title: t('roleTable.columns.remark'),
-//     dataIndex: 'remark',
-//   },
-//   {
-//     title: t('roleTable.columns.createTime'),
-//     dataIndex: 'createTime',
-//     slotName: 'createTime',
-//     sortable: {
-//       sortDirections: ['ascend', 'descend'],
-//     },
-//   },
-//   {
-//     title: t('roleTable.columns.enabled'),
-//     dataIndex: 'enabled',
-//     slotName: 'enabled',
-//   },
-//   {
-//     title: t('searchTable.columns.operations'),
-//     dataIndex: 'operations',
-//     slotName: 'operations',
-//   },
-// ]);
-
-
-const fetchData = () => {
-    emit('refresh');
-};
-// 分页
-const onPageChange = (page: number) => {
-    emit('pageChange', page);
-};
-
-// 是否启用
-const enabledStatus = async (record: string) => {
-  record.enabled = !record.enabled;
-  const res = await roleStore.enabledRole(record.id);
-  if (res.status === 200) {
-    Message.success({
-      content: t('modify.status.sucess'),
-      duration: 3 * 1000,
-    });
-  } else {
-    Message.error({
-      content: t('modify.status.fail'),
-      duration: 3 * 1000,
-    });
-  }
-};
-
-// 删除
-const handleDelete = async (record: RoleRecord) => {
-  const res = await roleStore.removeRole(record.id);
-  if (res.status === 200) {
-    Message.success({
-      content: t('delete.role.sucess'),
-      duration: 5 * 1000,
-    });
-    emit('search'); 
-  } else {
-    Message.error({
-      content: t('delete.role.fail'),
-      duration: 3 * 1000,
-    });
-  }
-};
-
-// watch(() => columns.value, deepClone, { deep: true, immediate: true });
-</script>
-
-<style scoped>
-/* 添加一些样式 */
-</style>
\ No newline at end of file