neo-cmp-cli 1.1.6 → 1.1.8
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.
- package/package.json +1 -1
- package/src/module/index.js +5 -0
- package/src/module/main.js +3 -3
- package/src/module/neoInitByCopy.js +4 -0
- package/src/template/antd-custom-cmp-template/.prettierrc.js +12 -0
- package/src/template/antd-custom-cmp-template/README.md +47 -0
- package/src/template/antd-custom-cmp-template/commitlint.config.js +59 -0
- package/src/template/antd-custom-cmp-template/neo.config.js +109 -0
- package/src/template/antd-custom-cmp-template/package.json +59 -0
- package/src/template/antd-custom-cmp-template/public/css/base.css +283 -0
- package/src/template/antd-custom-cmp-template/public/scripts/app/bluebird.js +6679 -0
- package/src/template/antd-custom-cmp-template/public/template.html +13 -0
- package/src/template/antd-custom-cmp-template/src/assets/css/common.scss +127 -0
- package/src/template/antd-custom-cmp-template/src/assets/css/mixin.scss +47 -0
- package/src/template/antd-custom-cmp-template/src/components/data-dashboard/README.md +39 -0
- package/src/template/antd-custom-cmp-template/src/components/data-dashboard/index.tsx +462 -0
- package/src/template/antd-custom-cmp-template/src/components/data-dashboard/model.ts +76 -0
- package/src/template/antd-custom-cmp-template/src/components/data-dashboard/style.scss +1409 -0
- package/src/template/antd-custom-cmp-template/src/components/info-card/index.tsx +72 -0
- package/src/template/antd-custom-cmp-template/src/components/info-card/model.ts +78 -0
- package/src/template/antd-custom-cmp-template/src/components/info-card/style.scss +105 -0
- package/src/template/antd-custom-cmp-template/tsconfig.json +68 -0
- package/src/template/echart-custom-cmp-template/.prettierrc.js +12 -0
- package/src/template/echart-custom-cmp-template/README.md +47 -0
- package/src/template/echart-custom-cmp-template/commitlint.config.js +59 -0
- package/src/template/echart-custom-cmp-template/neo.config.js +109 -0
- package/src/template/echart-custom-cmp-template/package.json +58 -0
- package/src/template/echart-custom-cmp-template/public/css/base.css +283 -0
- package/src/template/echart-custom-cmp-template/public/scripts/app/bluebird.js +6679 -0
- package/src/template/echart-custom-cmp-template/public/template.html +13 -0
- package/src/template/echart-custom-cmp-template/src/assets/css/common.scss +127 -0
- package/src/template/echart-custom-cmp-template/src/assets/css/mixin.scss +47 -0
- package/src/template/echart-custom-cmp-template/src/components/info-card/index.tsx +69 -0
- package/src/template/echart-custom-cmp-template/src/components/info-card/model.ts +78 -0
- package/src/template/echart-custom-cmp-template/src/components/info-card/style.scss +105 -0
- package/src/template/echart-custom-cmp-template/src/components/list-widget/README.md +2 -0
- package/src/template/echart-custom-cmp-template/src/components/list-widget/index.tsx +208 -0
- package/src/template/echart-custom-cmp-template/src/components/list-widget/model.ts +90 -0
- package/src/template/echart-custom-cmp-template/src/components/list-widget/style.scss +350 -0
- package/src/template/echart-custom-cmp-template/tsconfig.json +68 -0
- package/src/template/react-custom-cmp-template/package.json +2 -2
- package/src/template/react-ts-custom-cmp-template/package.json +2 -3
- package/src/template/react-ts-custom-cmp-template/src/components/info-card/index.tsx +0 -3
- package/src/template/vue2-custom-cmp-template/package.json +2 -2
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<html lang="en">
|
|
2
|
+
<head>
|
|
3
|
+
<meta charset="UTF-8">
|
|
4
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
5
|
+
<meta name="format-detection" content="telephone=no"/>
|
|
6
|
+
<meta name="viewport" content="initial-scale=1.0,user-scalable=no,width=device-width,viewport-fit=cover">
|
|
7
|
+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
8
|
+
<title>自定义组件预览页</title>
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/* 公共的自定义函数 */
|
|
2
|
+
|
|
3
|
+
@function px2vw($px, $screen-width: 750) {
|
|
4
|
+
@return ($px / $screen-width) * 100vw;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
@function px2rem($px, $remRate: 100) {
|
|
8
|
+
@return ($px / $remRate) + rem;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
@function px2vmin($px, $screen-width: 750) {
|
|
12
|
+
@return ($px / $screen-width) * 100vmin;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@mixin fillBox {
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100%;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* 头部细线 */
|
|
21
|
+
@mixin borderTop {
|
|
22
|
+
content: '';
|
|
23
|
+
position: absolute;
|
|
24
|
+
left: 0;
|
|
25
|
+
right: 0;
|
|
26
|
+
top: 0;
|
|
27
|
+
width: 100%;
|
|
28
|
+
height: 1px;
|
|
29
|
+
background: #ddd;
|
|
30
|
+
transform: scaleY(0.5);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* 底部细线 */
|
|
34
|
+
@mixin borderBtm {
|
|
35
|
+
content: '';
|
|
36
|
+
position: absolute;
|
|
37
|
+
left: 0;
|
|
38
|
+
right: 0;
|
|
39
|
+
bottom: 0;
|
|
40
|
+
width: 100%;
|
|
41
|
+
height: 1px;
|
|
42
|
+
background: #ddd;
|
|
43
|
+
transform: scaleY(0.5);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* 统一的内边距 */
|
|
47
|
+
@mixin unifiedPadding($value: 40) {
|
|
48
|
+
padding: 0 px2rem($value) 0 px2rem($value);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* 统一的左内边距 */
|
|
52
|
+
@mixin unifiedLeftPadding($value: 40) {
|
|
53
|
+
padding-left: px2rem($value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* 统一的右内边距 */
|
|
57
|
+
@mixin unifiedRightPadding($value: 40) {
|
|
58
|
+
padding-right: px2rem($value);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* 统一的底部边框样式 */
|
|
62
|
+
@mixin unifiedBottomBorder {
|
|
63
|
+
border-bottom: 1px solid #ddd;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/* 统一的上边框样式 */
|
|
67
|
+
@mixin unifiedTopBorder {
|
|
68
|
+
border-top: 1px solid #ddd;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* 统一的Item高度 */
|
|
72
|
+
@mixin unifiedItemHeight {
|
|
73
|
+
line-height: px2rem(120);
|
|
74
|
+
height: px2rem(120);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* 设置行高样式 */
|
|
78
|
+
@mixin setItemHeight($value: 120) {
|
|
79
|
+
line-height: px2rem($value);
|
|
80
|
+
height: px2rem($value);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* 统一的Item样式 */
|
|
84
|
+
@mixin unifiedItemStyle {
|
|
85
|
+
font-family: PingFangSC-Regular;
|
|
86
|
+
font-size: px2rem(28);
|
|
87
|
+
color: #828282;
|
|
88
|
+
letter-spacing: 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* 统一的弹性盒子样式 */
|
|
92
|
+
@mixin unifiedFlexBoxStyle {
|
|
93
|
+
display: flex;
|
|
94
|
+
flex-wrap: nowrap;
|
|
95
|
+
justify-content: center;
|
|
96
|
+
align-items: center;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* 统一的Title样式 */
|
|
100
|
+
@mixin unifiedTitleStyle {
|
|
101
|
+
font-family: PingFangSC-Regular;
|
|
102
|
+
font-size: px2rem(40);
|
|
103
|
+
color: #1e1e1e;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* 统一的内容样式 */
|
|
107
|
+
@mixin unifiedContentStyle {
|
|
108
|
+
font-family: PingFangSC-Regular;
|
|
109
|
+
font-size: px2rem(28);
|
|
110
|
+
color: #1e1e1e;
|
|
111
|
+
letter-spacing: 0;
|
|
112
|
+
text-align: right;
|
|
113
|
+
line-height: px2rem(28);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/* 底部导航盒子样式 */
|
|
117
|
+
@mixin fixedBottomBox {
|
|
118
|
+
position: fixed;
|
|
119
|
+
left: 0;
|
|
120
|
+
bottom: 0;
|
|
121
|
+
width: 100%;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 常用的变量
|
|
125
|
+
$background-color: #fafafa;
|
|
126
|
+
$border-color: #f7f7f7;
|
|
127
|
+
$page-padding-top: px2rem(20);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// 通用mixin
|
|
2
|
+
$borderColor: #ddd;
|
|
3
|
+
|
|
4
|
+
// type 为top 或者 bottom
|
|
5
|
+
@mixin borderTopOrBtm($type) {
|
|
6
|
+
&::after {
|
|
7
|
+
content: '';
|
|
8
|
+
position: absolute;
|
|
9
|
+
left: 0;
|
|
10
|
+
right: 0;
|
|
11
|
+
#{$type}: 0;
|
|
12
|
+
width: 100%;
|
|
13
|
+
height: 1px;
|
|
14
|
+
background: $borderColor;
|
|
15
|
+
transform: scaleY(0.5);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// type为 right 或者 left
|
|
20
|
+
@mixin borderRtOrLt($type) {
|
|
21
|
+
&::after {
|
|
22
|
+
content: '';
|
|
23
|
+
position: absolute;
|
|
24
|
+
top: 0;
|
|
25
|
+
bottom: 0;
|
|
26
|
+
#{$type}: 0;
|
|
27
|
+
height: 100%;
|
|
28
|
+
width: 1px;
|
|
29
|
+
background: $borderColor;
|
|
30
|
+
transform: scaleX(0.5);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//超出1行显示...
|
|
35
|
+
@mixin ellipsis1 {
|
|
36
|
+
overflow: hidden;
|
|
37
|
+
text-overflow: ellipsis;
|
|
38
|
+
white-space: nowrap;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 超出多行显示...
|
|
42
|
+
@mixin ellipsis($num) {
|
|
43
|
+
overflow: hidden;
|
|
44
|
+
display: -webkit-box;
|
|
45
|
+
-webkit-line-clamp: $num;
|
|
46
|
+
-webkit-box-orient: vertical;
|
|
47
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
### 特别说明
|
|
2
|
+
- 这是通过 Cursor 生成的一个自定义组件示例
|
|
3
|
+
|
|
4
|
+
### 数据仪表板组件特性
|
|
5
|
+
|
|
6
|
+
#### ✨ 核心功能
|
|
7
|
+
- 动态数据展示 - 使用 Mock 数据模拟实时数据更新
|
|
8
|
+
- 多种主题支持 - 渐变、深色、浅色三种主题
|
|
9
|
+
- 流畅动画效果 - 包含淡入、脉冲、发光、浮动等多种动画
|
|
10
|
+
- 响应式设计 - 完美适配各种屏幕尺寸
|
|
11
|
+
|
|
12
|
+
#### 界面特点
|
|
13
|
+
- 渐变背景 - 使用 CSS 渐变和毛玻璃效果
|
|
14
|
+
- 卡片式布局 - 现代化的卡片设计,支持悬停效果
|
|
15
|
+
- 图标系统 - 丰富的 Antd 图标,增强视觉效果
|
|
16
|
+
- 数据可视化 - 进度条、徽章、统计数字等元素
|
|
17
|
+
|
|
18
|
+
#### 📊 数据模块
|
|
19
|
+
- 核心指标 - 总用户数、订单数、收入、转化率
|
|
20
|
+
- 热门产品 - 产品销量排行,带增长趋势
|
|
21
|
+
- 实时动态 - 用户活动流,支持点赞和查看
|
|
22
|
+
- 性能指标 - 系统性能监控,带目标对比
|
|
23
|
+
- 活跃用户 - 圆形头像展示,浮动动画效果
|
|
24
|
+
|
|
25
|
+
#### 🔧 技术特性
|
|
26
|
+
- TypeScript 支持 - 完整的类型定义
|
|
27
|
+
- Antd 4.9.4 兼容 - 使用指定版本的组件
|
|
28
|
+
- SCSS 样式 - 模块化样式管理
|
|
29
|
+
- 自动数据更新 - 10秒间隔自动刷新数据
|
|
30
|
+
- 加载状态 - 数据更新时的加载动画
|
|
31
|
+
|
|
32
|
+
#### 交互体验
|
|
33
|
+
- 悬停效果 - 卡片悬停时的动画和阴影
|
|
34
|
+
- 点击反馈 - 按钮和卡片的点击反馈
|
|
35
|
+
- 平滑过渡 - 所有状态变化都有平滑过渡
|
|
36
|
+
- 视觉层次 - 清晰的信息层次和视觉引导
|
|
37
|
+
|
|
38
|
+
#### 属性配置
|
|
39
|
+
支持在编辑器中配置标题、主题和动画开关等属性
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Card,
|
|
4
|
+
Statistic,
|
|
5
|
+
Row,
|
|
6
|
+
Col,
|
|
7
|
+
Progress,
|
|
8
|
+
Badge,
|
|
9
|
+
Avatar,
|
|
10
|
+
Tag,
|
|
11
|
+
Button,
|
|
12
|
+
Tooltip,
|
|
13
|
+
Spin,
|
|
14
|
+
} from 'antd';
|
|
15
|
+
import {
|
|
16
|
+
UserOutlined,
|
|
17
|
+
ShoppingCartOutlined,
|
|
18
|
+
DollarOutlined,
|
|
19
|
+
TrophyOutlined,
|
|
20
|
+
FireOutlined,
|
|
21
|
+
ThunderboltOutlined,
|
|
22
|
+
StarOutlined,
|
|
23
|
+
HeartOutlined,
|
|
24
|
+
EyeOutlined,
|
|
25
|
+
LikeOutlined,
|
|
26
|
+
} from '@ant-design/icons';
|
|
27
|
+
import './style.scss';
|
|
28
|
+
|
|
29
|
+
interface DataDashboardProps {
|
|
30
|
+
title: string;
|
|
31
|
+
theme: 'dark' | 'light' | 'gradient';
|
|
32
|
+
showAnimations: boolean;
|
|
33
|
+
data?: any;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface MockData {
|
|
37
|
+
totalUsers: number;
|
|
38
|
+
totalOrders: number;
|
|
39
|
+
totalRevenue: number;
|
|
40
|
+
conversionRate: number;
|
|
41
|
+
activeUsers: number;
|
|
42
|
+
topProducts: Array<{
|
|
43
|
+
name: string;
|
|
44
|
+
sales: number;
|
|
45
|
+
growth: number;
|
|
46
|
+
color: string;
|
|
47
|
+
}>;
|
|
48
|
+
recentActivities: Array<{
|
|
49
|
+
id: string;
|
|
50
|
+
user: string;
|
|
51
|
+
action: string;
|
|
52
|
+
time: string;
|
|
53
|
+
avatar: string;
|
|
54
|
+
}>;
|
|
55
|
+
performanceMetrics: Array<{
|
|
56
|
+
name: string;
|
|
57
|
+
value: number;
|
|
58
|
+
target: number;
|
|
59
|
+
color: string;
|
|
60
|
+
}>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default class DataDashboard extends React.PureComponent<DataDashboardProps> {
|
|
64
|
+
private animationTimer: NodeJS.Timeout | null = null;
|
|
65
|
+
|
|
66
|
+
private dataUpdateTimer: NodeJS.Timeout | null = null;
|
|
67
|
+
|
|
68
|
+
constructor(props: DataDashboardProps) {
|
|
69
|
+
super(props);
|
|
70
|
+
this.state = {
|
|
71
|
+
currentData: this.generateMockData(),
|
|
72
|
+
isAnimating: false,
|
|
73
|
+
loading: false,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
componentDidMount() {
|
|
78
|
+
if (this.props.showAnimations) {
|
|
79
|
+
this.startDataAnimation();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
componentWillUnmount() {
|
|
84
|
+
if (this.animationTimer) {
|
|
85
|
+
clearInterval(this.animationTimer);
|
|
86
|
+
}
|
|
87
|
+
if (this.dataUpdateTimer) {
|
|
88
|
+
clearInterval(this.dataUpdateTimer);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
generateMockData = (): MockData => ({
|
|
93
|
+
totalUsers: Math.floor(Math.random() * 50000) + 10000,
|
|
94
|
+
totalOrders: Math.floor(Math.random() * 10000) + 2000,
|
|
95
|
+
totalRevenue: Math.floor(Math.random() * 1000000) + 500000,
|
|
96
|
+
conversionRate: Math.floor(Math.random() * 30) + 5,
|
|
97
|
+
activeUsers: Math.floor(Math.random() * 5000) + 1000,
|
|
98
|
+
topProducts: [
|
|
99
|
+
{ name: '智能手表', sales: 1250, growth: 15.6, color: '#1890ff' },
|
|
100
|
+
{ name: '无线耳机', sales: 980, growth: 8.2, color: '#52c41a' },
|
|
101
|
+
{ name: '智能音箱', sales: 756, growth: -2.1, color: '#faad14' },
|
|
102
|
+
{ name: '平板电脑', sales: 634, growth: 12.8, color: '#f5222d' },
|
|
103
|
+
{ name: '智能手环', sales: 520, growth: 25.3, color: '#722ed1' },
|
|
104
|
+
],
|
|
105
|
+
recentActivities: [
|
|
106
|
+
{
|
|
107
|
+
id: '1',
|
|
108
|
+
user: '张三',
|
|
109
|
+
action: '购买了智能手表',
|
|
110
|
+
time: '2分钟前',
|
|
111
|
+
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=1',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
id: '2',
|
|
115
|
+
user: '李四',
|
|
116
|
+
action: '完成了订单支付',
|
|
117
|
+
time: '5分钟前',
|
|
118
|
+
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=2',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: '3',
|
|
122
|
+
user: '王五',
|
|
123
|
+
action: '添加了商品到购物车',
|
|
124
|
+
time: '8分钟前',
|
|
125
|
+
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=3',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
id: '4',
|
|
129
|
+
user: '赵六',
|
|
130
|
+
action: '发表了产品评价',
|
|
131
|
+
time: '12分钟前',
|
|
132
|
+
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=4',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: '5',
|
|
136
|
+
user: '钱七',
|
|
137
|
+
action: '分享了产品链接',
|
|
138
|
+
time: '15分钟前',
|
|
139
|
+
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=5',
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
performanceMetrics: [
|
|
143
|
+
{ name: '页面加载速度', value: 85, target: 90, color: '#1890ff' },
|
|
144
|
+
{ name: '用户满意度', value: 92, target: 95, color: '#52c41a' },
|
|
145
|
+
{ name: '系统稳定性', value: 98, target: 99, color: '#faad14' },
|
|
146
|
+
{ name: '数据准确性', value: 96, target: 98, color: '#f5222d' },
|
|
147
|
+
],
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
startDataAnimation = () => {
|
|
151
|
+
this.dataUpdateTimer = setInterval(() => {
|
|
152
|
+
this.setState({ loading: true });
|
|
153
|
+
setTimeout(() => {
|
|
154
|
+
this.setState({
|
|
155
|
+
currentData: this.generateMockData(),
|
|
156
|
+
loading: false,
|
|
157
|
+
isAnimating: true,
|
|
158
|
+
});
|
|
159
|
+
setTimeout(() => {
|
|
160
|
+
this.setState({ isAnimating: false });
|
|
161
|
+
}, 1000);
|
|
162
|
+
}, 500);
|
|
163
|
+
}, 10000);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
formatNumber = (num: number): string => {
|
|
167
|
+
if (num >= 1000000) {
|
|
168
|
+
return `${(num / 1000000).toFixed(1)}M`;
|
|
169
|
+
}
|
|
170
|
+
if (num >= 1000) {
|
|
171
|
+
return `${(num / 1000).toFixed(1)}K`;
|
|
172
|
+
}
|
|
173
|
+
return num.toString();
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
render() {
|
|
177
|
+
const { title, theme, showAnimations } = this.props;
|
|
178
|
+
const { currentData, isAnimating, loading } = this.state as any;
|
|
179
|
+
const curAmisData = this.props.data || {};
|
|
180
|
+
|
|
181
|
+
const userInfo = curAmisData.__NeoCurrentUser;
|
|
182
|
+
const systemInfo = curAmisData.__NeoSystemInfo || {};
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<div
|
|
186
|
+
className={`data-dashboard-container ${theme} ${
|
|
187
|
+
isAnimating ? 'animating' : ''
|
|
188
|
+
}`}
|
|
189
|
+
>
|
|
190
|
+
<div className="dashboard-header">
|
|
191
|
+
<h2 className="dashboard-title">
|
|
192
|
+
{title || '数据仪表板'}
|
|
193
|
+
{systemInfo.tenantName && (
|
|
194
|
+
<Tag color="blue">【{systemInfo.tenantName}】</Tag>
|
|
195
|
+
)}
|
|
196
|
+
</h2>
|
|
197
|
+
{userInfo && (
|
|
198
|
+
<div className="user-info">
|
|
199
|
+
<Avatar size={40} src={userInfo.icon} icon={<UserOutlined />} />
|
|
200
|
+
<span className="user-name">{userInfo.name}</span>
|
|
201
|
+
</div>
|
|
202
|
+
)}
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<Spin spinning={loading} tip="数据更新中...">
|
|
206
|
+
<div className="dashboard-content">
|
|
207
|
+
{/* 核心指标卡片 */}
|
|
208
|
+
<Row gutter={[16, 16]} className="metrics-row">
|
|
209
|
+
<Col xs={24} sm={12} lg={6}>
|
|
210
|
+
<Card className="metric-card users-card" hoverable>
|
|
211
|
+
<Statistic
|
|
212
|
+
title="总用户数"
|
|
213
|
+
value={currentData.totalUsers}
|
|
214
|
+
formatter={(value) => this.formatNumber(value as number)}
|
|
215
|
+
prefix={<UserOutlined className="metric-icon" />}
|
|
216
|
+
valueStyle={{ color: '#1890ff' }}
|
|
217
|
+
/>
|
|
218
|
+
<div className="metric-trend">
|
|
219
|
+
<Badge count="+12.5%" color="#52c41a" />
|
|
220
|
+
<span className="trend-text">较上月</span>
|
|
221
|
+
</div>
|
|
222
|
+
</Card>
|
|
223
|
+
</Col>
|
|
224
|
+
<Col xs={24} sm={12} lg={6}>
|
|
225
|
+
<Card className="metric-card orders-card" hoverable>
|
|
226
|
+
<Statistic
|
|
227
|
+
title="总订单数"
|
|
228
|
+
value={currentData.totalOrders}
|
|
229
|
+
formatter={(value) => this.formatNumber(value as number)}
|
|
230
|
+
prefix={<ShoppingCartOutlined className="metric-icon" />}
|
|
231
|
+
valueStyle={{ color: '#52c41a' }}
|
|
232
|
+
/>
|
|
233
|
+
<div className="metric-trend">
|
|
234
|
+
<Badge count="+8.3%" color="#52c41a" />
|
|
235
|
+
<span className="trend-text">较上月</span>
|
|
236
|
+
</div>
|
|
237
|
+
</Card>
|
|
238
|
+
</Col>
|
|
239
|
+
<Col xs={24} sm={12} lg={6}>
|
|
240
|
+
<Card className="metric-card revenue-card" hoverable>
|
|
241
|
+
<Statistic
|
|
242
|
+
title="总收入"
|
|
243
|
+
value={currentData.totalRevenue}
|
|
244
|
+
formatter={(value) =>
|
|
245
|
+
`¥${this.formatNumber(value as number)}`
|
|
246
|
+
}
|
|
247
|
+
prefix={<DollarOutlined className="metric-icon" />}
|
|
248
|
+
valueStyle={{ color: '#faad14' }}
|
|
249
|
+
/>
|
|
250
|
+
<div className="metric-trend">
|
|
251
|
+
<Badge count="+15.2%" color="#52c41a" />
|
|
252
|
+
<span className="trend-text">较上月</span>
|
|
253
|
+
</div>
|
|
254
|
+
</Card>
|
|
255
|
+
</Col>
|
|
256
|
+
<Col xs={24} sm={12} lg={6}>
|
|
257
|
+
<Card className="metric-card conversion-card" hoverable>
|
|
258
|
+
<Statistic
|
|
259
|
+
title="转化率"
|
|
260
|
+
value={currentData.conversionRate}
|
|
261
|
+
suffix="%"
|
|
262
|
+
prefix={<TrophyOutlined className="metric-icon" />}
|
|
263
|
+
valueStyle={{ color: '#f5222d' }}
|
|
264
|
+
/>
|
|
265
|
+
<div className="metric-trend">
|
|
266
|
+
<Badge count="+2.1%" color="#52c41a" />
|
|
267
|
+
<span className="trend-text">较上月</span>
|
|
268
|
+
</div>
|
|
269
|
+
</Card>
|
|
270
|
+
</Col>
|
|
271
|
+
</Row>
|
|
272
|
+
|
|
273
|
+
{/* 热门产品和活动动态 */}
|
|
274
|
+
<Row gutter={[16, 16]} className="content-row">
|
|
275
|
+
<Col xs={24} lg={12}>
|
|
276
|
+
<Card
|
|
277
|
+
title={
|
|
278
|
+
<span>
|
|
279
|
+
<FireOutlined className="section-icon" />
|
|
280
|
+
热门产品
|
|
281
|
+
</span>
|
|
282
|
+
}
|
|
283
|
+
className="products-card"
|
|
284
|
+
extra={<Button type="link">查看全部</Button>}
|
|
285
|
+
>
|
|
286
|
+
<div className="products-list">
|
|
287
|
+
{currentData.topProducts.map(
|
|
288
|
+
(product: any, index: number) => (
|
|
289
|
+
<div key={index} className="product-item">
|
|
290
|
+
<div className="product-info">
|
|
291
|
+
<div className="product-name">{product.name}</div>
|
|
292
|
+
<div className="product-sales">
|
|
293
|
+
{product.sales} 销量
|
|
294
|
+
</div>
|
|
295
|
+
</div>
|
|
296
|
+
<div className="product-growth">
|
|
297
|
+
<Tag color={product.growth > 0 ? 'green' : 'red'}>
|
|
298
|
+
{product.growth > 0 ? '+' : ''}
|
|
299
|
+
{product.growth}%
|
|
300
|
+
</Tag>
|
|
301
|
+
</div>
|
|
302
|
+
<div className="product-progress">
|
|
303
|
+
<Progress
|
|
304
|
+
percent={Math.min(
|
|
305
|
+
(product.sales / 1500) * 100,
|
|
306
|
+
100,
|
|
307
|
+
)}
|
|
308
|
+
strokeColor={product.color}
|
|
309
|
+
showInfo={false}
|
|
310
|
+
size="small"
|
|
311
|
+
/>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
),
|
|
315
|
+
)}
|
|
316
|
+
</div>
|
|
317
|
+
</Card>
|
|
318
|
+
</Col>
|
|
319
|
+
<Col xs={24} lg={12}>
|
|
320
|
+
<Card
|
|
321
|
+
title={
|
|
322
|
+
<span>
|
|
323
|
+
<ThunderboltOutlined className="section-icon" />
|
|
324
|
+
实时动态
|
|
325
|
+
</span>
|
|
326
|
+
}
|
|
327
|
+
className="activities-card"
|
|
328
|
+
extra={<Button type="link">查看全部</Button>}
|
|
329
|
+
>
|
|
330
|
+
<div className="activities-list">
|
|
331
|
+
{currentData.recentActivities.map((activity: any) => (
|
|
332
|
+
<div key={activity.id} className="activity-item">
|
|
333
|
+
<Avatar
|
|
334
|
+
size={32}
|
|
335
|
+
src={activity.avatar}
|
|
336
|
+
icon={<UserOutlined />}
|
|
337
|
+
/>
|
|
338
|
+
<div className="activity-content">
|
|
339
|
+
<div className="activity-text">
|
|
340
|
+
<span className="user-name">{activity.user}</span>
|
|
341
|
+
<span className="action">{activity.action}</span>
|
|
342
|
+
</div>
|
|
343
|
+
<div className="activity-time">{activity.time}</div>
|
|
344
|
+
</div>
|
|
345
|
+
<div className="activity-actions">
|
|
346
|
+
<Tooltip title="点赞">
|
|
347
|
+
<Button
|
|
348
|
+
type="text"
|
|
349
|
+
icon={<LikeOutlined />}
|
|
350
|
+
size="small"
|
|
351
|
+
/>
|
|
352
|
+
</Tooltip>
|
|
353
|
+
<Tooltip title="查看">
|
|
354
|
+
<Button
|
|
355
|
+
type="text"
|
|
356
|
+
icon={<EyeOutlined />}
|
|
357
|
+
size="small"
|
|
358
|
+
/>
|
|
359
|
+
</Tooltip>
|
|
360
|
+
</div>
|
|
361
|
+
</div>
|
|
362
|
+
))}
|
|
363
|
+
</div>
|
|
364
|
+
</Card>
|
|
365
|
+
</Col>
|
|
366
|
+
</Row>
|
|
367
|
+
|
|
368
|
+
{/* 性能指标 */}
|
|
369
|
+
<Row gutter={[16, 16]} className="performance-row">
|
|
370
|
+
<Col xs={24}>
|
|
371
|
+
<Card
|
|
372
|
+
title={
|
|
373
|
+
<span>
|
|
374
|
+
<StarOutlined className="section-icon" />
|
|
375
|
+
性能指标
|
|
376
|
+
</span>
|
|
377
|
+
}
|
|
378
|
+
className="performance-card"
|
|
379
|
+
>
|
|
380
|
+
<Row gutter={[16, 16]}>
|
|
381
|
+
{currentData.performanceMetrics.map(
|
|
382
|
+
(metric: any, index: number) => (
|
|
383
|
+
<Col xs={24} sm={12} lg={6} key={index}>
|
|
384
|
+
<div className="performance-item">
|
|
385
|
+
<div className="performance-header">
|
|
386
|
+
<span className="metric-name">{metric.name}</span>
|
|
387
|
+
<span className="metric-value">
|
|
388
|
+
{metric.value}%
|
|
389
|
+
</span>
|
|
390
|
+
</div>
|
|
391
|
+
<Progress
|
|
392
|
+
percent={metric.value}
|
|
393
|
+
strokeColor={metric.color}
|
|
394
|
+
trailColor="#f0f0f0"
|
|
395
|
+
strokeWidth={8}
|
|
396
|
+
/>
|
|
397
|
+
<div className="performance-target">
|
|
398
|
+
目标: {metric.target}%
|
|
399
|
+
</div>
|
|
400
|
+
</div>
|
|
401
|
+
</Col>
|
|
402
|
+
),
|
|
403
|
+
)}
|
|
404
|
+
</Row>
|
|
405
|
+
</Card>
|
|
406
|
+
</Col>
|
|
407
|
+
</Row>
|
|
408
|
+
|
|
409
|
+
{/* 活跃用户统计 */}
|
|
410
|
+
<Row gutter={[16, 16]} className="active-users-row">
|
|
411
|
+
<Col xs={24}>
|
|
412
|
+
<Card
|
|
413
|
+
title={
|
|
414
|
+
<span>
|
|
415
|
+
<HeartOutlined className="section-icon" />
|
|
416
|
+
活跃用户统计
|
|
417
|
+
</span>
|
|
418
|
+
}
|
|
419
|
+
className="active-users-card"
|
|
420
|
+
>
|
|
421
|
+
<div className="active-users-content">
|
|
422
|
+
<div className="active-users-main">
|
|
423
|
+
<div className="active-users-number">
|
|
424
|
+
<span className="number">
|
|
425
|
+
{this.formatNumber(currentData.activeUsers)}
|
|
426
|
+
</span>
|
|
427
|
+
<span className="unit">活跃用户</span>
|
|
428
|
+
</div>
|
|
429
|
+
<div className="active-users-description">
|
|
430
|
+
当前在线用户数量,实时更新
|
|
431
|
+
</div>
|
|
432
|
+
</div>
|
|
433
|
+
<div className="active-users-visual">
|
|
434
|
+
<div className="user-avatars">
|
|
435
|
+
{Array.from({ length: 8 }, (_, i) => (
|
|
436
|
+
<Avatar
|
|
437
|
+
key={i}
|
|
438
|
+
size={80}
|
|
439
|
+
src={`https://api.dicebear.com/7.x/avataaars/svg?seed=${
|
|
440
|
+
i + 10
|
|
441
|
+
}`}
|
|
442
|
+
className="user-avatar"
|
|
443
|
+
style={{
|
|
444
|
+
animationDelay: `${i * 0.1}s`,
|
|
445
|
+
transform: `rotate(${
|
|
446
|
+
i * 45
|
|
447
|
+
}deg) translateY(-60px) rotate(-${i * 45}deg)`,
|
|
448
|
+
}}
|
|
449
|
+
/>
|
|
450
|
+
))}
|
|
451
|
+
</div>
|
|
452
|
+
</div>
|
|
453
|
+
</div>
|
|
454
|
+
</Card>
|
|
455
|
+
</Col>
|
|
456
|
+
</Row>
|
|
457
|
+
</div>
|
|
458
|
+
</Spin>
|
|
459
|
+
</div>
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
}
|