From ebb977a1707dfcd33b841b952f45c7182c3d12bf Mon Sep 17 00:00:00 2001 From: JINGYJ <1458671527@qq.com> Date: Thu, 21 Dec 2023 17:36:54 +0800 Subject: [PATCH] =?UTF-8?q?feact:=20=E6=B6=88=E6=81=AF=E9=80=9A=E7=9F=A5?= =?UTF-8?q?=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/routes.ts | 5 + public/icons/notice.svg | 5 + src/app.tsx | 3 +- src/components/Notice/index.module.scss | 38 +++++ src/components/Notice/index.tsx | 173 +++++++++++++++++++ src/components/index.ts | 3 +- src/locales/zh-CN.ts | 2 + src/locales/zh-CN/menu.ts | 3 +- src/locales/zh-CN/notice.ts | 17 ++ src/pages/Notice/index.tsx | 210 ++++++++++++++++++++++++ 10 files changed, 456 insertions(+), 3 deletions(-) create mode 100644 public/icons/notice.svg create mode 100644 src/components/Notice/index.module.scss create mode 100644 src/components/Notice/index.tsx create mode 100644 src/locales/zh-CN/notice.ts create mode 100644 src/pages/Notice/index.tsx diff --git a/config/routes.ts b/config/routes.ts index 6a15dfe..7f91e97 100644 --- a/config/routes.ts +++ b/config/routes.ts @@ -306,4 +306,9 @@ export default [ }, ], }, + { + name: 'notice', + path: '/notice', + component: 'Notice', + }, ]; diff --git a/public/icons/notice.svg b/public/icons/notice.svg new file mode 100644 index 0000000..ef90ded --- /dev/null +++ b/public/icons/notice.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/app.tsx b/src/app.tsx index 49b84ba..b941dc7 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,4 +1,4 @@ -import { AvatarDropdown, AvatarName, Footer, Question, SelectLang } from '@/components'; +import { AvatarDropdown, AvatarName, Footer, Question, SelectLang, Notice } from '@/components'; import { LinkOutlined } from '@ant-design/icons'; import type { Settings as LayoutSettings } from '@ant-design/pro-components'; import { SettingDrawer } from '@ant-design/pro-components'; @@ -82,6 +82,7 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) = , , , + ], avatarProps: { src: SERVER_HOST + initialState?.currentUser?.avatarUrl, diff --git a/src/components/Notice/index.module.scss b/src/components/Notice/index.module.scss new file mode 100644 index 0000000..d5ccff3 --- /dev/null +++ b/src/components/Notice/index.module.scss @@ -0,0 +1,38 @@ +.notice { + display: flex; + // float: right; + // padding-top: 10px; + // margin-right: 28px; + justify-content: space-between; +} + +.topNotice { + padding: 4px 8px 0px 8px; + user-select: none; +} + +.bottomBar { + text-align: center; + border-top: 1px solid #f0f0f0; + border-radius: 0 0 2px 2px; + transition: all 0.3s; +} + +.dobtn { + display: inline-block; + width: 50%; + padding: 12px 0; + cursor: pointer; + &:hover { + background-color: #eee; + } +} + +.doLeftBtn { + @extend .dobtn; + border-right: 1px solid #f0f0f0; +} + +.tab { + padding: 0 12px; +} diff --git a/src/components/Notice/index.tsx b/src/components/Notice/index.tsx new file mode 100644 index 0000000..cd0bdc9 --- /dev/null +++ b/src/components/Notice/index.tsx @@ -0,0 +1,173 @@ +import React, { useState, useEffect, useRef } from "react"; +import { Tabs, Badge, Spin, List, Avatar, Tag, Popover, notification } from "antd"; +import { BellOutlined, LoadingOutlined } from "@ant-design/icons"; +// svg 转组件 +import { ReactComponent as NoticeSvg } from '../../../public/icons/notice.svg'; +import type { NotificationPlacement } from 'antd/es/notification/interface'; + +// import { getallnotices, getUidNotices } from "@/api/caravan/User"; + +import styles from "./index.module.scss"; + +enum EventStatus { + todo = "rgba(255,255,255,1)", + urgent = "#f5222d", + doing = "#faad14", + processing = "#1890ff" +} + +const antIcon = ; + +const { TabPane} = Tabs; +const Context = React.createContext({ name: 'Default' }); + +const Notice: React.FC = () => { + const [visible, setVisible] = useState(false); + const [noticeList, setNoticeList] = useState([]); + const [loading, setLoading] = useState(false); + const noticeCount = 10; + const intervalHandle: any = useRef(null); + const [noticeNum, setNoticeNum] = useState(0); + + const noticeListFilter = (type: T) => { + return noticeList.filter(notice => notice.type === type) as any[]; + }; + + const getNotice = async () => { + //查看我是否有新消息 无论如何 + // setLoading(true); + //无论如何,清掉定时器,使用了 ref,肯定能拿到指针。 + //并且启动一个定时器,定时刷新我的消息 + clearTimeout(intervalHandle.current); + intervalHandle.current = setTimeout(() => { + setNoticeNum(Math.ceil(Math.random() * 1000)); + }, 1000 * 60 * 60); + // getUidNotices() + // .then(result => { + // setLoading(false); + // if (result.status && result.data && Array.isArray(result.data.data)) { + // setNoticeList(result.data.data); + // } + // }) + // .catch(() => { + // setLoading(false); + // }); + // getallnotices(); + }; + // const [api, contextHolder] = notification.useNotification(); + + // const openNotification = (placement: NotificationPlacement) => { + // api.info({ + // message: `Notification ${placement}`, + // description: {({ name }) => `Hello, ${name}!`}, + // placement, + // }); + // }; + + useEffect(() => { + getNotice(); + }, [noticeNum]); + // const ws = new WebSocket("ws://localhost:3000/"); + + // useEffect(() => { + + // console.log(ws); + // // ws.onopen = function () { + // // setInterval(function () { + // // ws.send("客户端消息"); + // // }, 2000); + // // }; + + // ws.onmessage = function (e) { + // console.log(e.data); + // openNotification('topRight') + // } + // }, []); + useEffect(() => { + return () => { + clearTimeout(intervalHandle.current); + }; + }, []); + + const onClear = () => { + // ws.send("客户端消息"); + }; + const onViewMore = () => {}; + const tabsData = [ + { + title: 'Ant Design Title 1', + time: '刚刚' + }, + { + title: 'Ant Design Title 2Ant Design Title 2Ant Design Title 2Ant Design Title 2Ant Design Title 2Ant Design Title 2Ant Design Title 2', + time: '刚刚' + }, + { + title: 'Ant Design Title 3', + time: '刚刚' + }, + { + title: 'Ant Design Title 4', + time: '刚刚' + }, + ]; + const tabs = ( +
+ + ( + + +
+ 系统消息 + + 紧急 + +
+
+ {item.title} +
+
{item.time}
+
+ } + /> + + )} + /> + + + ); + return ( +
+ {/* {contextHolder} */} + setVisible(v)} + arrow={{pointAtCenter: true}} + overlayStyle={{ + width: 396, + }} + > + {/* */} + + + {/* */} + + + + {/* */} + +
+ ); +}; + +export default Notice; diff --git a/src/components/index.ts b/src/components/index.ts index ca88a6d..3c73148 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -6,7 +6,8 @@ * 布局组件 */ import Footer from './Footer'; +import Notice from './Notice'; import { Question, SelectLang } from './RightContent'; import { AvatarDropdown, AvatarName } from './RightContent/AvatarDropdown'; -export { Footer, Question, SelectLang, AvatarDropdown, AvatarName }; +export { Footer, Question, SelectLang, AvatarDropdown, AvatarName, Notice }; diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index ebe45fb..d7a8a29 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -6,6 +6,7 @@ * @FilePath: \general-ai-platform-web\src\locales\zh-CN.ts * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE */ +import * as noticeZh from '@/locales/zh-CN/notice'; import * as contactZh from '@/locales/zh-CN/contact'; import * as DCSDevice from '@/locales/zh-CN/DCSDevice'; import * as alarmLangs from '@/locales/zh-CN/alarm'; @@ -69,4 +70,5 @@ export default { ...Object.assign({}, ...Object.values(DCSDevice)), ...Object.assign({}, ...Object.values(contactZh)), ...Object.assign({}, ...Object.values(alarmLangs)), + ...Object.assign({}, ...Object.values(noticeZh)), }; diff --git a/src/locales/zh-CN/menu.ts b/src/locales/zh-CN/menu.ts index c2ea48c..3042e8d 100644 --- a/src/locales/zh-CN/menu.ts +++ b/src/locales/zh-CN/menu.ts @@ -75,5 +75,6 @@ export default { 'menu.DCSDevice.DCSDevice-device-list': '设备列表', 'menu.DCSDevice.DCSDevice-device-category-list': '设备类别', 'menu.DCSDevice.DCSDevice-device-group-list': '设备组', - 'menu.Contact.Contact-contact-list': '联系人列表' + 'menu.Contact.Contact-contact-list': '联系人列表', + 'menu.notice': '消息通知' }; diff --git a/src/locales/zh-CN/notice.ts b/src/locales/zh-CN/notice.ts new file mode 100644 index 0000000..e051610 --- /dev/null +++ b/src/locales/zh-CN/notice.ts @@ -0,0 +1,17 @@ +export const notice_list: { [key: string]: string } = { + 'notice.notice.table.list.id': 'ID', + 'notice.notice.table.list.type': '消息类型', + 'notice.notice.table.list.priority': '优先级', + 'notice.notice.table.list.content': '内容', + 'notice.notice.table.list.time': '时间', + 'notice.notice.table.list.isEnable': '是否启用', + 'notice.notice.table.list.remark': '备注', + 'notice.notice.table.list.createTime': '创建时间', + 'notice.notice.table.list.updateTime': '更新时间', + 'notice.notice.table.rule.required.name': '姓名为必填项', + 'notice.notice.table.rule.required.code': '项目代码为必填项', + 'notice.notice.table.rule.required.info': '项目简介为必填项', + 'notice.notice.table.list.add': '新建联系人', + 'notice.notice.table.list.update': '编辑联系人', + 'notice.notice.table.list.editor': '编辑', +}; \ No newline at end of file diff --git a/src/pages/Notice/index.tsx b/src/pages/Notice/index.tsx new file mode 100644 index 0000000..2eb2375 --- /dev/null +++ b/src/pages/Notice/index.tsx @@ -0,0 +1,210 @@ +import IsBatchDelete from '@/components/BatchOperation/isBatchDelete'; +import TableActionCard from '@/components/TableActionCard'; +import IsDelete from '@/components/TableActionCard/isDelete'; +import { + deleteProjectDeleteProject, + deleteProjectDeleteProjectByIds, + postProjectGetProjectList, +} from '@/services/project/Project'; +import type { ActionType, ProColumns } from '@ant-design/pro-components'; +import { PageContainer, ProTable } from '@ant-design/pro-components'; +import { FormattedMessage, useAccess, useIntl } from '@umijs/max'; +import { Tag, message } from 'antd'; +import React, { useRef, useState } from 'react'; +import { proTableCommonOptions, proTablePaginationOptions } from '../../../config/defaultTable'; +const ProjectList: React.FC = () => { + /** + * @en-US Pop-up window of new window + * @zh-CN 新建窗口的弹窗 + * */ + const [createModalOpen, setCreateModalOpen] = useState(false); + /** + * @en-US The pop-up window of the distribution update window + * @zh-CN 分布更新窗口的弹窗 + * */ + const [updateModalOpen, setUpdateModalOpen] = useState(false); + const [showDetail, setShowDetail] = useState(false); + /** + * @en-US International configuration + * @zh-CN 国际化配置 + * */ + const intl = useIntl(); + const actionRef = useRef(); + // 动态设置每页数量 + const [currentPageSize, setCurrentPageSize] = useState(10); + const [currentRow, setCurrentRow] = useState(); + const [selectedRowsState, setSelectedRows] = useState([]); + + const handleUpdateModal = () => { + if (updateModalOpen) { + setUpdateModalOpen(false); + setCurrentRow(undefined); + } else { + setUpdateModalOpen(true); + } + }; + const handleCreateModal = () => { + if (createModalOpen) { + setCreateModalOpen(false); + setCurrentRow(undefined); + } else { + setCreateModalOpen(true); + } + }; + const handleColumnDrawer = () => { + if (showDetail) { + setShowDetail(false); + setCurrentRow(undefined); + } else { + setShowDetail(true); + } + }; + const handleDestroy = async (selectedRow: API.Project) => { + deleteProjectDeleteProject({ id: selectedRow.id }) + .then(() => { + message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '$$$' })); + actionRef.current?.reload(); + }) + .catch(() => { + message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '$$$' })); + }); + }; + + const columns: ProColumns[] = [ + { + title: , + dataIndex: 'name', + hideInSearch: true, + key: 'fixedName', + fixed: 'left', + }, + { + title: , + dataIndex: 'code', + // hideInSearch: true, + render: (dom) => { + return ( + + {dom} + + ); + }, + }, + + { + title: , + dataIndex: 'info', + hideInSearch: true, + }, + + { + title: , + dataIndex: 'createTime', + hideInSearch: false, + valueType: 'dateRange', + }, + + { + title: , + dataIndex: 'option', + valueType: 'option', + fixed: 'right', + render: (_, record) => [ + { + handleDestroy(record).then(() => {}); + }} + > + ), + }, + ]} + >, + ], + }, + ]; + return ( + + + headerTitle={intl.formatMessage({ + id: 'pages.searchTable.title', + defaultMessage: '$$$', + })} + scroll={{ y: proTableCommonOptions.commscrollY, x: proTableCommonOptions.commscrollX }} + options={{ fullScreen: true, setting: true, density: true, reload: true }} + actionRef={actionRef} + rowKey="key" + search={{ + labelWidth: proTableCommonOptions.searchLabelWidth, + }} + onDataSourceChange={() => {}} + pagination={{ + ...proTablePaginationOptions, + pageSize: currentPageSize, + onChange: (page, pageSize) => setCurrentPageSize(pageSize), + }} + columnsState={{ + persistenceKey: 'project_list', + persistenceType: 'localStorage', + }} + tableAlertOptionRender={() => { + return ( + <> + {selectedRowsState?.length > 0 && ( + { + // TODO 需要;联调删除接口 + deleteProjectDeleteProjectByIds({ + ids: selectedRowsState.map((v: API.Project) => { + return v.id as number; + }), + }).then(() => { + actionRef.current?.reloadAndRest?.(); + }); + }} + /> + )} + + ); + }} + request={async (params = {}, sort) => { + const { current, ...rest } = params; + const reqParams = { + page: current, + desc: false, + orderKey: '', + ...rest, + }; + if (sort && Object.keys(sort).length) { + reqParams.orderKey = Object.keys(sort)[0]; + let sort_select = sort[reqParams.orderKey]; + reqParams.desc = sort_select === 'descend'; + } + let resp = await postProjectGetProjectList({ ...reqParams }); + return { + data: resp.data.list.map((v: API.Project) => { + return { ...v, key: v.id }; + }), + success: resp.success, + total: resp.data.total, + current: resp.data.page, + pageSize: resp.data.pageSize, + }; + }} + columns={columns} + // rowSelection={{ + // onChange: (_, selectedRows) => { + // setSelectedRows(selectedRows); + // }, + // }} + /> + + ); +}; + +export default ProjectList;