@tuya-sat/sdf-main-sdk 0.0.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/.vscode/settings.json +5 -0
  2. package/README.md +1 -0
  3. package/antd.less.overwrite.js +56 -0
  4. package/color.js +140 -0
  5. package/dark-variable.less +1449 -0
  6. package/package.json +74 -0
  7. package/scripts/gen-localize-file.mjs +56 -0
  8. package/src/App.less +156 -0
  9. package/src/App.tsx +87 -0
  10. package/src/api/index.ts +52 -0
  11. package/src/api/req.ts +23 -0
  12. package/src/api/res.ts +29 -0
  13. package/src/api/urls.ts +30 -0
  14. package/src/api/utils.ts +41 -0
  15. package/src/assets/imgs/404.svg +194 -0
  16. package/src/assets/imgs/reLogin.png +0 -0
  17. package/src/components/404/index.tsx +44 -0
  18. package/src/components/500/index.tsx +49 -0
  19. package/src/components/BCustomNav/index.module.less +17 -0
  20. package/src/components/BCustomNav/index.tsx +108 -0
  21. package/src/components/BForgot/index.module.less +5 -0
  22. package/src/components/BForgot/index.tsx +96 -0
  23. package/src/components/BHeaderUser/account.png +0 -0
  24. package/src/components/BHeaderUser/app-scan-en.png +0 -0
  25. package/src/components/BHeaderUser/app-scan-zh.png +0 -0
  26. package/src/components/BHeaderUser/app-scan.png +0 -0
  27. package/src/components/BHeaderUser/components/BSwitchLang/index.module.less +6 -0
  28. package/src/components/BHeaderUser/components/BSwitchLang/index.tsx +56 -0
  29. package/src/components/BHeaderUser/components/Badge/components/Notice/Drawer/Content.tsx +199 -0
  30. package/src/components/BHeaderUser/components/Badge/components/Notice/Drawer/index.module.less +11 -0
  31. package/src/components/BHeaderUser/components/Badge/components/Notice/Drawer/index.tsx +27 -0
  32. package/src/components/BHeaderUser/components/Badge/components/Notice/hooks.ts +104 -0
  33. package/src/components/BHeaderUser/components/Badge/components/Notice/index.module.less +70 -0
  34. package/src/components/BHeaderUser/components/Badge/components/Notice/index.tsx +184 -0
  35. package/src/components/BHeaderUser/components/Badge/components/Notice/table/index.tsx +184 -0
  36. package/src/components/BHeaderUser/components/Badge/components/Notice/table/read.tsx +67 -0
  37. package/src/components/BHeaderUser/components/Badge/components/Notice/tools/index.tsx +116 -0
  38. package/src/components/BHeaderUser/components/Badge/index.module.less +99 -0
  39. package/src/components/BHeaderUser/components/Badge/index.tsx +179 -0
  40. package/src/components/BHeaderUser/index.module.less +105 -0
  41. package/src/components/BHeaderUser/index.tsx +261 -0
  42. package/src/components/BHeaderUser/logout.tsx +26 -0
  43. package/src/components/BLayout/components/Header/index.module.less +27 -0
  44. package/src/components/BLayout/components/Header/index.tsx +36 -0
  45. package/src/components/BLayout/components/Layout/empty.tsx +35 -0
  46. package/src/components/BLayout/components/Layout/emptyPage.png +0 -0
  47. package/src/components/BLayout/components/Layout/index.tsx +72 -0
  48. package/src/components/BLayout/components/Logo.tsx +6 -0
  49. package/src/components/BLayout/components/Menu/collapse.tsx +41 -0
  50. package/src/components/BLayout/components/Menu/image/close.tsx +26 -0
  51. package/src/components/BLayout/components/Menu/image/closedefault.tsx +26 -0
  52. package/src/components/BLayout/components/Menu/image/open.tsx +38 -0
  53. package/src/components/BLayout/components/Menu/image/opendefault.tsx +38 -0
  54. package/src/components/BLayout/components/Menu/index.module.less +125 -0
  55. package/src/components/BLayout/components/Menu/index.tsx +244 -0
  56. package/src/components/BLayout/components/MenuIcon.module.less +5 -0
  57. package/src/components/BLayout/components/MenuIcon.tsx +46 -0
  58. package/src/components/BLayout/components/MultiSider/index.module.less +104 -0
  59. package/src/components/BLayout/components/MultiSider/index.tsx +172 -0
  60. package/src/components/BLayout/components/Sider/index.less +64 -0
  61. package/src/components/BLayout/components/Sider/index.module.less +17 -0
  62. package/src/components/BLayout/components/Sider/index.tsx +34 -0
  63. package/src/components/BLayout/index.tsx +78 -0
  64. package/src/components/BLayoutLogin/index.module.less +65 -0
  65. package/src/components/BLayoutLogin/index.tsx +68 -0
  66. package/src/components/BLayoutLogin/login.jpg +0 -0
  67. package/src/components/BLogin/component/Clause/index.module.less +25 -0
  68. package/src/components/BLogin/component/Clause/index.tsx +58 -0
  69. package/src/components/BLogin/component/ForgotBtn/index.module.less +9 -0
  70. package/src/components/BLogin/component/ForgotBtn/index.tsx +18 -0
  71. package/src/components/BLogin/component/Password/index.tsx +39 -0
  72. package/src/components/BLogin/component/SubmitBtn/index.tsx +30 -0
  73. package/src/components/BLogin/component/TenanSpace/index.tsx +28 -0
  74. package/src/components/BLogin/component/Title/index.module.less +6 -0
  75. package/src/components/BLogin/component/Title/index.tsx +12 -0
  76. package/src/components/BLogin/component/UserName/index.tsx +48 -0
  77. package/src/components/BLogin/component/VerifyCode/index.module.less +11 -0
  78. package/src/components/BLogin/component/VerifyCode/index.tsx +165 -0
  79. package/src/components/BLogin/index.module.less +31 -0
  80. package/src/components/BLogin/index.tsx +210 -0
  81. package/src/components/BRegister/components/TenantName/index.tsx +26 -0
  82. package/src/components/BRegister/index.module.less +5 -0
  83. package/src/components/BRegister/index.tsx +71 -0
  84. package/src/components/Back/index.tsx +25 -0
  85. package/src/components/IconFont/font.js +66 -0
  86. package/src/components/IconFont/index.tsx +18 -0
  87. package/src/components/MicroComponent/Header/index.module.less +7 -0
  88. package/src/components/MicroComponent/Header/index.tsx +220 -0
  89. package/src/components/PForgot/index.tsx +10 -0
  90. package/src/components/PLogin/index.tsx +12 -0
  91. package/src/components/PRegister/index.tsx +10 -0
  92. package/src/components/PSetting/index.module.less +53 -0
  93. package/src/components/PSetting/index.tsx +420 -0
  94. package/src/constant/chargeStatus.ts +6 -0
  95. package/src/constant/imgs.ts +6 -0
  96. package/src/constant/index.ts +293 -0
  97. package/src/dark-variable.less +1449 -0
  98. package/src/global.d.ts +54 -0
  99. package/src/hooks/index.ts +133 -0
  100. package/src/index.css +1493 -0
  101. package/src/index.tsx +105 -0
  102. package/src/lang/en.json +266 -0
  103. package/src/lang/index.ts +44 -0
  104. package/src/lang/utils.ts +285 -0
  105. package/src/lang/zh.json +270 -0
  106. package/src/micro-script/theme/index.ts +29 -0
  107. package/src/micro-script/theme/theme-css/static.js +73 -0
  108. package/src/micro-script/theme/theme-css/subscriber.ts +201 -0
  109. package/src/micro-script/theme/util/index.ts +58 -0
  110. package/src/mqtt/index.ts +121 -0
  111. package/src/pages/403.tsx +18 -0
  112. package/src/pages/404.tsx +17 -0
  113. package/src/pages/expiration.tsx +23 -0
  114. package/src/pages/forgot.tsx +9 -0
  115. package/src/pages/home/index.tsx +172 -0
  116. package/src/pages/home/setting/index.tsx +7 -0
  117. package/src/pages/index.ts +50 -0
  118. package/src/pages/login.tsx +46 -0
  119. package/src/pages/register.tsx +9 -0
  120. package/src/pages/relogin/index.module.less +0 -0
  121. package/src/pages/relogin/index.tsx +54 -0
  122. package/src/plugins/index.ts +11 -0
  123. package/src/public-path.js +8 -0
  124. package/src/qiankun/globalState.ts +6 -0
  125. package/src/qiankun/index.ts +174 -0
  126. package/src/qiankun/utils/index.ts +69 -0
  127. package/src/qiankun/xhook/index.ts +193 -0
  128. package/src/reportWebVitals.ts +15 -0
  129. package/src/sentry/index.ts +33 -0
  130. package/src/sky/index.ts +57 -0
  131. package/src/theme/custom-dark.less +64 -0
  132. package/src/theme/custom-light.less +48 -0
  133. package/src/theme/index.less +327 -0
  134. package/src/theme/variable.less +13 -0
  135. package/src/utils/checkPass.ts +21 -0
  136. package/src/utils/common.ts +195 -0
  137. package/src/utils/eventBus.ts +112 -0
  138. package/src/utils/gt.js +293 -0
  139. package/src/utils/index.ts +89 -0
  140. package/src/utils/theme/base.ts +110 -0
  141. package/src/utils/theme/changeCssVariable.ts +157 -0
  142. package/src/utils/theme/changeMenuCssVariable.ts +176 -0
  143. package/src/utils/theme/index.ts +85 -0
  144. package/src/utils/theme/store.ts +37 -0
  145. package/tsconfig.json +28 -0
  146. package/typings.d.ts +10 -0
  147. package/webpack.config.js +103 -0
@@ -0,0 +1,184 @@
1
+ import { Table, Typography } from 'antd';
2
+ import { useState, useEffect } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+ import { useSaasInfo } from '@/hooks';
5
+ import styles from '../index.module.less';
6
+ import Read from './read';
7
+ import { eventEmiter, eventNames } from '@/utils';
8
+
9
+ const { Text, Link } = Typography;
10
+
11
+ const NoticeTable = (props) => {
12
+ const { t } = useTranslation();
13
+ const { saasIdInfoList } = useSaasInfo();
14
+
15
+ // 触发每条消息的已读
16
+ const {
17
+ selectedRowKeys,
18
+ setSelectedRowKeys,
19
+ loading,
20
+ list,
21
+ total,
22
+ pageSize,
23
+ current,
24
+ setCurrent,
25
+ setPageSize,
26
+ getData,
27
+ } = props;
28
+
29
+ const [dataList, setDataList] = useState(list);
30
+ useEffect(() => {
31
+ setDataList(list);
32
+ }, [list]);
33
+ const columns = [
34
+ {
35
+ title: t('notice.table.column.content'),
36
+ dataIndex: 'message_content',
37
+ width: '40%',
38
+ render: (text, record) => {
39
+ if (
40
+ record.action_url &&
41
+ record.action_url.includes('tuyaSmart://microApp')
42
+ ) {
43
+ const queryString = record.action_url.replace(
44
+ 'tuyaSmart://microApp?',
45
+ ''
46
+ );
47
+ const searchParams = new URLSearchParams(queryString);
48
+ const universal_id = searchParams.get('universalId');
49
+ const path = searchParams.get('path');
50
+ const query = searchParams.get('query');
51
+
52
+ return (
53
+ <Text
54
+ ellipsis={{ tooltip: record.message_content }}
55
+ style={{ color: 'var(--ant-primary-color)', cursor: 'pointer' }}
56
+ onClick={() => {
57
+ let pathUrl = '';
58
+ if (path) {
59
+ pathUrl = path;
60
+ if (atob(query)) {
61
+ pathUrl += `?${atob(query)}`;
62
+ }
63
+ }
64
+ const appId =
65
+ saasIdInfoList.find(
66
+ (item) => item.universal_id === universal_id
67
+ ).oem_micro_app_id || '';
68
+ if (appId) {
69
+ window.open(
70
+ `${window.location.origin}/apps/${appId}${pathUrl}`
71
+ );
72
+ }
73
+ }}
74
+ >
75
+ {record.message_content}
76
+ </Text>
77
+ );
78
+ } else {
79
+ return (
80
+ <Text ellipsis={{ tooltip: record.message_content }}>
81
+ {record.message_content}
82
+ </Text>
83
+ );
84
+ }
85
+ },
86
+ },
87
+ {
88
+ title: t('notice.table.column.status'),
89
+ dataIndex: 'read_status',
90
+ render: (text) =>
91
+ text === '0'
92
+ ? t('notice.table.render.status.unread')
93
+ : t('notice.table.render.status.read'),
94
+ },
95
+ {
96
+ title: t('notice.table.column.type'),
97
+ dataIndex: 'message_type',
98
+ render: (text) =>
99
+ text === '1'
100
+ ? t('notice.typeSelect.alert')
101
+ : t('notice.typeSelect.message'),
102
+ },
103
+ {
104
+ title: t('notice.table.column.source'),
105
+ render: (text, record) => {
106
+ if (record.micro_universal_id) {
107
+ return (
108
+ <Link
109
+ onClick={() => {
110
+ const appId =
111
+ saasIdInfoList.find(
112
+ (item) => item.universal_id === record.micro_universal_id
113
+ ).oem_micro_app_id || '';
114
+ appId && window.open(`${window.location.origin}/apps/${appId}`);
115
+ }}
116
+ >
117
+ {record.source_name}
118
+ </Link>
119
+ );
120
+ } else {
121
+ return <Text>{record.source_name}</Text>;
122
+ }
123
+ },
124
+ },
125
+ {
126
+ title: t('notice.table.column.time'),
127
+ dataIndex: 'create_time',
128
+ width: '170px',
129
+ render: (text, record) => {
130
+ return rowKey === record.message_id ? (
131
+ <Read record={record} setDataList={setDataList} />
132
+ ) : (
133
+ <Text className={styles.action}>{text}</Text>
134
+ );
135
+ },
136
+ },
137
+ ];
138
+
139
+ const rowSelection = {
140
+ selectedRowKeys,
141
+ onChange: (selectedRowKeys) => {
142
+ console.log('selectedRowKeys', selectedRowKeys.length);
143
+ setSelectedRowKeys(selectedRowKeys);
144
+ },
145
+ };
146
+ const [rowKey, setRowKey] = useState(null);
147
+ return (
148
+ <Table
149
+ rowKey="message_id"
150
+ rowSelection={rowSelection}
151
+ columns={columns}
152
+ dataSource={dataList}
153
+ sticky
154
+ loading={loading}
155
+ scroll={{ y: '560px' }}
156
+ onRow={(record) => {
157
+ return {
158
+ onMouseEnter: () => {
159
+ setRowKey(record.message_id);
160
+ }, // 鼠标移入行
161
+ onMouseLeave: () => {
162
+ setRowKey(null);
163
+ },
164
+ };
165
+ }}
166
+ pagination={{
167
+ total,
168
+ current,
169
+ pageSize,
170
+ showSizeChanger: true,
171
+ showQuickJumper: true,
172
+ pageSizeOptions: ['10', '20', '40', '50'],
173
+ onChange: (current: number, pageSize: number) => {
174
+ setCurrent(current);
175
+ setPageSize(pageSize);
176
+ getData(pageSize, current);
177
+ eventEmiter.emit(eventNames.HIDE_MSG_TOOL);
178
+ },
179
+ }}
180
+ />
181
+ );
182
+ };
183
+
184
+ export default NoticeTable;
@@ -0,0 +1,67 @@
1
+ import { Typography, Divider, Popconfirm } from 'antd';
2
+ import cx from 'classnames';
3
+ import styles from '../index.module.less';
4
+ import { useTranslation } from 'react-i18next';
5
+ import { readStatus, noticeDelete } from '../hooks';
6
+ import EventBus from '@/utils/eventBus';
7
+ import { EVENT_NOTICE } from '@/constant';
8
+
9
+ const { Text, Link } = Typography;
10
+ const Read = ({ record, setDataList }) => {
11
+ const { t } = useTranslation();
12
+
13
+ const changItem = (read_status: string) => {
14
+ setDataList((prev) => {
15
+ const newList = prev.map((item) => {
16
+ if (item.message_id === record.message_id) {
17
+ item.read_status = read_status;
18
+ }
19
+ return item;
20
+ });
21
+ return newList;
22
+ });
23
+ setTimeout(() => {
24
+ EventBus.dispatchEvent(EVENT_NOTICE);
25
+ }, 500);
26
+ };
27
+ const markStatus = () => {
28
+ if (record.read_status == 0) {
29
+ readStatus('1', [record.message_id]).then(() => changItem('1'));
30
+ } else {
31
+ readStatus('0', [record.message_id]).then(() => changItem('0'));
32
+ }
33
+ };
34
+
35
+ const del = () => {
36
+ noticeDelete([record.message_id]).then(() => {
37
+ setDataList((prev) =>
38
+ prev.filter((item) => item.message_id !== record.message_id)
39
+ );
40
+ if (record.read_status == 0) {
41
+ setTimeout(() => {
42
+ EventBus.dispatchEvent(EVENT_NOTICE);
43
+ }, 500);
44
+ }
45
+ });
46
+ };
47
+ return (
48
+ <>
49
+ <Link className={styles.action} onClick={() => markStatus()}>
50
+ {record.read_status == 0
51
+ ? t('notice.table.hover.read')
52
+ : t('notice.table.hover.unread')}
53
+ </Link>
54
+ <Divider type="vertical" />
55
+ <Popconfirm title={t('notice.table.delTip')} onConfirm={() => del()}>
56
+ <Text
57
+ className={cx(styles.action)}
58
+ style={{ cursor: 'pointer' }}
59
+ type="danger"
60
+ >
61
+ {t('notice.table.hover.del')}
62
+ </Text>
63
+ </Popconfirm>
64
+ </>
65
+ );
66
+ };
67
+ export default Read;
@@ -0,0 +1,116 @@
1
+ import { useCallback, useMemo, useEffect } from 'react';
2
+ import { Modal, Typography } from 'antd';
3
+
4
+ import eventBus from '@/utils/eventBus';
5
+ import { EVENT_NOTICE } from '@/constant';
6
+ import { useTranslation } from 'react-i18next';
7
+ import { readStatus, noticeDelete, useReadCount } from '../hooks';
8
+
9
+ const { Link, Text } = Typography;
10
+ import styles from '../index.module.less';
11
+ import classnames from 'classnames';
12
+ import { eventEmiter, eventNames } from '@/utils';
13
+
14
+ interface Iprops {
15
+ pageSize: number;
16
+ selectedRowKeys: string[];
17
+ setSelectedRowKeys: (selectedRowKeys: string[]) => void;
18
+ getData: (page: number, pageSize: number) => void;
19
+ }
20
+ const Tools = ({
21
+ selectedRowKeys,
22
+ getData,
23
+ setSelectedRowKeys,
24
+ pageSize,
25
+ }: Iprops) => {
26
+ const { t } = useTranslation();
27
+
28
+ const [count] = useReadCount();
29
+
30
+ const resultBack = () => {
31
+ setTimeout(() => {
32
+ getData(pageSize, 1);
33
+ setSelectedRowKeys([]);
34
+ eventBus.dispatchEvent(EVENT_NOTICE);
35
+ }, 500);
36
+ };
37
+
38
+ useEffect(() => {
39
+ eventEmiter.addListener(eventNames.HIDE_MSG_TOOL, () => {
40
+ setSelectedRowKeys([]);
41
+ });
42
+ }, []);
43
+
44
+ const onDelete = useCallback(async () => {
45
+ const onOk = async () => {
46
+ const result = await noticeDelete(selectedRowKeys);
47
+ result && resultBack();
48
+ };
49
+ Modal.confirm({
50
+ title: t('notice.tools.popconfirm.title'),
51
+ content: t('notice.tools.popconfirm.content'),
52
+ okText: t('notice.tools.popconfirm.ok'),
53
+ onOk: () => onOk(),
54
+ cancelText: t('notice.tools.popconfirm.cancel'),
55
+ });
56
+ }, [getData, selectedRowKeys]);
57
+
58
+ const onReadStatus = useCallback(
59
+ async (type: string) => {
60
+ const result = await readStatus(type, selectedRowKeys);
61
+ result && resultBack();
62
+ },
63
+ [getData, selectedRowKeys]
64
+ );
65
+
66
+ const selectNone = () => {
67
+ setSelectedRowKeys([]);
68
+ };
69
+
70
+ const checked = useMemo(() => {
71
+ return (
72
+ <div className={classnames(styles.checked, 'main-notice-tools-bg')}>
73
+ <div className={styles['checked-left']}>
74
+ <Text style={{ marginLeft: '16px' }}>
75
+ {t('notice.tools.itemsNums', {
76
+ num: selectedRowKeys.length,
77
+ })}
78
+ </Text>
79
+
80
+ <Link style={{ marginLeft: '16px' }} onClick={selectNone}>
81
+ {t('notice.tools.cancelSelect')}
82
+ </Link>
83
+ </div>
84
+ <div className={styles['checked-right']}>
85
+ <Link
86
+ style={{ marginRight: '16px' }}
87
+ onClick={() => onReadStatus('1')}
88
+ >
89
+ {t('notice.tools.pread')}
90
+ </Link>
91
+ <Link
92
+ style={{ marginRight: '16px' }}
93
+ onClick={() => onReadStatus('0')}
94
+ >
95
+ {t('notice.tools.punread')}
96
+ </Link>
97
+ <Text
98
+ style={{ marginRight: '16px', cursor: 'pointer' }}
99
+ type="danger"
100
+ onClick={() => onDelete()}
101
+ >
102
+ {t('notice.tools.pdelete')}
103
+ </Text>
104
+ </div>
105
+ </div>
106
+ );
107
+ }, [onDelete, onReadStatus]);
108
+
109
+ return (
110
+ <div className={styles.tools}>
111
+ {selectedRowKeys && selectedRowKeys.length > 0 && checked}
112
+ </div>
113
+ );
114
+ };
115
+
116
+ export default Tools;
@@ -0,0 +1,99 @@
1
+ // 单行
2
+ .single-warp() {
3
+ overflow: hidden;
4
+ text-overflow: ellipsis;
5
+ white-space: nowrap;
6
+ }
7
+
8
+ // 两行
9
+ .multi-warp {
10
+ overflow: hidden;
11
+ text-overflow: ellipsis;
12
+ display: -webkit-box;
13
+ -webkit-line-clamp: 2;
14
+ -webkit-box-orient: vertical;
15
+ }
16
+
17
+ .resetPopover {
18
+ :global {
19
+ .main-popover-inner-content {
20
+ padding: 0;
21
+ }
22
+
23
+ .main-list-header {
24
+ height: 32px;
25
+ line-height: 32px;
26
+ padding: 0;
27
+ font-weight: 500;
28
+ font-size: 14px;
29
+ padding-left: 20px;
30
+ }
31
+
32
+ .main-spin-nested-loading {
33
+ padding: 0 20px;
34
+ }
35
+
36
+ .main-list-item {
37
+ height: 79px;
38
+ }
39
+ }
40
+ }
41
+
42
+ .resetList {
43
+ :global {
44
+ .main-list-item-meta-title {
45
+ font-size: 12px;
46
+ .single-warp();
47
+ }
48
+
49
+ .main-list-item-meta-description {
50
+ font-size: 14px;
51
+ font-weight: 400;
52
+ .multi-warp();
53
+ }
54
+ }
55
+ }
56
+
57
+ .multiple {
58
+ :global {
59
+ .main-badge-multiple-words {
60
+ padding: 0 4px;
61
+ }
62
+ }
63
+ }
64
+
65
+ .iconMargin {
66
+ margin-right: 5px;
67
+ }
68
+
69
+ .circle {
70
+ height: 24px;
71
+ .icon {
72
+ cursor: pointer;
73
+ color: #555;
74
+ &:hover {
75
+ color: rgb(24, 144, 255);
76
+ }
77
+ }
78
+ }
79
+
80
+ .footer {
81
+ height: 18px;
82
+ display: flex;
83
+ align-self: center;
84
+ justify-content: center;
85
+
86
+ span {
87
+ cursor: pointer;
88
+ font-weight: 400;
89
+ font-size: 14px;
90
+ line-height: 22px;
91
+ }
92
+ }
93
+
94
+ .wrap-badge {
95
+ height: 24px;
96
+ margin-left: 24px;
97
+ line-height: 24px;
98
+ margin-left: 24px;
99
+ }
@@ -0,0 +1,179 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { Badge, List, Popover, Typography } from 'antd';
3
+ import cn from 'classnames';
4
+ import { useHistory, useLocation } from 'react-router-dom';
5
+ import { useTranslation } from 'react-i18next';
6
+ import IconFont from '@/components/IconFont';
7
+ import EventBus from '@/utils/eventBus';
8
+ import { useSaasInfo } from '@/hooks';
9
+ import { EVENT_NOTICE } from '@/constant';
10
+ import {
11
+ useReadCount,
12
+ useNoticeList,
13
+ Inotice,
14
+ } from '@/components/BHeaderUser/components/Badge/components/Notice/hooks';
15
+
16
+ import styles from './index.module.less';
17
+
18
+ const { Text } = Typography;
19
+
20
+ const Notice = () => {
21
+ const { t } = useTranslation();
22
+ const { saasIdInfoList } = useSaasInfo();
23
+
24
+ const [count, getReadCount] = useReadCount();
25
+
26
+ const { list, getData } = useNoticeList('', '', '0', 10);
27
+
28
+ const [visible, setVisible] = useState(false);
29
+
30
+ const history = useHistory();
31
+
32
+ const { pathname } = useLocation();
33
+
34
+ useEffect(() => {
35
+ const cb = () => {
36
+ getReadCount();
37
+ getData(10, 1);
38
+ };
39
+ EventBus.addEventListener(EVENT_NOTICE, cb);
40
+ return () => {
41
+ EventBus.removeEventListener(EVENT_NOTICE, cb);
42
+ };
43
+ }, []);
44
+
45
+ const jumpNotice = () => {
46
+ // 点击后关闭弹窗
47
+ setVisible(false);
48
+ if (pathname === '/application/notification') return;
49
+
50
+ if (pathname === '/application/setting') {
51
+ history.replace('/application/notification');
52
+ } else {
53
+ history.push('/application/notification');
54
+ }
55
+ };
56
+
57
+ const onVisibleChange = (visible: boolean) => {
58
+ setVisible(visible);
59
+ };
60
+
61
+ const offset = (count: number): [number, number] => {
62
+ if (count <= 99 && count > 9) {
63
+ return [3, 0];
64
+ }
65
+ if (count > 99) {
66
+ return [8, 0];
67
+ }
68
+ return [-1, 0];
69
+ };
70
+
71
+ const Desc = ({ record }) => {
72
+ if (
73
+ record.action_url &&
74
+ record.action_url.includes('tuyaSmart://microApp')
75
+ ) {
76
+ const queryString = record.action_url.replace(
77
+ 'tuyaSmart://microApp?',
78
+ ''
79
+ );
80
+ const searchParams = new URLSearchParams(queryString);
81
+ const universal_id = searchParams.get('universalId');
82
+ const path = searchParams.get('path');
83
+ const query = searchParams.get('query');
84
+ return (
85
+ <Text
86
+ ellipsis
87
+ style={{ color: 'var(--ant-primary-color)', cursor: 'pointer' }}
88
+ onClick={() => {
89
+ let pathUrl = '';
90
+ if (path) {
91
+ pathUrl = path;
92
+ if (atob(query)) {
93
+ pathUrl += `?${atob(query)}`;
94
+ }
95
+ }
96
+ const appId =
97
+ saasIdInfoList.find((item) => item.universal_id === universal_id)
98
+ .oem_micro_app_id || '';
99
+ appId &&
100
+ window.open(`${window.location.origin}/apps/${appId}${pathUrl}`);
101
+ }}
102
+ >
103
+ {record.message_content}
104
+ </Text>
105
+ );
106
+ } else {
107
+ return <Text ellipsis>{record.message_content}</Text>;
108
+ }
109
+ };
110
+
111
+ const content = (
112
+ <List
113
+ className={cn(styles.resetList, 'main-app-message')}
114
+ header={
115
+ <span className={'main-app-message-title'}>
116
+ {t('notice.badge.title')}
117
+ </span>
118
+ }
119
+ itemLayout="horizontal"
120
+ dataSource={(list || []).slice(0, 4)}
121
+ footer={
122
+ <div className={cn(styles.footer, 'main-app-message-footer')}>
123
+ <span onClick={() => jumpNotice()}>{t('notice.badge.message')}</span>
124
+ </div>
125
+ }
126
+ renderItem={(item: Inotice) => (
127
+ <List.Item>
128
+ <List.Item.Meta
129
+ title={
130
+ <>
131
+
132
+ {item.message_type === '1'
133
+ ? t('notice.typeSelect.alert')
134
+ : t('notice.typeSelect.message')}
135
+ 】{item.create_time}
136
+ </>
137
+ }
138
+ description={<Desc record={item} />}
139
+ />
140
+ </List.Item>
141
+ )}
142
+ />
143
+ );
144
+
145
+ return (
146
+ <Popover
147
+ content={content}
148
+ trigger="hover"
149
+ visible={visible}
150
+ mouseLeaveDelay={0.3}
151
+ arrowPointAtCenter
152
+ placement="bottomRight"
153
+ onVisibleChange={onVisibleChange}
154
+ overlayStyle={{ width: 400 }}
155
+ overlayClassName={styles.resetPopover}
156
+ >
157
+ <div className={styles['wrap-badge']}>
158
+ <Badge
159
+ count={count}
160
+ size="small"
161
+ className={cn(styles.circle, {
162
+ [styles.multiple]: count > 9,
163
+ [styles.iconMargin]: count > 99,
164
+ })}
165
+ offset={offset(count)}
166
+ >
167
+ <a onClick={() => jumpNotice()}>
168
+ <IconFont
169
+ type="icon-bell"
170
+ className={cn(styles.icon, 'main-nav-text-color')}
171
+ />
172
+ </a>
173
+ </Badge>
174
+ </div>
175
+ </Popover>
176
+ );
177
+ };
178
+
179
+ export default Notice;