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[] => {