diff --git a/config/defaultForm.ts b/config/defaultForm.ts
index 38a51b8..9228aad 100644
--- a/config/defaultForm.ts
+++ b/config/defaultForm.ts
@@ -2,15 +2,26 @@
  * @Author: zhoux zhouxia@supervision.ltd
  * @Date: 2023-11-13 14:19:57
  * @LastEditors: zhoux zhouxia@supervision.ltd
- * @LastEditTime: 2023-11-22 13:15:04
+ * @LastEditTime: 2023-12-27 16:09:07
  * @FilePath: \general-ai-platform-web\config\defaultForm.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE2
  */
 
+import { CloseCircleOutlined, CopyOutlined, DeleteOutlined } from "@ant-design/icons";
 import { StepsFormProps } from "@ant-design/pro-components";
 import { ReactNode } from "react";
 
-
+export type IconConfig = {
+  /**
+   * 新的icon的组件,我们会将其实例化
+   * Icon: ()=> <div/>
+   */
+  Icon?: React.FC<any>;
+  /**
+   * tooltip 的提示文案
+   */
+  tooltipText?: string;
+};
 // 通用表单配置
 export const proFormCommonOptions: Record<string,any> = {
 }
@@ -22,6 +33,8 @@ export const proFormSmallModelWidth: number = 560;
 export const proFormSmallItemStyleProps: Record<string, any> = {
   width: proFormSmallModelWidth - formBoxMargin,  // 一列
   // column2Width: (proFormSmallModelWidth -  2 * formBoxMargin)/2 , // 两列
+
+  
 };
 
 // normal 804
@@ -46,9 +59,28 @@ export const proFormMaxItemStyleProps: Record<string, any> = {
 export const proFormListCreatorButtonProps : {
   creatorButtonText?: ReactNode;
   position?: 'top' | 'bottom';
+  deleteIconProps?: IconConfig | false;
 } = {
   position: 'bottom',
   creatorButtonText: '添加参数字段', // 设置新增一项数据的文案
+  deleteIconProps: {
+    Icon: CloseCircleOutlined,
+    tooltipText: '不需要这行了',
+  }
+}
+
+export const proFormListActionButtonProps : {
+  CopyableIconProps?: IconConfig | false;
+  deleteIconProps?: IconConfig | false;
+} = {
+  CopyableIconProps: {
+    Icon: CopyOutlined,
+    tooltipText: '复制',
+  },
+  deleteIconProps: {
+    Icon: DeleteOutlined,
+    tooltipText: '删除',
+  }
 }
 
 
diff --git a/config/defaultStyle.ts b/config/defaultStyle.ts
new file mode 100644
index 0000000..35ce779
--- /dev/null
+++ b/config/defaultStyle.ts
@@ -0,0 +1,16 @@
+/*
+ * @Author: zhoux zhouxia@supervision.ltd
+ * @Date: 2023-12-26 15:51:09
+ * @LastEditors: zhoux zhouxia@supervision.ltd
+ * @LastEditTime: 2023-12-26 15:51:18
+ * @FilePath: \general-ai-platform-web\config\defaultStyle.ts
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE 
+ */
+export const flex: React.CSSProperties = {
+    display: 'flex'
+}
+
+export const flexRA: React.CSSProperties = {
+    ...flex,
+    
+}
\ No newline at end of file
diff --git a/config/routes copy.ts b/config/routes copy.ts
new file mode 100644
index 0000000..d1b2cba
--- /dev/null
+++ b/config/routes copy.ts	
@@ -0,0 +1,332 @@
+/**
+ * @name umi 的路由配置
+ * @description 只支持 path,components,routes,redirect,wrappers,name,icon 的配置
+ * @param path  path 只支持两种占位符配置,第一种是动态参数 :id 的形式,第二种是 * 通配符,通配符只能出现路由字符串的最后。
+ * @param components 配置 location 和 path 匹配后用于渲染的 React 组件路径。可以是绝对路径,也可以是相对路径,如果是相对路径,会从 src/pages 开始找起。
+ * @param routes 配置子路由,通常在需要为多个路径增加 layout 组件时使用。
+ * @param redirect 配置路由跳转
+ * @param wrappers 配置路由组件的包装组件,通过包装组件可以为当前的路由组件组合进更多的功能。 比如,可以用于路由级别的权限校验
+ * @param name 配置路由的标题,默认读取国际化文件 menu.ts 中 menu.xxxx 的值,如配置 name 为 login,则读取 menu.ts 中 menu.login 的取值作为标题
+ * @param icon 配置路由的图标,取值参考 https://ant.design/components/icon-cn, 注意去除风格后缀和大小写,如想要配置图标为 <StepBackwardOutlined /> 则取值应为 stepBackward 或 StepBackward,如想要配置图标为 <UserOutlined /> 则取值应为 user 或者 User
+ * @doc https://umijs.org/docs/guides/routes
+ */
+export default [
+  {
+    path: '/user',
+    layout: false,
+    routes: [
+      {
+        name: 'login',
+        path: '/user/login',
+        component: './User/Login/index1',
+      },
+    ],
+  },
+  {
+    path: '/welcome',
+    name: 'welcome',
+    component: 'Welcome/Welcome',
+  },
+  {
+    path: '/admin',
+    name: 'admin',
+
+    access: 'canAdmin',
+    routes: [
+      {
+        path: '/admin',
+        redirect: '/admin/sub-page',
+      },
+      {
+        path: '/admin/sub-page',
+        name: 'sub-page',
+        component: './Admin',
+      },
+    ],
+  },
+
+  {
+    path: '/system',
+
+    name: 'system',
+
+    routes: [
+      {
+        name: 'api-list',
+        path: '/system/api-list',
+        component: 'System/ApiList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'menu-list',
+        path: '/system/menu-list',
+        component: 'System/MenuList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'role-list',
+        path: '/system/role-list',
+        component: 'System/RoleList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'user-list',
+        path: '/system/user-list',
+        component: 'System/UserList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'post-list',
+        path: '/system/post-list',
+        component: 'System/PostList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'department-list',
+        path: '/system/department-list',
+        component: 'System/DepartmentList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'operation_record-list',
+        path: '/system/operation_record-list',
+        component: 'System/OperationRecordList',
+        access: 'canReadMenu',
+      },
+    ],
+  },
+  {
+    name: 'device',
+    path: '/device',
+    routes: [
+      {
+        name: 'device-list',
+        path: '/device/device-list',
+        component: 'Device/DeviceList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'device-category-list',
+        path: '/device/device-category-list',
+        component: 'Device/DeviceCategoryList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'device-group-list',
+        path: '/device/device-group-list',
+        component: 'Device/DeviceGroupList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'device-relation-list',
+        path: '/device/device-relation-list',
+        component: 'Device/DeviceRelationList',
+        access: 'canReadMenu',
+      },
+    ],
+  },
+  {
+    name: 'DCSDevice',
+    path: '/DCSDevice',
+    routes: [
+      {
+        name: 'DCSDevice-device-group-list',
+        path: '/DCSDevice/device-group-list',
+        component: 'DCSDevice/DeviceGroupList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'DCSDevice-device-category-list',
+        path: '/DCSDevice/device-category-list',
+        component: 'DCSDevice/DeviceCategoryList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'DCSDevice-device-list',
+        path: '/DCSDevice/device-list',
+        component: 'DCSDevice/DeviceList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'DCSDevice-device-status',
+        path: '/DCSDevice/device-status',
+        component: 'DCSDevice/DeviceStatus',
+        access: 'canReadMenu',
+      },
+    ],
+  },
+  {
+    name: 'resource',
+    path: '/resource',
+    routes: [
+      {
+        name: 'algorithm-model-list',
+
+        path: '/resource/algorithm-model-list',
+        component: 'Resource/AlgorithmModelList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'algorithm-model-detail',
+        path: '/resource/algorithm-model-detail/:id',
+        component: 'Resource/AlgorithmModelList/detail',
+        access: 'canReadMenu',
+        isHideTab: true,
+      },
+      {
+        name: 'business-image-list',
+
+        path: '/resource/business-image-list',
+        component: 'Resource/BusinessImageList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'model-category-list',
+
+        path: '/resource/model-category-list',
+        component: 'Resource/ModelCategoryList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'model-image-list',
+        path: '/resource/model-image-list',
+        component: 'Resource/ModelImageList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'model-version-list',
+        path: '/resource/model-version-list',
+        component: 'Resource/ModelVersionList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'resource-device-status',
+        path: '/resource/resource-device-status',
+        component: 'Resource/ResourceDeviceStatus',
+        access: 'canReadMenu',
+      },
+    ],
+  },
+  {
+    name: 'analysis',
+    path: '/analysis',
+    routes: [
+      {
+        name: 'action-detection-list',
+        path: '/analysis/action-detection-list',
+        component: 'Analysis/ActionDetectionList',
+        access: 'canReadMenu',
+      },
+    ],
+  },
+  {
+    name: 'project',
+    path: '/project',
+    routes: [
+      {
+        name: 'project-list',
+
+        path: '/project/project-list',
+        component: 'Project/ProjectList',
+        access: 'canReadMenu',
+      },
+    ],
+  },
+  {
+    name: 'Contact',
+    path: '/Contact',
+    routes: [
+      {
+        name: 'Contact-contact-list',
+        path: '/Contact/contact-list',
+        component: 'Contact/ContactList',
+        access: 'canReadMenu',
+      },
+    ],
+  },
+  {
+    name: 'task',
+    path: '/task',
+    component: 'Hidden',
+  },
+  {
+    name: 'compute_power',
+    path: '/compute_power',
+    component: 'ComputePowerAllocation/ComputePowerAllocation',
+  },
+  {
+    name: 'data_screen',
+    path: '/data_screen',
+  },
+  {
+    name: 'algorithm_setting',
+    path: '/algorithm_setting',
+    component: 'Setting/AlgorithmSetting',
+  },
+  {
+    name: 'alarm',
+    path: '/alarm',
+    routes: [
+      {
+        name: 'alarm-list',
+        path: '/alarm/alarm-list',
+        component: 'Alarm/AlarmList',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'alarm-setting',
+        path: '/alarm/alarm-setting',
+        component: 'Alarm/AlarmSetting',
+        access: 'canReadMenu',
+      },
+      {
+        name: 'alarm-ways',
+        path: '/alarm/alarm-ways',
+        component: 'Alarm/AlarmWays',
+        access: 'canReadMenu',
+      },
+    ],
+  },
+  {
+    name: 'logging',
+    path: 'http://192.168.10.96:5601/app/r/s/uDpRg',
+  },
+  {
+    path: '/',
+    redirect: '/welcome',
+  },
+  {
+    path: '*',
+    layout: false,
+    component: './404',
+  },
+  {
+    name: 'fabricView',
+    path: '/fabricView',
+    routes: [
+      {
+        name: 'fabricView-room',
+        path: '/fabricView/room',
+        component: 'FabricView/Room',
+        access: 'canReadMenu',
+      },
+    ],
+  },
+  {
+    name: 'notice',
+    path: '/notice',
+    component: 'Notice',
+  },
+  {
+    name: 'account',
+    path: '/account',
+    routes: [
+      {
+        name: 'center',
+        path: '/account/center',
+        component: 'Account/Center',
+        access: 'canReadMenu',
+      },
+    ],
+  },
+];
diff --git a/config/routes.ts b/config/routes.ts
index 8f68b38..f10493a 100644
--- a/config/routes.ts
+++ b/config/routes.ts
@@ -286,6 +286,12 @@ export default [
         component: 'Alarm/AlarmSetting',
         access: 'canReadMenu',
       },
+      {
+        name: 'alarm-ways',
+        path: '/alarm/alarm-ways',
+        component: 'Alarm/AlarmWays',
+        access: 'canReadMenu',
+      },
     ],
   },
   {
diff --git a/public/loading.gif b/public/loading.gif
new file mode 100644
index 0000000..d980e93
Binary files /dev/null and b/public/loading.gif differ
diff --git a/public/loading1.gif b/public/loading1.gif
new file mode 100644
index 0000000..03c0ee4
Binary files /dev/null and b/public/loading1.gif differ
diff --git a/src/components/Loading/loadingSpin.tsx b/src/components/Loading/loadingSpin.tsx
new file mode 100644
index 0000000..852abfd
--- /dev/null
+++ b/src/components/Loading/loadingSpin.tsx
@@ -0,0 +1,65 @@
+/*
+ * @Author: zhoux zhouxia@supervision.ltd
+ * @Date: 2023-12-29 14:19:46
+ * @LastEditors: zhoux zhouxia@supervision.ltd
+ * @LastEditTime: 2023-12-29 15:31:14
+ * @FilePath: \general-ai-platform-web\src\components\Loading\loadingSpin.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+
+type LoadingSpinProps = {
+  spinning: boolean;
+  tip?: string | React.ReactNode;
+  indicator?: React.ReactNode;
+};
+/**
+ * @加载控件
+ * @param props
+ * @returns
+ */
+const LoadingSpin: React.FC<LoadingSpinProps> = (props) => {
+  return props.spinning ? (
+    <div
+      style={{
+        background: 'transparent',
+        position: 'fixed',
+        left: 0,
+        top: 0,
+        width: '100vw',
+        height: '100vh',
+        display: 'flex',
+        alignItems: 'center',
+        justifyContent: 'center',
+        zIndex: 999,
+        backgroundColor: 'rgba(0,0,0, 0.3)',
+        color: 'white',
+      }}
+    >
+      <div
+        style={{
+          backgroundColor: 'white',
+          borderRadius: 12,
+          width: 361,
+          height: 216,
+          display: 'flex',
+          alignItems: 'center',
+          justifyContent: 'center',
+          flexDirection: 'column',
+          color: '#154DDD'
+        }}
+      >
+        {props.indicator ? (
+          props.indicator
+        ) : (
+          <img style={{ width: 120 }} src="/loading1.gif" alt="" />
+        )}
+
+        <p style={{padding: 8, margin: 0}}>{props.tip || '请稍候...'}</p>
+      </div>
+    </div>
+  ) : (
+    <></>
+  );
+};
+
+export default LoadingSpin;
diff --git a/src/components/TableActionCard/isModalDelete.tsx b/src/components/TableActionCard/isModalDelete.tsx
new file mode 100644
index 0000000..0b43c15
--- /dev/null
+++ b/src/components/TableActionCard/isModalDelete.tsx
@@ -0,0 +1,45 @@
+/*
+ * @Author: zhoux zhouxia@supervision.ltd
+ * @Date: 2023-12-27 10:30:10
+ * @LastEditors: zhoux zhouxia@supervision.ltd
+ * @LastEditTime: 2023-12-27 11:06:00
+ * @FilePath: \general-ai-platform-web\src\components\TableActionCard\isModalDelete.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import { useIntl } from '@umijs/max';
+import modal from 'antd/es/modal';
+
+type IsModalDeleteProps = {
+  deleteButton: React.ReactNode;
+  deleteApi: () => void;
+  titleText?: string;
+  contentText?: string;
+};
+
+const IsModalDelete: React.FC<IsModalDeleteProps> = (props) => {
+  const intl = useIntl();
+  const confirm = () => {
+    modal.confirm({
+      title: props.titleText || `确认删除吗?`,
+      icon: <ExclamationCircleOutlined />,
+      content: props.contentText || '确认删除吗?删除后将无法找回,请谨慎操作。',
+      okText: intl.formatMessage({ id: 'common.okText', defaultMessage: '$$$' }),
+      cancelText: intl.formatMessage({ id: 'common.cancelText', defaultMessage: '$$$' }),
+      onOk() {
+        props.deleteApi();
+      },
+      onCancel() {
+        console.log('Cancel');
+      },
+    });
+  };
+
+  return (
+    <>
+      <span onClick={() => confirm()}>{props.deleteButton}</span>
+    </>
+  );
+};
+
+export default IsModalDelete;
diff --git a/src/global.css b/src/global.css
index 9c37e64..1e7f45d 100644
--- a/src/global.css
+++ b/src/global.css
@@ -166,7 +166,7 @@ a.ant-dropdown-trigger {
 .ant-modal-body .ant-pro-steps-form-steps-container {
   max-width: 1900px !important;
 }
-/* 列表table && proTable */
+/* 列表 ProTable && ProList */
 .ant-pro-table .ant-pro-table-list-toolbar-left {
   flex: 0.3;
 }
@@ -181,6 +181,22 @@ a.ant-dropdown-trigger {
 .ant-pro-list .ant-pro-table-list-toolbar-left {
   flex: 1;
 }
+/*表单 ProFrom */
+.ant-btn-dashed {
+  border-radius: 4px;
+  border: 1px dashed #154DDD;
+  background: rgba(21, 91, 212, 0.05);
+  color: #154DDD;
+}
+.ant-pro-form-list-action {
+  margin-block-end: 16px;
+}
+.ant-pro-form-list .ant-pro-form-list-action .action-copy {
+  color: #154DDD;
+}
+.ant-pro-form-list .ant-pro-form-list-action .action-remove {
+  color: #E80D0D;
+}
 .ant-popover .ant-popover-content {
   min-width: 200px;
 }
@@ -360,6 +376,11 @@ a.ant-dropdown-trigger {
   background: rgba(21, 77, 221, 0.1);
   color: #154DDD;
 }
+.gn.tabAction_box_wrap .ant-btn-primary {
+  border: 1px solid #154DDD;
+  background: rgba(21, 77, 221, 0.1);
+  color: #154DDD;
+}
 .ant-pro-global-header-logo img {
   height: 48px;
 }
diff --git a/src/global.less b/src/global.less
index 7f48f2b..e58c77f 100644
--- a/src/global.less
+++ b/src/global.less
@@ -204,7 +204,7 @@ a.ant-dropdown-trigger{
 .ant-modal-body .ant-pro-steps-form-steps-container{
   max-width: 1900px !important;
 }
-/* 列表table && proTable */
+/* 列表 ProTable && ProList */
 // proTable 
 .ant-pro-table{
   // 标题栏左侧文字最大弹性占比
@@ -221,8 +221,7 @@ a.ant-dropdown-trigger{
   }
 }
 
-// proList
-
+// proList 
 .ant-pro-list{
   .ant-pro-query-filter.ant-pro-query-filter {
     background-color: white;
@@ -233,7 +232,29 @@ a.ant-dropdown-trigger{
   .ant-pro-table-list-toolbar-left{
     flex: 1
   }
+}
+/*表单 ProFrom */
+.ant-btn-dashed{
+  border-radius: 4px;
+  border: 1px dashed #154DDD;
+  background: rgba(21, 91, 212, 0.05);
+  color: #154DDD;
+}
 
+.ant-pro-form-list-action {
+  margin-block-end: 16px;
+}
+
+// ProFormList
+.ant-pro-form-list{
+  .ant-pro-form-list-action{
+    .action-copy{
+      color: #154DDD;
+    }
+    .action-remove {
+      color: #E80D0D;
+    }
+  }
 }
 
 // 气泡框
@@ -475,6 +496,15 @@ a.ant-dropdown-trigger{
     //   }
     // }
   }
+
+  // 自定义切换按钮样式
+  &.tabAction_box_wrap{
+    .ant-btn-primary{
+      border: 1px solid #154DDD;
+      background: rgba(21, 77, 221, 0.10);
+      color: #154DDD;
+    }
+  }
 }
 .ant-pro-global-header-logo img {
   height: 48px;
@@ -508,3 +538,6 @@ a.ant-dropdown-trigger{
 
 
 
+
+
+
diff --git a/src/locales/zh-CN/alarm.ts b/src/locales/zh-CN/alarm.ts
index ba17d53..274fe31 100644
--- a/src/locales/zh-CN/alarm.ts
+++ b/src/locales/zh-CN/alarm.ts
@@ -2,11 +2,10 @@
  * @Author: zhoux zhouxia@supervision.ltd
  * @Date: 2023-12-18 16:36:36
  * @LastEditors: zhoux zhouxia@supervision.ltd
- * @LastEditTime: 2023-12-22 16:58:28
+ * @LastEditTime: 2023-12-27 09:30:24
  * @FilePath: \general-ai-platform-web\src\locales\zh-CN\alarm.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
-
 // 设备列表
 export const alarm_list: { [key: string]: string } = {
     'alarm.list.table.list.id': 'ID',
@@ -29,6 +28,23 @@ export const alarm_setting: { [key: string]: string } = {
     'alarm.setting.table.model.alarmStatusSetting': '告警等级',
     'alarm.list.table.list.deviceGroup': '设备组',
     'alarm.list.table.list.alarmTime': '告警时间',
+    'alarm.setting.table.list.rule.required.name': '请填写告警名称',
+
+}  
+
+// 设备状态
+export const alarm_ways: { [key: string]: string } = {
+    'alarm.ways.page.name': '告警方式',
+    'alarm.ways.page.title': '告警方式设置',
+    'alarm.ways.page.add': '新建告警方式',
+    'alarm.ways.page.empty.des': '暂无告警方式',
+    'alarm.ways.page.model.name': '告警方式名称',
+    'alarm.ways.page.form.serviceName': '第三方服务商',
+    'alarm.ways.page.form.params': '服务商参数',
+    'alarm.ways.page.form.template': '通知模板',
+
 
+    'alarm.ways.page.model.rule.required.name': '请填写告警方式名称',
+    
 
 }  
\ No newline at end of file
diff --git a/src/locales/zh-CN/common.ts b/src/locales/zh-CN/common.ts
index 4167c4d..45e7c00 100644
--- a/src/locales/zh-CN/common.ts
+++ b/src/locales/zh-CN/common.ts
@@ -2,15 +2,15 @@
  * @Author: zhoux zhouxia@supervision.ltd
  * @Date: 2023-11-01 13:56:33
  * @LastEditors: zhoux zhouxia@supervision.ltd
- * @LastEditTime: 2023-11-03 16:33:59
+ * @LastEditTime: 2023-12-27 11:06:30
  * @FilePath: \general-ai-platform-web\src\locales\zh-CN\common.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
 export default {
   'common.modal.table.update.title': '更新表单',
   'common.modal.table.create.title': '新增表单',
-  'common.modal.table.delete.title': '确定要删除吗?',
-  'common.modal.table.delete.content': '确定删除吗,删除后将无法找回,请谨慎操作',
+  'common.modal.table.delete.title': '确认要删除吗?',
+  'common.modal.table.delete.content': '确认删除吗,删除后将无法找回,请谨慎操作',
   'common.enable': '开启',
   'common.disable': '禁用',
   'common.yes': '是',
@@ -46,4 +46,8 @@ export default {
   'common.open_failure': '打开失败',
   'common.start_process': '开始运行',
   'common.finish_process': '关闭运行',
+  'common.save': '保存',
+  'common.delete': '删除',
+  'common.okText': '确认',
+  'common.cancelText': '取消',
 }
diff --git a/src/pages/Alarm/AlarmList/components/ColumnDrawer.tsx b/src/pages/Alarm/AlarmList/components/ColumnDrawer.tsx
deleted file mode 100644
index 208d446..0000000
--- a/src/pages/Alarm/AlarmList/components/ColumnDrawer.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from "react";
-import {Drawer} from "antd";
-import {ProColumns, ProDescriptions, ProDescriptionsItemProps} from "@ant-design/pro-components";
-
-export type ColumnDrawProps = {
-  handleDrawer: (id?: any)=>void;
-  isShowDetail: boolean;
-  columns: ProColumns<API.DeviceCategory>[];
-  currentRow: API.DeviceCategory | undefined;
-};
-
-
-const ColumnDrawer: React.FC<ColumnDrawProps> = (props) => {
-
-  return (
-    <Drawer
-      width={500}
-      open={props.isShowDetail}
-      onClose={() => {
-        props.handleDrawer();
-      }}
-      closable={true}
-    >
-      {props.currentRow?.id && (
-        <ProDescriptions<API.DeviceCategory>
-          column={2}
-          title={props.currentRow?.id}
-          request={async () => ({
-            data: props.currentRow || {},
-          })}
-          params={{
-            id: props.currentRow?.id,
-          }}
-          columns={props.columns as ProDescriptionsItemProps<API.DeviceCategory>[]}
-        />
-      )}
-    </Drawer>
-  )
-}
-export {ColumnDrawer}
-
diff --git a/src/pages/Alarm/AlarmList/components/Columns.tsx b/src/pages/Alarm/AlarmList/components/Columns.tsx
deleted file mode 100644
index 90f714b..0000000
--- a/src/pages/Alarm/AlarmList/components/Columns.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { FormattedMessage} from '@umijs/max';
-export const DeviceCategoryColumns = [{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.id"
-               defaultMessage="$$$"/>),
-           dataIndex: "id",
-       },{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.name"
-               defaultMessage="$$$"/>),
-           dataIndex: "name",
-       },{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.code"
-               defaultMessage="$$$"/>),
-           dataIndex: "code",
-       },{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.remark"
-               defaultMessage="$$$"/>),
-           dataIndex: "remark",
-       },{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.createTime"
-               defaultMessage="$$$"/>),
-           dataIndex: "create_time",
-       },{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.updateTime"
-               defaultMessage="$$$"/>),
-           dataIndex: "update_time",
-       },]
diff --git a/src/pages/Alarm/AlarmList/components/CreateForm.tsx b/src/pages/Alarm/AlarmList/components/CreateForm.tsx
deleted file mode 100644
index 137116e..0000000
--- a/src/pages/Alarm/AlarmList/components/CreateForm.tsx
+++ /dev/null
@@ -1,143 +0,0 @@
-import { postDeviceCategoryCreateDeviceCategory } from '@/services/device/DeviceCategory';
-import { ModalForm, ProForm, ProFormText } from '@ant-design/pro-components';
-import { FormattedMessage, useIntl } from '@umijs/max';
-import { Form, Switch, message } from 'antd';
-import React, { useState } from 'react';
-import {
-  proFormSmallItemStyleProps,
-  proFormSmallModelWidth,
-} from '../../../../../config/defaultForm';
-export type FormValueType = {
-  target?: string;
-  template?: string;
-  type?: string;
-  time?: string;
-  frequency?: string;
-} & Partial<API.DeviceCategory>;
-
-export type CreateFormProps = {
-  createModalOpen: boolean;
-  handleModal: () => void;
-  values: Partial<API.DeviceCategory>;
-  reload: any;
-};
-const CreateForm: React.FC<CreateFormProps> = (props) => {
-  const intl = useIntl();
-  const [isAuto, setIsAuto] = useState(true);
-  const [form] = Form.useForm<API.DeviceCategory>();
-
-  return (
-    <ModalForm<API.DeviceCategory>
-      width={proFormSmallModelWidth}
-      title={intl.formatMessage({
-        id: 'DCSDeviceList.device_category.table.list.add',
-        defaultMessage: '$$$',
-      })}
-      open={props.createModalOpen}
-      form={form}
-      autoFocusFirstInput
-      modalProps={{
-        destroyOnClose: true,
-        onCancel: () => props.handleModal(),
-      }}
-      submitTimeout={2000}
-      onFinish={async (values) => {
-        postDeviceCategoryCreateDeviceCategory(values)
-          .then(() => {
-            message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '$$$' }));
-            props.reload();
-          })
-          .catch(() => {
-            message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '$$$' }));
-          });
-        props.handleModal();
-        return true;
-      }}
-    >
-      <ProForm.Group>
-        <ProFormText
-          width={proFormSmallItemStyleProps.width}
-          name="name"
-          label={
-            <FormattedMessage id="DCSDeviceList.device_category.table.list.name" defaultMessage="$$$" />
-          }
-          placeholder={`${intl.formatMessage({
-            id: 'common.please_input',
-            defaultMessage: '$$$',
-          })}${intl.formatMessage({
-            id: 'DCSDeviceList.device_category.table.list.name',
-            defaultMessage: '$$$',
-          })}`}
-          required={true}
-          rules={[
-            {
-              required: true,
-              message: (
-                <FormattedMessage
-                  id="DCSDeviceList.device_category.table.rule.required.name"
-                  defaultMessage="name is required"
-                />
-              ),
-            },
-          ]}
-        />
-        <ProFormText
-          width="lg"
-          name="code"
-          label={
-            <FormattedMessage id="DCSDeviceList.device_category.table.list.code" defaultMessage="$$$" />
-          }
-          placeholder={`${intl.formatMessage({
-            id: 'common.please_input',
-            defaultMessage: '$$$',
-          })}${intl.formatMessage({
-            id: 'DCSDeviceList.device_category.table.list.code',
-            defaultMessage: '$$$',
-          })}`}
-          required={!isAuto}
-          initialValue=""
-          disabled={isAuto}
-          rules={
-            isAuto
-              ? []
-              : [
-                  {
-                    required: true,
-                    message: (
-                      <FormattedMessage
-                        id="DCSDeviceList.device_category.table.rule.required.code"
-                        defaultMessage="code is required"
-                      />
-                    ),
-                  },
-                ]
-          }
-          addonAfter={
-            <Switch
-              checked={isAuto}
-              checkedChildren={<FormattedMessage id="common.auto" defaultMessage="$$$" />}
-              unCheckedChildren={<FormattedMessage id="common.edit" defaultMessage="$$$" />}
-              onChange={setIsAuto}
-            />
-          }
-        />
-        <ProFormText
-          width={proFormSmallItemStyleProps.width}
-          name="remark"
-          label={
-            <FormattedMessage id="DCSDeviceList.device_category.table.list.remark" defaultMessage="$$$" />
-          }
-          placeholder={`${intl.formatMessage({
-            id: 'common.please_input',
-            defaultMessage: '$$$',
-          })}${intl.formatMessage({
-            id: 'DCSDeviceList.device_category.table.list.remark',
-            defaultMessage: '$$$',
-          })}`}
-          required={false}
-        />
-      </ProForm.Group>
-    </ModalForm>
-  );
-};
-export default CreateForm;
diff --git a/src/pages/Alarm/AlarmList/components/UpdateForm.tsx b/src/pages/Alarm/AlarmList/components/UpdateForm.tsx
deleted file mode 100644
index 64ea0c0..0000000
--- a/src/pages/Alarm/AlarmList/components/UpdateForm.tsx
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * @Author: zhoux zhouxia@supervision.ltd
- * @Date: 2023-11-01 13:56:33
- * @LastEditors: zhoux zhouxia@supervision.ltd
- * @LastEditTime: 2023-11-17 10:12:53
- * @FilePath: \general-ai-platform-web\src\pages\Device\DeviceCategoryList\components\UpdateForm.tsx
- * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
- */
-import { putDeviceCategoryUpdateDeviceCategory } from '@/services/device/DeviceCategory';
-import { ModalForm, ProForm, ProFormDateTimePicker, ProFormText } from '@ant-design/pro-components';
-import { FormattedMessage, useIntl } from '@umijs/max';
-import { Form, message } from 'antd';
-import { proFormItemStyleProps, proFormModelWidth } from '../../../../../config/defaultForm';
-import React from 'react';
-export type FormValueType = {
-  target?: string;
-  template?: string;
-  type?: string;
-  time?: string;
-  frequency?: string;
-} & Partial<API.DeviceCategory>;
-
-export type UpdateFormProps = {
-  updateModalOpen: boolean;
-  handleModal: () => void;
-  values: Partial<API.DeviceCategory>;
-  reload: any;
-};
-const UpdateForm: React.FC<UpdateFormProps> = (props) => {
-  const intl = useIntl();
-  const [form] = Form.useForm<API.DeviceCategory>();
-
-  return (
-    <ModalForm<API.DeviceCategory>
-    width={proFormModelWidth}
-      title={intl.formatMessage({
-        id: 'DCSDeviceList.device_category.table.list.update',
-        defaultMessage: '$$$',
-      })}
-      open={props.updateModalOpen}
-      form={form}
-      autoFocusFirstInput
-      modalProps={{
-        destroyOnClose: true,
-        onCancel: () => props.handleModal(),
-      }}
-      submitTimeout={2000}
-      onFinish={async (values) => {
-        putDeviceCategoryUpdateDeviceCategory(values)
-          .then(() => {
-            message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '$$$' }));
-            props.reload();
-          })
-          .catch(() => {
-            message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '$$$' }));
-          });
-
-        props.handleModal();
-        return true;
-      }}
-    >
-      <ProForm.Group>
-        <ProFormText
-          width={proFormItemStyleProps.column2Width}
-          name="id"
-          label="id"
-          disabled={true}
-          initialValue={props.values.id}
-        />
-        <ProFormText
-          width={proFormItemStyleProps.column2Width}
-          name="name"
-          label={
-            <FormattedMessage id="DCSDeviceList.device_category.table.list.name" defaultMessage="$$$" />
-          }
-          placeholder={`${intl.formatMessage({
-            id: 'common.please_input',
-            defaultMessage: '$$$',
-          })}${intl.formatMessage({
-            id: 'DCSDeviceList.device_category.table.list.name',
-            defaultMessage: '$$$',
-          })}`}
-          required={true}
-          initialValue={props.values.name}
-          disabled={false}
-          rules={[
-            {
-              required: true,
-              message: (
-                <FormattedMessage
-                  id="DCSDeviceList.device_category.table.rule.required.name"
-                  defaultMessage="name is required"
-                />
-              ),
-            },
-          ]}
-        />
-        <ProFormText
-          width={proFormItemStyleProps.column2Width}
-          name="code"
-          label={
-            <FormattedMessage id="DCSDeviceList.device_category.table.list.code" defaultMessage="$$$" />
-          }
-          placeholder={`${intl.formatMessage({
-            id: 'common.please_input',
-            defaultMessage: '$$$',
-          })}${intl.formatMessage({
-            id: 'DCSDeviceList.device_category.table.list.code',
-            defaultMessage: '$$$',
-          })}`}
-          required={true}
-          initialValue={props.values.code}
-          disabled={false}
-          rules={[
-            {
-              required: true,
-              message: (
-                <FormattedMessage
-                  id="DCSDeviceList.device_category.table.rule.required.code"
-                  defaultMessage="code is required"
-                />
-              ),
-            },
-          ]}
-        />
-        <ProFormText
-          width={proFormItemStyleProps.column2Width}
-          name="remark"
-          label={
-            <FormattedMessage id="DCSDeviceList.device_category.table.list.remark" defaultMessage="$$$" />
-          }
-          placeholder={`${intl.formatMessage({
-            id: 'common.please_input',
-            defaultMessage: '$$$',
-          })}${intl.formatMessage({
-            id: 'DCSDeviceList.device_category.table.list.remark',
-            defaultMessage: '$$$',
-          })}`}
-          required={false}
-          initialValue={props.values.remark}
-          disabled={false}
-        />
-        <ProFormDateTimePicker
-          width={proFormItemStyleProps.column2Width}
-          name="createTime"
-          label={
-            <FormattedMessage
-              id="DCSDeviceList.device_category.table.list.createTime"
-              defaultMessage="$$$"
-            />
-          }
-          placeholder={`${intl.formatMessage({
-            id: 'common.please_input',
-            defaultMessage: '$$$',
-          })}${intl.formatMessage({
-            id: 'DCSDeviceList.device_category.table.list.createTime',
-            defaultMessage: '$$$',
-          })}`}
-          required={false}
-          initialValue={props.values.createTime}
-          disabled={true}
-        />
-        <ProFormDateTimePicker
-          width={proFormItemStyleProps.column2Width}
-          name="updateTime"
-          label={
-            <FormattedMessage
-              id="DCSDeviceList.device_category.table.list.updateTime"
-              defaultMessage="$$$"
-            />
-          }
-          placeholder={`${intl.formatMessage({
-            id: 'common.please_input',
-            defaultMessage: '$$$',
-          })}${intl.formatMessage({
-            id: 'DCSDeviceList.device_category.table.list.updateTime',
-            defaultMessage: '$$$',
-          })}`}
-          required={false}
-          initialValue={props.values.updateTime}
-          disabled={true}
-        />
-      </ProForm.Group>
-    </ModalForm>
-  );
-};
-export default UpdateForm;
diff --git a/src/pages/Alarm/AlarmSetting/components/Columns.tsx b/src/pages/Alarm/AlarmSetting/components/Columns.tsx
deleted file mode 100644
index 90f714b..0000000
--- a/src/pages/Alarm/AlarmSetting/components/Columns.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { FormattedMessage} from '@umijs/max';
-export const DeviceCategoryColumns = [{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.id"
-               defaultMessage="$$$"/>),
-           dataIndex: "id",
-       },{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.name"
-               defaultMessage="$$$"/>),
-           dataIndex: "name",
-       },{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.code"
-               defaultMessage="$$$"/>),
-           dataIndex: "code",
-       },{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.remark"
-               defaultMessage="$$$"/>),
-           dataIndex: "remark",
-       },{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.createTime"
-               defaultMessage="$$$"/>),
-           dataIndex: "create_time",
-       },{
-           title: (<FormattedMessage
-               id="DCSDeviceList.device_category.table.list.updateTime"
-               defaultMessage="$$$"/>),
-           dataIndex: "update_time",
-       },]
diff --git a/src/pages/Alarm/AlarmSetting/components/CreateForm.tsx b/src/pages/Alarm/AlarmSetting/components/CreateForm.tsx
index 4fbffd3..840c1ed 100644
--- a/src/pages/Alarm/AlarmSetting/components/CreateForm.tsx
+++ b/src/pages/Alarm/AlarmSetting/components/CreateForm.tsx
@@ -74,7 +74,7 @@ const CreateForm: React.FC<CreateFormProps> = (props) => {
               required: true,
               message: (
                 <FormattedMessage
-                  id="DCSDeviceList.device_category.table.rule.required.name"
+                  id="alarm.setting.table.list.rule.required.name"
                   defaultMessage="name is required"
                 />
               ),
diff --git a/src/pages/Alarm/AlarmSetting/components/UpdateForm.tsx b/src/pages/Alarm/AlarmSetting/components/UpdateForm.tsx
index 1c022a6..e008673 100644
--- a/src/pages/Alarm/AlarmSetting/components/UpdateForm.tsx
+++ b/src/pages/Alarm/AlarmSetting/components/UpdateForm.tsx
@@ -2,7 +2,7 @@
  * @Author: zhoux zhouxia@supervision.ltd
  * @Date: 2023-11-01 13:56:33
  * @LastEditors: zhoux zhouxia@supervision.ltd
- * @LastEditTime: 2023-12-19 13:46:07
+ * @LastEditTime: 2023-12-26 15:01:08
  * @FilePath: \general-ai-platform-web\src\pages\Device\DeviceCategoryList\components\UpdateForm.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -83,7 +83,7 @@ const UpdateForm: React.FC<UpdateFormProps> = (props) => {
               required: true,
               message: (
                 <FormattedMessage
-                  id="DCSDeviceList.device_category.table.rule.required.name"
+                  id="alarm.setting.table.list.rule.required.name"
                   defaultMessage="name is required"
                 />
               ),
diff --git a/src/pages/Alarm/AlarmSetting/components/alarmStatusForm.tsx b/src/pages/Alarm/AlarmSetting/components/alarmStatusForm.tsx
index 0cf347c..0ef3ce9 100644
--- a/src/pages/Alarm/AlarmSetting/components/alarmStatusForm.tsx
+++ b/src/pages/Alarm/AlarmSetting/components/alarmStatusForm.tsx
@@ -141,6 +141,7 @@ const AlarmStatusForm: React.FC<CreateFormProps> = (props) => {
                   <DeleteOutlined
                     style={{
                       color: 'rgba(232, 13, 13, 1)',
+                      fontSize: 16
                     }}
                   />
                 </div>
diff --git a/src/pages/Alarm/AlarmSetting/index.tsx b/src/pages/Alarm/AlarmSetting/index.tsx
index 50eca73..9362983 100644
--- a/src/pages/Alarm/AlarmSetting/index.tsx
+++ b/src/pages/Alarm/AlarmSetting/index.tsx
@@ -219,26 +219,26 @@ const DeviceCategoryList: React.FC = () => {
           persistenceKey: 'device_category_list',
           persistenceType: 'localStorage',
         }}
-        tableAlertOptionRender={() => {
-          return (
-            <>
-              {selectedRowsState?.length > 0 && (
-                <IsBatchDelete
-                  deleteApi={() => {
-                    // TODO 需要;联调删除接口
-                    deleteDeviceCategoryDeleteDeviceCategoryByIds({
-                      ids: selectedRowsState.map((v: API.DeviceCategory) => {
-                        return v.id as number;
-                      }),
-                    }).then(() => {
-                      actionRef.current?.reloadAndRest?.();
-                    });
-                  }}
-                />
-              )}
-            </>
-          );
-        }}
+        // tableAlertOptionRender={() => {
+        //   return (
+        //     <>
+        //       {selectedRowsState?.length > 0 && (
+        //         <IsBatchDelete
+        //           deleteApi={() => {
+        //             // TODO 需要;联调删除接口
+        //             deleteDeviceCategoryDeleteDeviceCategoryByIds({
+        //               ids: selectedRowsState.map((v: API.DeviceCategory) => {
+        //                 return v.id as number;
+        //               }),
+        //             }).then(() => {
+        //               actionRef.current?.reloadAndRest?.();
+        //             });
+        //           }}
+        //         />
+        //       )}
+        //     </>
+        //   );
+        // }}
         toolBarRender={() => [
           <Access
             accessible={access.canUpdate(history.location.pathname)}
diff --git a/src/pages/Alarm/AlarmWays/components/CreateForm.tsx b/src/pages/Alarm/AlarmWays/components/CreateForm.tsx
new file mode 100644
index 0000000..05c14c8
--- /dev/null
+++ b/src/pages/Alarm/AlarmWays/components/CreateForm.tsx
@@ -0,0 +1,95 @@
+/*
+ * @Author: zhoux zhouxia@supervision.ltd
+ * @Date: 2023-12-26 14:46:35
+ * @LastEditors: zhoux zhouxia@supervision.ltd
+ * @LastEditTime: 2023-12-26 14:58:36
+ * @FilePath: \general-ai-platform-web\src\pages\Alarm\AlarmWays\components\CreateForm.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import { ModalForm, ProForm, ProFormText } from '@ant-design/pro-components';
+import { FormattedMessage, useIntl } from '@umijs/max';
+import { Form } from 'antd';
+import React from 'react';
+import {
+  proFormSmallItemStyleProps,
+  proFormSmallModelWidth,
+} from '../../../../../config/defaultForm';
+// TODO 需要根据接口替换API.DeviceCategory
+export type FormValueType = {
+  target?: string;
+  template?: string;
+  type?: string;
+  time?: string;
+  frequency?: string;
+} & Partial<API.DeviceCategory>;
+
+export type CreateFormProps = {
+  createModalOpen: boolean;
+  handleModal: () => void;
+  reload: any;
+};
+const CreateForm: React.FC<CreateFormProps> = (props) => {
+  const intl = useIntl();
+  // const [isAuto, setIsAuto] = useState(true);
+  const [form] = Form.useForm<API.DeviceCategory>();
+
+  return (
+    <ModalForm<API.DeviceCategory>
+      width={proFormSmallModelWidth}
+      title={intl.formatMessage({
+        id: 'alarm.ways.page.add',
+        defaultMessage: '$$$',
+      })}
+      open={props.createModalOpen}
+      form={form}
+      autoFocusFirstInput
+      modalProps={{
+        destroyOnClose: true,
+        onCancel: () => props.handleModal(),
+      }}
+      submitTimeout={2000}
+      onFinish={async (values) => {
+        // TODO 需要对接新增告警方式接口
+        console.log('onFinish_values', values);
+        // postDeviceCategoryCreateDeviceCategory(values)
+        //   .then(() => {
+        //     message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '$$$' }));
+        //     props.reload();
+        //   })
+        //   .catch(() => {
+        //     message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '$$$' }));
+        //   });
+        props.handleModal();
+        return true;
+      }}
+    >
+      <ProForm.Group>
+        <ProFormText
+          width={proFormSmallItemStyleProps.width}
+          name="name"
+          label={<FormattedMessage id="alarm.ways.page.model.name" defaultMessage="$$$" />}
+          placeholder={`${intl.formatMessage({
+            id: 'common.please_input',
+            defaultMessage: '$$$',
+          })}${intl.formatMessage({
+            id: 'alarm.ways.page.model.name',
+            defaultMessage: '$$$',
+          })}`}
+          required={true}
+          rules={[
+            {
+              required: true,
+              message: (
+                <FormattedMessage
+                  id="alarm.ways.page.model.rule.required.name"
+                  defaultMessage="name is required"
+                />
+              ),
+            },
+          ]}
+        />
+      </ProForm.Group>
+    </ModalForm>
+  );
+};
+export default CreateForm;
diff --git a/src/pages/Alarm/AlarmWays/components/UpdateForm.tsx b/src/pages/Alarm/AlarmWays/components/UpdateForm.tsx
new file mode 100644
index 0000000..639cb43
--- /dev/null
+++ b/src/pages/Alarm/AlarmWays/components/UpdateForm.tsx
@@ -0,0 +1,169 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+/*
+ * @Author: zhoux zhouxia@supervision.ltd
+ * @Date: 2023-11-01 13:56:33
+ * @LastEditors: zhoux zhouxia@supervision.ltd
+ * @LastEditTime: 2023-12-28 14:38:52
+ * @FilePath: \general-ai-platform-web\src\pages\Device\DeviceCategoryList\components\UpdateForm.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import { postDeviceGroupGetDeviceGroupFkSelect } from '@/services/device/DeviceGroup';
+import { CloseOutlined, SnippetsOutlined } from '@ant-design/icons';
+import {
+  ProForm,
+  ProFormList,
+  ProFormSelect,
+  ProFormText,
+  ProFormTextArea,
+} from '@ant-design/pro-components';
+import { FormattedMessage, useIntl } from '@umijs/max';
+import { Form } from 'antd';
+import React, { forwardRef, useEffect, useImperativeHandle } from 'react';
+import {
+  proFormListActionButtonProps,
+  proFormListCreatorButtonProps,
+  proFormSmallItemStyleProps,
+} from '../../../../../config/defaultForm';
+export type FormValueType = {
+  target?: string;
+  template?: string;
+  type?: string;
+  time?: string;
+  frequency?: string;
+} & Partial<API.DeviceCategory>;
+
+export type UpdateFormProps = {
+  ref: any;
+  values: Record<string, any>;
+  reload: any;
+};
+const UpdateForm = forwardRef((props: UpdateFormProps, ref: React.Ref<any> | undefined) => {
+  const intl = useIntl();
+  const [form] = Form.useForm<API.DeviceCategory>();
+  //   modalProps={{
+  //     destroyOnClose: true,
+  //     onCancel: () => props.handleModal(),
+  //   }}
+  //       submitTimeout={2000}
+
+  // 最关键的代码: 第二个参数返回一个对象 —— 定义 父组件可以调用这个组件 的方法
+  const initSubmitForm = () => {
+    console.log('调用子组件方法', form);
+    form.submit();
+  };
+
+  useImperativeHandle(
+    ref,
+    () => ({
+      initSubmitForm,
+    }),
+    [],
+  );
+  // 数据变更给表单设置初始值
+  useEffect(() => {
+    form.setFieldsValue({
+      ...props.values,
+    });
+  }, [props.values]);
+
+  return (
+    <div>
+      <ProForm
+        form={form}
+        autoFocusFirstInput
+        submitter={{
+          render: false, // 隐藏提交按钮
+        }}
+        onFinish={async (values) => {
+          // TODO 需要对接更新告警方式接口
+          console.log('onFinish_values', values);
+          // putDeviceCategoryUpdateDeviceCategory(values)
+          //   .then(() => {
+          //     message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '$$$' }));
+          //     props.reload();
+          //   })
+          //   .catch(() => {
+          //     message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '$$$' }));
+          //   });
+          return true;
+        }}
+      >
+        <ProFormSelect
+          width={proFormSmallItemStyleProps.width}
+          name="serviceName"
+          label={<FormattedMessage id="alarm.ways.page.form.serviceName" defaultMessage="$$$" />}
+          placeholder={`${intl.formatMessage({
+            id: 'common.please_select',
+            defaultMessage: '$$$',
+          })}${intl.formatMessage({
+            id: 'alarm.ways.page.form.serviceName',
+            defaultMessage: '$$$',
+          })}`}
+          required={false}
+          // TODO 在types中增加类型注释
+          initialValue={props.values?.serviceName}
+          debounceTime={1000}
+          request={async () => {
+            // TODO 此处需要使用告警级别接口联调
+            const resp = await postDeviceGroupGetDeviceGroupFkSelect({});
+            return resp.data.list.map((v: any) => {
+              return {
+                label: v.name,
+                value: v.id,
+              };
+            });
+          }}
+        />
+        <ProFormList
+          style={{
+            width: proFormSmallItemStyleProps.width,
+          }}
+          copyIconProps={{
+            Icon: SnippetsOutlined,
+          }}
+          deleteIconProps={{
+            Icon: CloseOutlined,
+          }}
+          initialValue={props.values?.params}
+          name="params"
+          label= {<span className='h3 gn'><FormattedMessage id="alarm.ways.page.form.params" defaultMessage="$$$" /></span>}
+
+          creatorButtonProps={proFormListCreatorButtonProps}
+           {
+            ...proFormListActionButtonProps
+           }
+        >
+          {(f, index, action) => {
+            return (
+              <div
+                style={{
+                  display: 'flex',
+                  justifyContent: 'space-between',
+                  width: proFormSmallItemStyleProps.width - 44,
+                }}
+              >
+                <ProFormText width={229} key="name" name="name" label="键名" />
+                <ProFormText width={229} key="default" name="default" label="默认值" />
+              </div>
+            );
+          }}
+        </ProFormList>
+        <ProFormTextArea
+          name="template"
+          label={<FormattedMessage id="alarm.ways.page.form.template" defaultMessage="$$$" />}
+          placeholder={`${intl.formatMessage({
+            id: 'common.please_input',
+            defaultMessage: '$$$',
+          })}${intl.formatMessage({
+            id: 'alarm.ways.page.form.template',
+            defaultMessage: '$$$',
+          })}`}
+          required={false}
+          initialValue={props.values?.template}
+          disabled={false}
+        />
+      </ProForm>
+    </div>
+  );
+});
+export default UpdateForm;
diff --git a/src/pages/Alarm/AlarmWays/index.tsx b/src/pages/Alarm/AlarmWays/index.tsx
new file mode 100644
index 0000000..97f18d9
--- /dev/null
+++ b/src/pages/Alarm/AlarmWays/index.tsx
@@ -0,0 +1,222 @@
+import { FormattedMessage } from '@/.umi/plugin-locale';
+import IsModalDelete from '@/components/TableActionCard/isModalDelete';
+import { PageContainer, ProCard } from '@ant-design/pro-components';
+import { Button, Empty } from 'antd';
+import { useEffect, useRef, useState } from 'react';
+import CreateForm from './components/CreateForm';
+import UpdateForm from './components/UpdateForm';
+
+/**
+ * @交互说明
+ * 1.告警方式初始状态
+ * 2.新建告警方式
+ * 3.选择告警方式、更新内容
+ * 4.删除告警方式
+ *
+ * 【*是否需要新增通知按钮】缺少新建操作
+ * 【*是否需要展示告警方式列表】展示&编辑混合
+ */
+
+const pageStyle: React.CSSProperties = {
+  minHeight: '50vh',
+};
+
+const AlarmWays: React.FC = () => {
+  const updateFormRef = useRef(null);
+
+  const [createModalOpen, setCreateModalOpen] = useState<boolean>(false);
+  //   const [updateModalOpen, setUpdateModalOpen] = useState<boolean>(false);
+  const [activeTabId, setActiveTabId] = useState<string>('0');
+  const [waysList, setWaysList] = useState<Record<string, any>[]>([
+    {
+      name: '短信通知',
+      id: '0',
+      serviceName: 4,
+      params: [
+        {
+          name: 'name1',
+          default: 'default1',
+        },
+      ],
+      template: '123',
+    },
+    {
+      name: '电话通知',
+      id: '1',
+      serviceName: 2,
+      params: [
+        {
+          name: 'name11',
+          default: 'default11',
+        },
+        {
+          name: 'name12',
+          default: 'default12',
+        },
+      ],
+      template: '456',
+    },
+    {
+      name: '邮件通知',
+      id: '2',
+      serviceName: '',
+      params: [],
+      template: '',
+    },
+    {
+      name: '微信通知',
+      id: '3',
+      serviceName: '',
+      params: [],
+      template: '',
+    },
+  ]);
+  const [currentRow, setCurrentRow] = useState<Record<string, any> | undefined>({});
+
+  //   const handleUpdateModal = () => {
+  //     if (updateModalOpen) {
+  //       setUpdateModalOpen(false);
+  //       setCurrentRow(undefined);
+  //     } else {
+  //       setUpdateModalOpen(true);
+  //     }
+  //   };
+  const handleCreateModal = () => {
+    if (createModalOpen) {
+      setCreateModalOpen(false);
+      setCurrentRow(undefined);
+    } else {
+      setCreateModalOpen(true);
+    }
+  };
+
+  // 加载告警方式详情
+  function loadDetail() {
+    const currRow = waysList.find((item) => item.id === activeTabId);
+    setCurrentRow(() => currRow);
+    console.log(currRow, 'loadDetail', currentRow);
+  }
+
+  // 更新告警方式
+  function handleUpdate() {
+    updateFormRef.current.initSubmitForm();
+    console.log(updateFormRef.current, 'updateFormRef');
+  }
+
+  // 删除告警方式
+  function handleDelete() {
+    const waysData = waysList.filter((item) => item.id !== activeTabId);
+    setWaysList(waysData);
+    // eslint-disable-next-line @typescript-eslint/no-unused-expressions
+    waysData.length && setActiveTabId(waysData[0].id);
+  }
+
+  function handleReload() {
+    // TODO 需要调用刷新告警方式列表接口
+    // loadDetail();
+  }
+
+  useEffect(() => {
+    loadDetail();
+  }, [activeTabId]);
+
+  useEffect(() => {
+    handleReload();
+  }, []);
+
+  return (
+    <PageContainer>
+      <ProCard
+        title={<FormattedMessage id="alarm.ways.page.title" defaultMessage="$$$" />}
+        extra={
+          <Button type="primary" onClick={handleCreateModal}>
+            <FormattedMessage id="alarm.ways.page.add" defaultMessage="$$$" />
+          </Button>
+        }
+        headStyle={{
+          padding: '16px',
+          borderBottom: '1px solid  #E0E0E0',
+        }}
+        bodyStyle={{
+          ...pageStyle,
+          padding: '16px',
+          margin: 0,
+        }}
+      >
+        {waysList?.length ? (
+          <div>
+            <div className="gn tabAction_box_wrap" style={{ paddingTop: 4, marginBottom: 16 }}>
+              {waysList.map((item, index) => {
+                // eslint-disable-next-line react/jsx-key
+                return (
+                  <Button
+                    style={{ marginRight: 12 }}
+                    type={activeTabId === item.id ? 'primary' : 'default'}
+                    key={index}
+                    onClick={() => {
+                      setActiveTabId(item.id);
+                    }}
+                  >
+                    {item.name || ''}
+                  </Button>
+                );
+              })}
+            </div>
+            <UpdateForm ref={updateFormRef} values={currentRow || {}} reload={handleReload} />
+            <div
+              style={{
+                display: 'flex',
+                justifyContent: 'space-between',
+                paddingTop: 8,
+                paddingBottom: 8,
+              }}
+            >
+              <Button type="primary" onClick={handleUpdate}>
+                <FormattedMessage id="common.save" defaultMessage="$$$" />
+              </Button>
+              <IsModalDelete
+                titleText={`确认删除${currentRow?.name}吗?`}
+                contentText={`确认删除${currentRow?.name}吗?删除后将无法通过${currentRow?.name}发送告警,请谨慎操作。`}
+                deleteButton={
+                  <Button type="default" danger>
+                    <FormattedMessage id="common.delete" defaultMessage="$$$" />
+                  </Button>
+                }
+                deleteApi={handleDelete}
+              ></IsModalDelete>
+            </div>
+          </div>
+        ) : (
+          <Empty
+            style={{
+              minHeight: pageStyle.minHeight,
+              display: 'flex',
+              flexDirection: 'column',
+              alignItems: 'center',
+              justifyContent: 'center',
+            }}
+            image="https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg"
+            imageStyle={{ height: 160 }}
+            description={
+              <span>
+                <FormattedMessage id="alarm.ways.page.empty.des" defaultMessage="$$$" />
+              </span>
+            }
+          >
+            <Button type="primary" onClick={handleCreateModal}>
+              <FormattedMessage id="alarm.ways.page.add" defaultMessage="$$$" />
+            </Button>
+          </Empty>
+        )}
+      </ProCard>
+
+      <CreateForm
+        createModalOpen={createModalOpen}
+        handleModal={handleCreateModal}
+        reload={handleReload}
+      />
+    </PageContainer>
+  );
+};
+
+export default AlarmWays;
diff --git a/src/pages/FabricView/Room/components/ColumnDrawer.tsx b/src/pages/FabricView/Room/components/ColumnDrawer.tsx
index 5b4187f..d3724df 100644
--- a/src/pages/FabricView/Room/components/ColumnDrawer.tsx
+++ b/src/pages/FabricView/Room/components/ColumnDrawer.tsx
@@ -2,7 +2,7 @@
  * @Author: zhoux zhouxia@supervision.ltd
  * @Date: 2023-11-01 13:56:33
  * @LastEditors: zhoux zhouxia@supervision.ltd
- * @LastEditTime: 2023-12-15 16:58:50
+ * @LastEditTime: 2023-12-28 14:25:08
  * @FilePath: \general-ai-platform-web\src\pages\Resource\ModelCategoryList\components\ColumnDrawer.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -16,18 +16,21 @@ export type ColumnDrawProps = {
   columns: ProColumns<API.ModelCategory>[];
   currentRow: Record<string, any>;
   clipPathData: Record<string, any>;
+  canvasObject: any;
 };
 
 const ColumnDrawer: React.FC<ColumnDrawProps> = (props) => {
   const [positionStyle, setPositionStyle] = useState<React.CSSProperties>({});
   // 生成模型详情卡片位置
   function initPointPosition() {
+    const zoomIndex = 1 * props.canvasObject?.getZoom();
+
     type Point = { x: number; y: number };
     type Position = 'left' | 'right' | 'top' | 'bottom';
     let currPositionStyle: React.CSSProperties = {};
     const modelInfoPosition: Position[] = ['right'];
-    const maxX = props.clipPathData?.width; // 画布宽度
-    const maxY = props.clipPathData?.height; // 画布高度
+    const maxX = props.clipPathData?.width * zoomIndex; // 画布宽度
+    const maxY = props.clipPathData?.height * zoomIndex; // 画布高度
     const x = props.currentRow.baseInfo?.left; // 模型x轴位置
     const y = props.currentRow.baseInfo?.top; // 模型y轴位置
     const modelWidth: number = 120; // 模型自身宽度
@@ -54,24 +57,24 @@ const ColumnDrawer: React.FC<ColumnDrawProps> = (props) => {
     }
     console.log(props.currentRow, 'currentRow');
     if (modelInfoPosition.includes('left')) {
-      let topValue = y - modelInfoHeight / 2 + modelHeight / 2
-      if(topValue> maxY - modelInfoHeight){
-        topValue = maxY - modelInfoHeight
+      let topValue = y - modelInfoHeight / 2 + modelHeight / 2;
+      if (topValue > maxY - modelInfoHeight) {
+        topValue = maxY - modelInfoHeight;
       }
-      if(topValue<0){
-        topValue = 0
+      if (topValue < 0) {
+        topValue = 0;
       }
       currPositionStyle = {
         top: topValue,
         left: x - modelInfoWidth - 10,
       };
     } else {
-      let topValue = y - modelInfoHeight / 2 + modelHeight / 2
-      if(topValue> maxY - modelInfoHeight){
-        topValue = maxY - modelInfoHeight
+      let topValue = y - modelInfoHeight / 2 + modelHeight / 2;
+      if (topValue > maxY - modelInfoHeight) {
+        topValue = maxY - modelInfoHeight;
       }
-      if(topValue<0){
-        topValue = 0
+      if (topValue < 0) {
+        topValue = 0;
       }
       currPositionStyle = {
         top: topValue,
@@ -85,7 +88,7 @@ const ColumnDrawer: React.FC<ColumnDrawProps> = (props) => {
     if (props.currentRow) {
       initPointPosition();
     }
-  }, [props.currentRow, props.clipPathData]);
+  }, [props.currentRow, props.clipPathData, props.canvasObject]);
   return props.isShowDetail ? (
     <div
       style={{
diff --git a/src/pages/FabricView/Room/components/ModelTipBox.tsx b/src/pages/FabricView/Room/components/ModelTipBox.tsx
new file mode 100644
index 0000000..e07a649
--- /dev/null
+++ b/src/pages/FabricView/Room/components/ModelTipBox.tsx
@@ -0,0 +1,112 @@
+/*
+ * @Author: zhoux zhouxia@supervision.ltd
+ * @Date: 2023-12-25 16:14:04
+ * @LastEditors: zhoux zhouxia@supervision.ltd
+ * @LastEditTime: 2023-12-29 15:36:39
+ * @FilePath: \general-ai-platform-web\src\pages\FabricView\Room\components\ModelTipBox.tsx
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import { useState } from 'react';
+
+const modelOptionList: Record<string, any>[] = [
+  {
+    id: '0',
+    label: '在线',
+    status: 'watchOnline',
+    color: '#52C41A',
+  },
+  {
+    id: '1',
+    label: '离线',
+    status: 'watchOutline',
+    color: '#CCCCCC',
+  },
+  {
+    id: '2',
+    label: '故障',
+    status: 'watchWarn',
+    color: '#FAAD14',
+  },
+  {
+    id: '3',
+    label: '告警',
+    status: 'watchError',
+    color: '#E80D0D',
+  },
+];
+
+type ModelTipBoxProps = {
+  options?: Record<string, any>[]; 
+  changeStatusSelected: (arr: string[]) => void
+};
+
+const ModelTipBox: React.FC<ModelTipBoxProps> = (props) => {
+  const [selected, setSelected] = useState<string[]>([]);
+  function doSelected(options: Record<string, any>) {
+    let currSelectedArr: string[] = []
+    if (selected.includes(options.status)) {
+      currSelectedArr = selected.filter((item) => options.status != item)
+    } else {
+      currSelectedArr =  [...selected, options.status]
+    }
+    setSelected(currSelectedArr);
+    props.changeStatusSelected(currSelectedArr)
+  }
+  return (
+    <ul
+      style={{
+        display: 'flex',
+        width: 100,
+        height: 200,
+        alignItems: 'center',
+        justifyContent: 'center',
+        flexDirection: 'column',
+        background: 'white'
+      }}
+    >
+      {modelOptionList.map((item) => {
+        const activeStyle: React.CSSProperties = selected.includes(item.status)
+          ? {
+              border: '1px solid #154DDD',
+              background: '#154DDD',
+              color: 'white',
+            }
+          : {
+              border: '1px solid #DCDCDC',
+              color: '#333',
+            };
+        return (
+          <li
+            key={item.id}
+            style={{
+              display: 'flex',
+              alignItems: 'center',
+              justifyContent: 'center',
+              borderRadius: 2,
+
+              padding: '4px 6px',
+              marginBottom: 12,
+              width: 50,
+              cursor: 'pointer',
+              ...activeStyle,
+
+            }}
+            onClick={() => doSelected(item)}
+          >
+            <span
+              style={{
+                width: 6,
+                height: 6,
+                borderRadius: '50%',
+                background: item.color,
+              }}
+            ></span>
+            <span style={{ paddingLeft: 2 }}>{item.label}</span>
+          </li>
+        );
+      })}
+    </ul>
+  );
+};
+
+export default ModelTipBox;
diff --git a/src/pages/FabricView/Room/index.tsx b/src/pages/FabricView/Room/index.tsx
index a8035df..0b7e087 100644
--- a/src/pages/FabricView/Room/index.tsx
+++ b/src/pages/FabricView/Room/index.tsx
@@ -2,12 +2,11 @@
  * @Author: zhoux zhouxia@supervision.ltd
  * @Date: 2023-12-12 10:57:54
  * @LastEditors: zhoux zhouxia@supervision.ltd
- * @LastEditTime: 2023-12-15 17:06:36
+ * @LastEditTime: 2023-12-29 15:44:16
  * @FilePath: \general-ai-platform-web\src\pages\FabricView\Room\index.tsx
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
 
-// import { useUuid } from '@/hooks/useUuid';
 import { currJson } from '@/testData/fabricRoomList';
 import { bgImageData } from '@/testData/fabricRoomSvg';
 import { ProCard } from '@ant-design/pro-components';
@@ -16,6 +15,8 @@ import { Button } from 'antd';
 import { fabric } from 'fabric';
 import React, { useEffect, useRef, useState } from 'react';
 import { ColumnDrawer } from './components/ColumnDrawer';
+import ModelTipBox from './components/ModelTipBox';
+import LoadingSpin from '@/components/Loading/loadingSpin';
 
 export const ModelCategoryColumns = [
   {
@@ -51,6 +52,7 @@ export const ModelCategoryColumns = [
     dataIndex: 'deviceName',
   },
 ];
+
 const FabricViewRoom: React.FC = () => {
   const intl = useIntl();
   const canvasRef = useRef(null);
@@ -59,6 +61,7 @@ const FabricViewRoom: React.FC = () => {
   const [descriptors, setDescriptors] = useState<Record<string, any>>({});
   const [category_fk_id_open, set_category_fk_id_open] = useState(false);
   const [currentModelUserProperty, setCurrentModelUserProperty] = useState<Record<string, any>>({});
+  const [isLoading, setisLoading] = useState<boolean>(true);
 
   const [changeId, setChangeId] = useState<string[]>([]);
   const [currentTargetObject, setCurrentTargetObject] = useState<any>(null);
@@ -68,12 +71,15 @@ const FabricViewRoom: React.FC = () => {
     height: 900, // 高
   });
   const [jsonData, setJsonData] = useState<Record<string, any>>({});
-
   /*test */
   // const { fetchUuid } = useUuid();
 
-  function changeModelStatus() {
-    setChangeId(['2', '3']);
+  function changeZoom(isPlus: boolean) {
+    const rate = isPlus ? 1.1 : 0.9;
+    // plus minus
+    const currentZoom = cvs.getZoom();
+    const newZoom = currentZoom * rate; // 缩小 10%
+    cvs.setZoom(newZoom);
   }
 
   const handle_category_fk_id = () => {
@@ -100,13 +106,33 @@ const FabricViewRoom: React.FC = () => {
       });
       groupObject.item(1).set({
         fill: 'rgb(0,0,0)',
-      })
+      });
       finalCvs.renderAll();
       // 遍历子对象找到要修改的子对象
 
       // }
     });
   }
+  // 筛选显示告警状态
+  function changeStatusSelected(selecteds: string[]) {
+    console.log(cvs.getObjects(), 'changeStatusSelected_selected', selecteds);
+    if(selecteds.length){
+      cvs.getObjects().map((element) => {
+        element.set({
+          visible: selecteds.includes(element?.userProperty?.status),
+        });
+      });
+    } else {
+      cvs.getObjects().map((element) => {
+        element.set({
+          visible: true,
+        });
+      });
+    }
+
+    cvs.renderAll();
+  }
+
   // 初始化加载画布&渲染模型
   useEffect(() => {
     const canvasObject = new fabric.Canvas(canvasRef.current);
@@ -129,7 +155,6 @@ const FabricViewRoom: React.FC = () => {
         // 获取事件的目标对象
         const targetObject = event.target;
         // set_category_fk_id_open(false);
-
         // 检查目标对象是否为组合对象
         if (targetObject && targetObject?.userProperty) {
           // canvasObject.setActiveObject(targetObject);
@@ -142,6 +167,7 @@ const FabricViewRoom: React.FC = () => {
         if (targetObject) {
           setCurrentTargetObject(targetObject);
           closeSelectedModel(canvasObject);
+          canvasObject.bringToFront(targetObject);
 
           // console.log('mouse:down:', );
           targetObject.item(0).item(1).set({
@@ -149,19 +175,21 @@ const FabricViewRoom: React.FC = () => {
           });
           targetObject.item(1).set({
             fill: 'blue',
-          })
+          });
         }
         canvasObject.renderAll();
       });
     });
     setCanvas(canvasObject);
+    // setTimeout(()=>{
+      setisLoading(false)
+    // },1000)
     return () => {
       canvasObject.dispose();
     };
   }, []);
 
   useEffect(() => {
-    // TODO_3 需要加个loading效果
     // import('./Descriptors.json').then((descriptors) => {
     //   setDescriptors(descriptors);
     // });
@@ -172,32 +200,44 @@ const FabricViewRoom: React.FC = () => {
   }, [changeId, category_fk_id_open]);
 
   return (
-    <ProCard
-      gutter={24}
-      extra={
-        <>
-          <Button type="primary" onClick={changeModelStatus}>
-            切换状态
-          </Button>
-        </>
-      }
-    >
-      {/* <ProCard colSpan={4}>
-        <ImageMapItems ref={itemsRef} canvasRef={canvasRef} descriptors={descriptors} />
-      </ProCard> */}
-      <ProCard colSpan={24} style={{ padding: 0, margin: 0 }} bodyStyle={{ padding: 0, margin: 0 }}>
-        <canvas ref={canvasRef} {...clipPathData} style={{ border: '1px dashed #eee' }}></canvas>
-
-        <ColumnDrawer
-          handleDrawer={handle_category_fk_id}
-          isShowDetail={category_fk_id_open}
-          columns={ModelCategoryColumns}
-          currentRow={currentModelUserProperty}
-          clipPathData={clipPathData}
-        />
+    <div>
+      <LoadingSpin spinning={isLoading}></LoadingSpin>
+      <ProCard
+        gutter={24}
+        extra={
+          <>
+            <Button type="primary" style={{ marginRight: 20 }} onClick={() => changeZoom(false)}>
+              缩小
+            </Button>
+            <Button type="primary" onClick={() => changeZoom(true)}>
+              扩大
+            </Button>
+          </>
+        }
+      >
+    
+        <ProCard
+          colSpan={24}
+          style={{ padding: 0, margin: 0 }}
+          bodyStyle={{ padding: 0, margin: 0 }}
+        >
+          <canvas ref={canvasRef} {...clipPathData} style={{ border: '1px dashed #eee' }}></canvas>
+          <div style={{ position: 'absolute', bottom: 0, right: 0 }}>
+            <ModelTipBox
+              changeStatusSelected={(selected: string[]) => changeStatusSelected(selected)}
+            ></ModelTipBox>
+          </div>
+          <ColumnDrawer
+            handleDrawer={handle_category_fk_id}
+            isShowDetail={category_fk_id_open}
+            columns={ModelCategoryColumns}
+            currentRow={currentModelUserProperty}
+            clipPathData={clipPathData}
+            canvasObject={cvs}
+          />
+        </ProCard>
       </ProCard>
-    </ProCard>
-    // 属性预览
+    </div>
   );
 };
 
diff --git a/src/pages/Setting/AlgorithmSetting.tsx b/src/pages/Setting/AlgorithmSetting.tsx
index deec20c..e723bf6 100644
--- a/src/pages/Setting/AlgorithmSetting.tsx
+++ b/src/pages/Setting/AlgorithmSetting.tsx
@@ -294,6 +294,7 @@ const AlgorithmSetting: React.FC = () => {
                     style={{ display: 'flex', padding: '0 16px', margin: 0 }}
                   >
                     {tabModeList.map((item) => {
+                      // TODO 统一使用button默认效果 'primary' : 'default'
                       return (
                         <li
                           key={item.value}
diff --git a/src/testData/fabricRoomList.ts b/src/testData/fabricRoomList.ts
index b917dda..372aba9 100644
--- a/src/testData/fabricRoomList.ts
+++ b/src/testData/fabricRoomList.ts
@@ -2,7 +2,7 @@
  * @Author: zhoux zhouxia@supervision.ltd
  * @Date: 2023-12-12 15:41:56
  * @LastEditors: zhoux zhouxia@supervision.ltd
- * @LastEditTime: 2023-12-15 17:22:03
+ * @LastEditTime: 2023-12-29 15:29:58
  * @FilePath: \general-ai-platform-web\src\testData\fabricRoomList.ts
  * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
  */
@@ -89,6 +89,34 @@ const startData: Record<string, any> = {
   ],
 };
 
+// 生成100到1100之间的随机整数
+function generateRandomNumber(minNum, maxNum) {
+  // 生成0到1之间的随机小数
+  const randomFraction = Math.random();
+
+  // 将随机小数映射到100到1100之间的范围
+  const randomNumber = Math.floor(randomFraction * (maxNum - minNum + 1) + minNum);
+
+  return randomNumber;
+}
+
+function initFabricRoomData() {
+  for (let i = 0; i < 5; i++) {
+    let currObjects = JSON.parse(JSON.stringify(startData.modelsList));
+    currObjects = currObjects.map((item) => {
+      item.baseInfo = {
+        left: generateRandomNumber(100, 1100),
+        top: generateRandomNumber(100, 800),
+      };
+      return item;
+    });
+    startData.modelsList = startData.modelsList.concat(currObjects);
+  }
+
+
+}
+initFabricRoomData();
+
 const fabricRoomListData: Record<string, any>[] = [];
 startData.modelsList.forEach((item: Record<string, any>) => {
   const { baseInfo, ...restInfo } = item;
@@ -104,6 +132,7 @@ startData.modelsList.forEach((item: Record<string, any>) => {
   );
 });
 
+
 export const currJson = {
   version: '5.3.0',
   objects: fabricRoomListData,
diff --git a/src/utils/FixMenuItemIcon.tsx b/src/utils/FixMenuItemIcon.tsx
index 1cadf80..44e1fa0 100644
--- a/src/utils/FixMenuItemIcon.tsx
+++ b/src/utils/FixMenuItemIcon.tsx
@@ -1,3 +1,8 @@
+/**
+ * @FixMenuItemIcon 菜单图标手动导入
+ * 
+ * 
+ */
 import React from 'react';
 import { MenuDataItem } from '@ant-design/pro-layout';
 import {CarOutlined, UserOutlined, TableOutlined,
@@ -5,7 +10,7 @@ import {CarOutlined, UserOutlined, TableOutlined,
   HomeOutlined, SettingOutlined, TeamOutlined, DotChartOutlined,
   BlockOutlined, DesktopOutlined, DatabaseOutlined,
   WarningOutlined, CalendarOutlined, ExperimentOutlined,
-  ThunderboltOutlined, BugOutlined, AreaChartOutlined,
+  ThunderboltOutlined, BugOutlined, AreaChartOutlined,ContactsOutlined, GatewayOutlined, BellOutlined
 } from '@ant-design/icons';
 
 const iconMap:any = {
@@ -28,6 +33,9 @@ const iconMap:any = {
   'ThunderboltOutlined': <ThunderboltOutlined/>,
   'BugOutlined': <BugOutlined/>,
   'AreaChartOutlined': <AreaChartOutlined/>,
+  'ContactsOutlined': <ContactsOutlined/>,
+  'GatewayOutlined': <GatewayOutlined/>,
+  'BellOutlined': <BellOutlined/>
 }
 // FIX从接口获取菜单时icon为string类型
 const fixMenuItemIcon = (menus: MenuDataItem[], iconType = 'Outlined'): MenuDataItem[] => {