win-chart 1.0.0

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 (185) hide show
  1. package/.eslintrc.json +3 -0
  2. package/.prettierrc.json +5 -0
  3. package/README.md +0 -0
  4. package/localhost-key.pem +28 -0
  5. package/localhost.pem +25 -0
  6. package/package.json +65 -0
  7. package/rsbuild.config.ts +48 -0
  8. package/src/api/README.md +15 -0
  9. package/src/api/index.js +5 -0
  10. package/src/api/layout/index.js +32 -0
  11. package/src/api/request.ts +87 -0
  12. package/src/api/url-map/index.js +10 -0
  13. package/src/api/user/index.js +12 -0
  14. package/src/components/FilterContext.tsx +6 -0
  15. package/src/components/GlobalStyle.tsx +25 -0
  16. package/src/components/HalfScreenBrowser.tsx +95 -0
  17. package/src/components/ImgBox.tsx +19 -0
  18. package/src/components/JumpBtn.tsx +38 -0
  19. package/src/components/MCardWrapper.tsx +33 -0
  20. package/src/components/NoContent/index.tsx +85 -0
  21. package/src/components/ResponsiveReactGridLayout.tsx +218 -0
  22. package/src/components/SliderDecoration.tsx +27 -0
  23. package/src/components/VisionUserConfigContext.ts +6 -0
  24. package/src/components/WinMenu/README.md +11 -0
  25. package/src/components/WinMenu/WinHeader.tsx +5 -0
  26. package/src/components/WinMenu/components/ExtraBox.tsx +61 -0
  27. package/src/components/WinMenu/components/FullMenuBox.tsx +80 -0
  28. package/src/components/WinMenu/components/FullMenuContainer.tsx +50 -0
  29. package/src/components/WinMenu/components/FullMenuItem.tsx +128 -0
  30. package/src/components/WinMenu/components/LangSwitch.tsx +84 -0
  31. package/src/components/WinMenu/components/LogoBox.tsx +29 -0
  32. package/src/components/WinMenu/components/PinDialog.tsx +72 -0
  33. package/src/components/WinMenu/components/PinnedMenuBox.tsx +183 -0
  34. package/src/components/WinMenu/components/UserBox.tsx +83 -0
  35. package/src/components/WinMenu/hooks/useUserInfo.ts +21 -0
  36. package/src/components/WinMenu/hooks/useUserMenu.ts +35 -0
  37. package/src/components/WinMenu/index.tsx +100 -0
  38. package/src/components/WinMenu/services/WinService.ts +79 -0
  39. package/src/components/WinMenu/services/request.ts +53 -0
  40. package/src/components/WinMenu/utils/const.ts +80 -0
  41. package/src/components/WinMenu/utils/enum.ts +19 -0
  42. package/src/components/WinMenu/utils/interface.ts +61 -0
  43. package/src/components/WinMenu/utils/map.ts +39 -0
  44. package/src/components/WinMenu/utils/tool.ts +142 -0
  45. package/src/components/WinMenu/utils/type.ts +1 -0
  46. package/src/components/hover-view.tsx +48 -0
  47. package/src/components/icon.tsx +44 -0
  48. package/src/components/indicator-remark.tsx +25 -0
  49. package/src/components/none-content.tsx +93 -0
  50. package/src/components/panel-tab.tsx +150 -0
  51. package/src/components/panel-title-tab.tsx +60 -0
  52. package/src/components/win-card/components/ChartContent.tsx +47 -0
  53. package/src/components/win-card/components/Indicator.tsx +42 -0
  54. package/src/components/win-card/components/IndicatorArea.tsx +63 -0
  55. package/src/components/win-card/components/IndicatorInfo.tsx +78 -0
  56. package/src/components/win-card/components/MatterContent.tsx +121 -0
  57. package/src/components/win-card/components/MatterList.tsx +141 -0
  58. package/src/components/win-card/components/NoticeContent.tsx +73 -0
  59. package/src/components/win-card/components/NoticeList.tsx +68 -0
  60. package/src/components/win-card/components/SelectDecoration.tsx +34 -0
  61. package/src/components/win-card/components/WinRankContent.tsx +102 -0
  62. package/src/components/win-card/index.tsx +298 -0
  63. package/src/components/win-card/utils/interface.ts +12 -0
  64. package/src/components/win-card/utils/tool.ts +11 -0
  65. package/src/components/win-card-mobile/components/ChartContent.tsx +47 -0
  66. package/src/components/win-card-mobile/components/DualLineBar.tsx +61 -0
  67. package/src/components/win-card-mobile/components/Indicator.tsx +42 -0
  68. package/src/components/win-card-mobile/components/IndicatorArea.tsx +65 -0
  69. package/src/components/win-card-mobile/components/IndicatorInfo.tsx +83 -0
  70. package/src/components/win-card-mobile/components/SelectDecoration.tsx +28 -0
  71. package/src/components/win-card-mobile/index.tsx +235 -0
  72. package/src/components/win-card-mobile/utils/interface.ts +12 -0
  73. package/src/components/win-card-mobile/utils/tool.ts +9 -0
  74. package/src/components/win-chart/components/chart-wrapper.tsx +5 -0
  75. package/src/components/win-chart/index.tsx +59 -0
  76. package/src/components/win-chart/theme/win-dark.json +372 -0
  77. package/src/components/win-chart/theme/win-light.json +372 -0
  78. package/src/components/win-chart/utils/const.ts +37 -0
  79. package/src/components/win-chart/utils/getAreaSpec.ts +150 -0
  80. package/src/components/win-chart/utils/getBarSpec.ts +60 -0
  81. package/src/components/win-chart/utils/getChartOptions.ts +59 -0
  82. package/src/components/win-chart/utils/getColumnSpec.ts +112 -0
  83. package/src/components/win-chart/utils/getDualSpec.ts +79 -0
  84. package/src/components/win-chart/utils/getFunnelSpec.ts +70 -0
  85. package/src/components/win-chart/utils/getLineSpec.ts +53 -0
  86. package/src/components/win-chart/utils/getPieSpec.ts +124 -0
  87. package/src/components/win-chart/utils/getRadarSpec.ts +87 -0
  88. package/src/components/win-chart/utils/tool.ts +163 -0
  89. package/src/components/win-chart/utils/type.ts +96 -0
  90. package/src/components/win-icon/index.tsx +97 -0
  91. package/src/components/win-v/components/EmptyBox.tsx +9 -0
  92. package/src/components/win-v/components/VDialog.tsx +173 -0
  93. package/src/components/win-v/components/VDialogBtn.tsx +119 -0
  94. package/src/components/win-v/components/VDialogMsg.tsx +325 -0
  95. package/src/components/win-v/components/VInput.tsx +15 -0
  96. package/src/components/win-v/components/VRemindMsgList.tsx +303 -0
  97. package/src/components/win-v/components/VRobot.tsx +97 -0
  98. package/src/components/win-v/hooks/useVDialogCore.ts +102 -0
  99. package/src/components/win-v/hooks/useVDialogOperate.ts +132 -0
  100. package/src/components/win-v/hooks/useVDialogState.ts +52 -0
  101. package/src/components/win-v/hooks/useVRemindMsgShow.ts +15 -0
  102. package/src/components/win-v/index.tsx +205 -0
  103. package/src/components/win-wrappers/card-wrapper.tsx +103 -0
  104. package/src/components/win-wrappers/dot-wrapper.tsx +18 -0
  105. package/src/components/win-wrappers/iframe-wrapper.tsx +7 -0
  106. package/src/components/win-wrappers/request-wrapper.tsx +190 -0
  107. package/src/global.d.ts +53 -0
  108. package/src/hooks/useCardOptionList.ts +23 -0
  109. package/src/hooks/useCostFiltersDicList.ts +22 -0
  110. package/src/hooks/useFbiUrl.ts +22 -0
  111. package/src/hooks/useHalfScreenState.ts +50 -0
  112. package/src/hooks/useHasIntersected.ts +36 -0
  113. package/src/hooks/useIndicatorCardInfo.ts +26 -0
  114. package/src/hooks/useIndicatorCardQueryList.ts +22 -0
  115. package/src/hooks/useIndicatorClassifyList.ts +25 -0
  116. package/src/hooks/useIndicatorDetailsDateList.ts +22 -0
  117. package/src/hooks/useIndicatorDetailsInfo.ts +49 -0
  118. package/src/hooks/useIndicatorDetailsTrend.ts +25 -0
  119. package/src/hooks/useIndicatorDicList.ts +22 -0
  120. package/src/hooks/useIndicatorLabelList.ts +20 -0
  121. package/src/hooks/useIndicatorList.ts +24 -0
  122. package/src/hooks/useIndicatorRangeList.ts +20 -0
  123. package/src/hooks/useIndicatorTypeList.ts +20 -0
  124. package/src/hooks/useIndicatorUnitList.ts +21 -0
  125. package/src/hooks/useListenQuery.ts +29 -0
  126. package/src/hooks/useMobile.ts +58 -0
  127. package/src/hooks/useNotice.ts +42 -0
  128. package/src/hooks/useOrgLevelList.ts +23 -0
  129. package/src/hooks/usePageSelection.ts +121 -0
  130. package/src/hooks/usePageState.ts +22 -0
  131. package/src/hooks/usePendingList.ts +27 -0
  132. package/src/hooks/usePortalPageInfo.ts +43 -0
  133. package/src/hooks/useRefreshByLocationChange.ts +16 -0
  134. package/src/hooks/useReportIndicatorList.ts +21 -0
  135. package/src/hooks/useReportInfo.ts +45 -0
  136. package/src/hooks/useReportPersonList.ts +21 -0
  137. package/src/hooks/useScriptLoader.ts +22 -0
  138. package/src/hooks/useUnreadMsgList.ts +26 -0
  139. package/src/hooks/useUserAvatar.ts +23 -0
  140. package/src/hooks/useVReportInfo.ts +50 -0
  141. package/src/hooks/useVisionUserConfig.ts +25 -0
  142. package/src/hooks/useWorkbenchOptions.ts +63 -0
  143. package/src/index.tsx +20 -0
  144. package/src/services/CardService.ts +91 -0
  145. package/src/services/CommonService.ts +23 -0
  146. package/src/services/CostService.ts +56 -0
  147. package/src/services/DialogService.ts +74 -0
  148. package/src/services/IndicatorService.ts +406 -0
  149. package/src/services/PageService.ts +204 -0
  150. package/src/services/ReportService.ts +335 -0
  151. package/src/services/WorkbenchService.ts +411 -0
  152. package/src/styles/README.md +12 -0
  153. package/src/styles/index.scss +9 -0
  154. package/src/styles/mixins/index.scss +25 -0
  155. package/src/styles/next-cover.scss +4 -0
  156. package/src/styles/normalize.scss +27 -0
  157. package/src/styles/utilities/index.scss +5 -0
  158. package/src/styles/vars/index.scss +17 -0
  159. package/src/types/enum-workbench.ts +29 -0
  160. package/src/types/enum.ts +156 -0
  161. package/src/types/index.ts +19 -0
  162. package/src/types/indicator.ts +299 -0
  163. package/src/types/interface.ts +303 -0
  164. package/src/types/portal.ts +211 -0
  165. package/src/types/report.ts +28 -0
  166. package/src/types/type.ts +11 -0
  167. package/src/types/user.ts +28 -0
  168. package/src/utils/README.md +4 -0
  169. package/src/utils/arms.ts +59 -0
  170. package/src/utils/arr.ts +123 -0
  171. package/src/utils/const-workbench.ts +9 -0
  172. package/src/utils/const.ts +18 -0
  173. package/src/utils/index.ts +18 -0
  174. package/src/utils/init.ts +5 -0
  175. package/src/utils/map-workbench.ts +66 -0
  176. package/src/utils/map.ts +377 -0
  177. package/src/utils/number.ts +101 -0
  178. package/src/utils/page.ts +81 -0
  179. package/src/utils/str.ts +26 -0
  180. package/src/utils/tools.ts +44 -0
  181. package/src/utils/tree.ts +145 -0
  182. package/src/utils/url.ts +40 -0
  183. package/src/utils/util.ts +99 -0
  184. package/src/utils/workbench.ts +25 -0
  185. package/tsconfig.json +33 -0
@@ -0,0 +1,325 @@
1
+ import $i18n from 'panda-i18n';
2
+ import {
3
+ IDialogMsgInfo,
4
+ IIndicatorChangeInfo,
5
+ IIndicatorMsgChangeInfo,
6
+ } from '@/types';
7
+ import {
8
+ ITimeMarker,
9
+ RESPONSIVE_BREAKPOINT,
10
+ getHandleOpenLink,
11
+ isJsonString,
12
+ treeFlatToArr,
13
+ } from '@/utils';
14
+ import { rgba } from 'polished';
15
+ import { styled, css } from 'styled-components';
16
+ import {
17
+ OperateBtnBox,
18
+ RetryBtn,
19
+ LikeBtn,
20
+ CopyBtn,
21
+ FeedbackBtn,
22
+ } from './VDialogBtn';
23
+ import { CnBox, CnTable, ICnTableColumn } from '@cainiaofe/cn-ui';
24
+ import { CustomIcon } from '@/components/icon';
25
+ import { CSSProperties, memo, useEffect, useRef } from 'react';
26
+ import { useHasIntersected } from '@/hooks/useHasIntersected';
27
+ import { useVDialogOperate } from '../hooks/useVDialogOperate';
28
+ import { HoverView } from '@/components/hover-view';
29
+ import { useMobileState } from '@/hooks/useMobile';
30
+ import { useSetHalfScreenState } from '@/hooks/useHalfScreenState';
31
+
32
+ function isDialogMsgInfo(
33
+ data: Partial<IDialogMsgInfo> | ITimeMarker,
34
+ ): data is Partial<IDialogMsgInfo> {
35
+ return 'sender' in data;
36
+ }
37
+
38
+ interface IProps {
39
+ data: Partial<IDialogMsgInfo> | ITimeMarker;
40
+ retryMsg?: string;
41
+ }
42
+
43
+ export const VDialogMsg = memo(({ data, retryMsg }: IProps) => {
44
+ const msgRef = useRef<HTMLDivElement>(null);
45
+ const isShow = useHasIntersected(msgRef);
46
+ const { handleUpdateDialogMsg } = useVDialogOperate();
47
+ const isMobile = useMobileState();
48
+ const handleSetHalfScreenState = useSetHalfScreenState();
49
+
50
+ useEffect(() => {
51
+ if (
52
+ isDialogMsgInfo(data) &&
53
+ isShow &&
54
+ data.sender === '0' &&
55
+ data.status === 0
56
+ ) {
57
+ handleUpdateDialogMsg({
58
+ id: data.id,
59
+ status: 1,
60
+ });
61
+ }
62
+ }, [data, handleUpdateDialogMsg, isShow]);
63
+
64
+ if (data.type === 'time-marker') {
65
+ // 时间
66
+ return <TimeMarkerWrapper>{data.content}</TimeMarkerWrapper>;
67
+ }
68
+
69
+ // 消息
70
+ const msg = data as IDialogMsgInfo;
71
+ const isVMsg = msg.sender === '0';
72
+
73
+ const renderContent = () => {
74
+ if (msg.type === 'text_multiply' && isJsonString(msg.content)) {
75
+ // 指标变动提醒
76
+ const data: IIndicatorMsgChangeInfo = JSON.parse(msg.content!);
77
+ const codeList = treeFlatToArr(data.indicators).map((item) => item.code);
78
+
79
+ const handleClick = (url?: string) => {
80
+ if (url) {
81
+ if (isMobile) {
82
+ handleSetHalfScreenState({
83
+ show: true,
84
+ src: url,
85
+ title: $i18n.get({ id: 'IndicatorDetails', dm: '指标详情' }),
86
+ });
87
+ } else {
88
+ window.open(url);
89
+ }
90
+ }
91
+ };
92
+
93
+ return (
94
+ <ContentWrapper>
95
+ <CnBox direction="row" margin={[0, 0, 8, 0]}>
96
+ <span>📈</span>
97
+ <IndicatorChangeTitle>{data.msg}</IndicatorChangeTitle>
98
+ </CnBox>
99
+ <ChangeTable
100
+ primaryKey="code"
101
+ tree
102
+ columns={getTableColumn({ handleClick, isMobile })}
103
+ hasBorder={false}
104
+ dataSource={data.indicators}
105
+ treeConfig={{
106
+ defaultOpenKeys: codeList,
107
+ }}
108
+ />
109
+ <Remark>
110
+ {$i18n.get(
111
+ {
112
+ id: 'NoteComparisonWithDataLastVisitD_1983478722',
113
+ dm: '备注:与 {dataLastVisitDay} 日数据对比',
114
+ },
115
+ { dataLastVisitDay: data.lastVisitDay },
116
+ )}
117
+ </Remark>
118
+ </ContentWrapper>
119
+ );
120
+ }
121
+ return (
122
+ <ContentWrapper>
123
+ {isJsonString(data.content) ? '...' : data.content}
124
+ </ContentWrapper>
125
+ );
126
+ };
127
+
128
+ return (
129
+ <Wrapper $v={isVMsg} ref={msgRef}>
130
+ <MsgWrapper
131
+ $v={isVMsg}
132
+ $vLoading={msg.id === -2}
133
+ onClick={getHandleOpenLink(msg.url)}
134
+ style={{
135
+ cursor: msg.url ? 'pointer' : 'default',
136
+ }}
137
+ >
138
+ {renderContent()}
139
+ {data.type === 'text_retry' && (
140
+ <OperateBtnBox>
141
+ <RetryBtn {...msg} retryMsg={retryMsg} />
142
+ </OperateBtnBox>
143
+ )}
144
+
145
+ {data.type === 'text_general' && (
146
+ <OperateBtnBox>
147
+ <LikeBtn {...msg} />
148
+ <CopyBtn {...msg} />
149
+ <FeedbackBtn />
150
+ </OperateBtnBox>
151
+ )}
152
+ </MsgWrapper>
153
+ </Wrapper>
154
+ );
155
+ });
156
+
157
+ const TimeMarkerWrapper = styled.div`
158
+ display: flex;
159
+ justify-content: center;
160
+ align-items: center;
161
+ font-size: 12px;
162
+ color: #828b9e;
163
+ font-weight: 500;
164
+ margin-top: 20px;
165
+
166
+ @media (max-width: ${RESPONSIVE_BREAKPOINT}) {
167
+ font-size: 0.22rem;
168
+ margin-top: 0.32rem;
169
+ }
170
+ `;
171
+
172
+ const Wrapper = styled.div<{ $v?: boolean }>`
173
+ display: flex;
174
+ flex-direction: column;
175
+
176
+ ${(props) =>
177
+ props.$v
178
+ ? css``
179
+ : css`
180
+ align-items: flex-end;
181
+ `}
182
+
183
+ @media (max-width: ${RESPONSIVE_BREAKPOINT}) {
184
+ font-size: 0.28rem;
185
+ line-height: 0.42rem;
186
+ }
187
+ `;
188
+
189
+ const MsgWrapper = styled.div<{ $v?: boolean; $vLoading?: boolean }>`
190
+ padding: 12px;
191
+
192
+ ${(props) =>
193
+ props.$v
194
+ ? css`
195
+ border-radius: 0 12px 12px 12px;
196
+ background: ${rgba('#fff', 0.8)};
197
+ white-space: pre-wrap;
198
+ `
199
+ : css`
200
+ border-radius: 12px 0px 12px 12px;
201
+ background: ${rgba('#3379FF', 0.2)};
202
+ `}
203
+
204
+ ${(props) =>
205
+ props.$vLoading &&
206
+ css`
207
+ width: 80px;
208
+ height: 40px;
209
+ background: url(https://img.alicdn.com/imgextra/i1/O1CN01uHrkBb1D9jpaM5O47_!!6000000000174-1-tps-800-600.gif)
210
+ no-repeat center / cover;
211
+ `}
212
+ `;
213
+
214
+ const IndicatorChangeTitle = styled.div`
215
+ color: #272f3d;
216
+ font-size: 14px;
217
+ font-weight: 700;
218
+ `;
219
+
220
+ const ChangeTable = styled(CnTable).attrs({
221
+ style: {
222
+ borderRadius: '4px 4px 0 0',
223
+ },
224
+ })`
225
+ margin-bottom: 8px;
226
+ `;
227
+
228
+ const Remark = styled.div`
229
+ color: #828b9e;
230
+ font-size: 12px;
231
+ `;
232
+
233
+ const ContentWrapper = styled.div`
234
+ max-height: 50vh;
235
+ overflow-y: auto;
236
+
237
+ overflow-wrap: break-word;
238
+ word-break: break-all;
239
+ white-space: pre-wrap;
240
+
241
+ &::-webkit-scrollbar {
242
+ display: none;
243
+ }
244
+ `;
245
+
246
+ const getTableColumn = ({
247
+ handleClick,
248
+ isMobile,
249
+ }: {
250
+ isMobile?: boolean;
251
+ handleClick: (url?: string) => void;
252
+ }): ICnTableColumn[] => {
253
+ return [
254
+ {
255
+ title: $i18n.get({ id: 'ExamplesOfIndicators', dm: '指标实例' }),
256
+ dataIndex: 'name',
257
+ width: 120,
258
+ render: (value: string, row: IIndicatorChangeInfo) => {
259
+ const handleTitleClick = () => handleClick(row.url);
260
+ const style: CSSProperties = {
261
+ width: 120,
262
+ ...(row.url && {
263
+ cursor: 'pointer',
264
+ color: '#3379FF',
265
+ }),
266
+ };
267
+
268
+ return isMobile ? (
269
+ <MobileIndicatorChangeTitle onClick={handleTitleClick} style={style}>
270
+ {value}
271
+ </MobileIndicatorChangeTitle>
272
+ ) : (
273
+ <HoverView
274
+ content={value}
275
+ onClick={handleTitleClick}
276
+ cStyle={style}
277
+ />
278
+ );
279
+ },
280
+ },
281
+ {
282
+ title: $i18n.get({ id: 'ThisData', dm: '本次数据' }),
283
+ dataIndex: 'value',
284
+ align: 'right',
285
+ render: (value: number, row: IIndicatorChangeInfo) => {
286
+ return (
287
+ <span>
288
+ {value}
289
+ {row.unit}
290
+ </span>
291
+ );
292
+ },
293
+ },
294
+ {
295
+ title: $i18n.get({ id: 'NumberOfDifferences', dm: '差异数' }),
296
+ dataIndex: 'diff',
297
+ align: 'right',
298
+ render: (value: string) => {
299
+ if (value) {
300
+ const isDown = value.includes('-');
301
+ const color = isDown ? '#F15451' : '#00C267';
302
+ const type = isDown ? 'icon-RED_DOWN' : 'icon-GREEN_UP';
303
+ const content = isDown ? value.replace('-', '') : value;
304
+ return (
305
+ <CnBox
306
+ direction="row"
307
+ justify="flex-end"
308
+ align="center"
309
+ spacing={4}
310
+ >
311
+ <span style={{ color }}>{content}</span>
312
+ <CustomIcon type={type} size={12} />
313
+ </CnBox>
314
+ );
315
+ }
316
+ },
317
+ },
318
+ ];
319
+ };
320
+
321
+ const MobileIndicatorChangeTitle = styled.div`
322
+ overflow: hidden;
323
+ text-overflow: ellipsis;
324
+ white-space: nowrap;
325
+ `;
@@ -0,0 +1,15 @@
1
+ import TextInput from 'react-autocomplete-input';
2
+ // import 'react-autocomplete-input/dist/bundle.css';
3
+
4
+ export const VInput = () => {
5
+ return (
6
+ <div>
7
+ <TextInput
8
+ trigger={['@']}
9
+ options={{
10
+ '@': ['问题反馈'],
11
+ }}
12
+ />
13
+ </div>
14
+ );
15
+ };
@@ -0,0 +1,303 @@
1
+ import $i18n from 'panda-i18n';
2
+ import { IUnreadMsg } from 'src/types';
3
+ import { css, styled } from 'styled-components';
4
+ import { CustomIcon } from 'src/components/icon';
5
+ import { CnBox, CnDrawer, CnIcon } from '@cainiaofe/cn-ui';
6
+ import { useEffect, useRef, useState } from 'react';
7
+ import { arraySum, msgBizTypeMap } from 'src/utils';
8
+ import dayjs from 'dayjs';
9
+ import { useSetVDialogState } from '../hooks/useVDialogState';
10
+ import { useHalfScreenDispatch } from '@/hooks/useHalfScreenState';
11
+ import { useMobileState } from '@/hooks/useMobile';
12
+
13
+ interface IProps {
14
+ data: IUnreadMsg[];
15
+ onRefreshData: (id: number) => void;
16
+ }
17
+
18
+ export const VRemindMsgList = ({ data = [], onRefreshData }: IProps) => {
19
+ const [isFold, setIsFold] = useState(data.length > 1);
20
+ const listBoxRef = useRef<HTMLDivElement>(null);
21
+ const setVDialogState = useSetVDialogState();
22
+ const dispatch = useHalfScreenDispatch();
23
+ const isMobileDevice = useMobileState();
24
+ const [showDrawerBrowser, setShowDrawerBrowser] = useState<string>();
25
+ const msgIdRef = useRef<number>();
26
+
27
+ useEffect(() => {
28
+ if (listBoxRef.current) {
29
+ const items = Array.from<HTMLDivElement>(
30
+ listBoxRef.current.querySelectorAll('.msg-item'),
31
+ );
32
+ setVDialogState((state) => ({
33
+ ...state,
34
+ show: true,
35
+ }));
36
+
37
+ if (isFold) {
38
+ // 折叠
39
+ const heightList = mapToHeightList(items);
40
+ const showHeight = Math.min(heightList.at(0)!);
41
+
42
+ items.forEach((ele, index) => {
43
+ ele.style.height = `${showHeight}px`;
44
+ ele.style.top = '0px';
45
+
46
+ if (index !== 0) {
47
+ Array.from(ele.children ?? []).forEach((item) => {
48
+ (item as HTMLElement).style.opacity = '0';
49
+ });
50
+ }
51
+
52
+ if (index === 1) {
53
+ ele.style.transform = 'translateY(12px) scale(0.95)';
54
+ }
55
+
56
+ if (index > 1) {
57
+ ele.style.transform = 'translateY(24px) scale(0.9)';
58
+ }
59
+
60
+ if (index > 2) {
61
+ ele.style.display = 'none';
62
+ }
63
+ });
64
+
65
+ listBoxRef.current.style.height = `calc(${showHeight}px + 16px)`;
66
+ } else {
67
+ // 展开
68
+ // 隐藏小V对话
69
+ if (data.length !== 1) {
70
+ setVDialogState((state) => ({
71
+ ...state,
72
+ show: false,
73
+ }));
74
+ }
75
+
76
+ items.forEach((ele, index) => {
77
+ ele.style.height = '';
78
+
79
+ if (index !== 0) {
80
+ Array.from(ele.children ?? []).forEach((item) => {
81
+ (item as HTMLElement).style.opacity = '';
82
+ });
83
+ }
84
+
85
+ if (index > 2) {
86
+ ele.style.display = '';
87
+ }
88
+ });
89
+
90
+ const heightList = mapToHeightList(items);
91
+
92
+ items.forEach((ele, index) => {
93
+ ele.style.top = `calc(${arraySum(heightList.slice(0, index))}px + ${
94
+ index * 12
95
+ }px)`;
96
+ ele.style.transform = 'translateY(0) scale(1)';
97
+ });
98
+
99
+ listBoxRef.current.style.height = `calc(${arraySum(heightList)}px + ${
100
+ (heightList.length - 1) * 12
101
+ }px)`;
102
+ }
103
+ }
104
+ }, [isFold, data, setVDialogState]);
105
+
106
+ return (
107
+ <div
108
+ onClick={() => {
109
+ if (isFold) {
110
+ setIsFold(false);
111
+ }
112
+ }}
113
+ >
114
+ <CnBox direction="row" justify="flex-end">
115
+ <FoldBtn
116
+ $show={!isFold && data.length > 1}
117
+ onClick={() => setIsFold(true)}
118
+ >
119
+ <CnIcon
120
+ type="arrow-up"
121
+ size="medium"
122
+ style={{
123
+ marginRight: 8,
124
+ }}
125
+ />
126
+ {$i18n.get({ id: 'Folding', dm: '折叠' })}
127
+ </FoldBtn>
128
+ </CnBox>
129
+ <MsgListWrapper ref={listBoxRef}>
130
+ {data.map((item, index) => {
131
+ const { iconType, color } = msgBizTypeMap.get(item.bizType2) ?? {};
132
+ const handleClick = () => {
133
+ if (!isFold || data.length === 1) {
134
+ if (item.url) {
135
+ if (isMobileDevice) {
136
+ // 手机端
137
+ dispatch.setState({
138
+ show: true,
139
+ src: item.url,
140
+ title: item.title,
141
+ });
142
+ onRefreshData(item.id);
143
+ } else {
144
+ // PC端
145
+ if (['GOOD_HABITS'].includes(item.bizType2)) {
146
+ setShowDrawerBrowser(
147
+ item.url.replace('cainiao.com', 'cainiao-inc.com'),
148
+ );
149
+ } else {
150
+ globalThis.open(item.url);
151
+ onRefreshData(item.id);
152
+ }
153
+ }
154
+ } else {
155
+ onRefreshData(item.id);
156
+ }
157
+ } else {
158
+ setIsFold(true);
159
+ }
160
+ };
161
+ return (
162
+ <MsgWrapper
163
+ $index={index}
164
+ $fold={isFold}
165
+ className="msg-item"
166
+ key={item.id}
167
+ style={{
168
+ zIndex: data.length - index,
169
+ }}
170
+ onClick={handleClick}
171
+ >
172
+ <Remark>
173
+ <div data-type>
174
+ <CustomIcon
175
+ type={iconType}
176
+ size={16}
177
+ style={{
178
+ marginRight: 4,
179
+ }}
180
+ />
181
+
182
+ <span style={{ color }}>{item.bizTypeDesc2}</span>
183
+ </div>
184
+ <div data-time>
185
+ {dayjs(item.sendTime).format('YYYY.MM.DD HH:mm')}
186
+ </div>
187
+ </Remark>
188
+ <MsgContentWrapper>
189
+ <span data-title>{item.title}:</span>
190
+ <span>{item.content}</span>
191
+ </MsgContentWrapper>
192
+ </MsgWrapper>
193
+ );
194
+ })}
195
+ </MsgListWrapper>
196
+ <Drawer
197
+ visible={!!showDrawerBrowser}
198
+ onClose={() => {
199
+ setShowDrawerBrowser(undefined);
200
+ onRefreshData(msgIdRef.current!);
201
+ }}
202
+ >
203
+ <iframe src={showDrawerBrowser} data-iframe title="abc" />
204
+ </Drawer>
205
+ </div>
206
+ );
207
+ };
208
+
209
+ const mapToHeightList = (items: Element[]) =>
210
+ items
211
+ .map((item) => item.getBoundingClientRect().height)
212
+ .map((item, index) => {
213
+ if (index === 1) {
214
+ return item / 0.95;
215
+ }
216
+
217
+ if (index > 1) {
218
+ return item / 0.9;
219
+ }
220
+
221
+ return item;
222
+ });
223
+
224
+ const MsgListWrapper = styled.div`
225
+ display: grid;
226
+ gap: 16px;
227
+ position: relative;
228
+ transition: all 0.5s;
229
+ `;
230
+
231
+ const MsgWrapper = styled.div<{ $index: number; $fold: boolean }>`
232
+ width: 100%;
233
+ position: absolute;
234
+ left: 0;
235
+ top: 0;
236
+ background-color: #fff;
237
+ box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.06);
238
+ border-radius: 16px;
239
+ padding: 16px;
240
+ color: #272e3a;
241
+ transition: all 0.5s;
242
+ cursor: pointer;
243
+ `;
244
+
245
+ const Remark = styled.div`
246
+ width: 100%;
247
+ font-size: 12px;
248
+ display: flex;
249
+ justify-content: space-between;
250
+ align-items: center;
251
+ margin-bottom: 8px;
252
+
253
+ [data-type] {
254
+ display: flex;
255
+ align-items: center;
256
+ color: #3379ff;
257
+ }
258
+
259
+ [data-time] {
260
+ color: #828b9e;
261
+ }
262
+ `;
263
+
264
+ const MsgContentWrapper = styled.div`
265
+ font-size: 14px;
266
+ line-height: 20px;
267
+
268
+ [data-title] {
269
+ font-weight: 700;
270
+ }
271
+ `;
272
+
273
+ const FoldBtn = styled.div<{ $show: boolean }>`
274
+ width: 80px;
275
+ height: 32px;
276
+ border-radius: 16px;
277
+ color: #828b9e;
278
+ font-size: 14px;
279
+ background-color: #ffffff;
280
+ box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.06);
281
+ margin-bottom: 12px;
282
+ display: flex;
283
+ justify-content: center;
284
+ align-items: center;
285
+ cursor: pointer;
286
+
287
+ ${(props) =>
288
+ !props.$show &&
289
+ css`
290
+ display: none;
291
+ `}
292
+ `;
293
+
294
+ const Drawer = styled(CnDrawer).attrs({
295
+ width: 430,
296
+ noCard: true,
297
+ })`
298
+ [data-iframe] {
299
+ border: none;
300
+ width: 100%;
301
+ height: calc(100vh - 70px);
302
+ }
303
+ `;