diff --git a/package.json b/package.json
index 979081a..15708e5 100644
--- a/package.json
+++ b/package.json
@@ -23,11 +23,14 @@
"@ant-design/charts": "^1.4.2",
"@ant-design/pro-layout": "6.32.1",
"@formily/antd": "^2.0.6",
+ "@jiaminghi/data-view-react": "^1.2.5",
"@types/lodash": "^4.14.172",
"@ztree/ztree_v3": "^3.5.42",
"ahooks": "^3.1.3",
"antd": "^4.17.3",
"axios": "^0.22.0",
+ "echarts": "^4.9.0",
+ "echarts-gl": "^1.1.2",
"fbemitter": "^3.0.0",
"js-base64": "^3.6.1",
"js-cookie": "^2.2.1",
@@ -58,7 +61,6 @@
"@types/react": "^17.0.2",
"@types/react-dom": "^17.0.2",
"@umijs/plugin-access": "2.4.2",
- "umi-plugin-authorize": "^2.8.12",
"@umijs/plugin-dva": "^0.13.0",
"@umijs/plugin-initial-state": "^2.4.0",
"@umijs/plugin-locale": "^0.15.0",
@@ -71,6 +73,7 @@
"prettier": "^2.2.0",
"typescript": "^4.3.5",
"umi": "^3.5.20",
+ "umi-plugin-authorize": "^2.8.12",
"yorkie": "^2.0.0"
}
}
diff --git a/src/assets/images/card_bg.png b/src/assets/images/card_bg.png
new file mode 100644
index 0000000..e27a78e
Binary files /dev/null and b/src/assets/images/card_bg.png differ
diff --git a/src/assets/images/frame_bg.png b/src/assets/images/frame_bg.png
new file mode 100644
index 0000000..9578b5b
Binary files /dev/null and b/src/assets/images/frame_bg.png differ
diff --git a/src/assets/images/frame_icon.png b/src/assets/images/frame_icon.png
new file mode 100644
index 0000000..3589658
Binary files /dev/null and b/src/assets/images/frame_icon.png differ
diff --git a/src/assets/images/frame_title_bg.png b/src/assets/images/frame_title_bg.png
new file mode 100644
index 0000000..84aa16b
Binary files /dev/null and b/src/assets/images/frame_title_bg.png differ
diff --git a/src/assets/images/head_bg1.png b/src/assets/images/head_bg1.png
new file mode 100644
index 0000000..ef18d95
Binary files /dev/null and b/src/assets/images/head_bg1.png differ
diff --git a/src/assets/images/head_title.png b/src/assets/images/head_title.png
new file mode 100644
index 0000000..d05b0b1
Binary files /dev/null and b/src/assets/images/head_title.png differ
diff --git a/src/assets/images/hxzgzgdjfx.png b/src/assets/images/hxzgzgdjfx.png
new file mode 100644
index 0000000..16052ce
Binary files /dev/null and b/src/assets/images/hxzgzgdjfx.png differ
diff --git a/src/assets/images/hxzgzgnljg.png b/src/assets/images/hxzgzgnljg.png
new file mode 100644
index 0000000..62575a6
Binary files /dev/null and b/src/assets/images/hxzgzgnljg.png differ
diff --git a/src/assets/images/hxzgzgrybdtj.png b/src/assets/images/hxzgzgrybdtj.png
new file mode 100644
index 0000000..46695c1
Binary files /dev/null and b/src/assets/images/hxzgzgrybdtj.png differ
diff --git a/src/assets/images/hxzgzgxljg.png b/src/assets/images/hxzgzgxljg.png
new file mode 100644
index 0000000..51c0432
Binary files /dev/null and b/src/assets/images/hxzgzgxljg.png differ
diff --git a/src/assets/images/more.png b/src/assets/images/more.png
new file mode 100644
index 0000000..d536f17
Binary files /dev/null and b/src/assets/images/more.png differ
diff --git a/src/assets/images/one.png b/src/assets/images/one.png
new file mode 100644
index 0000000..0a3c5d3
Binary files /dev/null and b/src/assets/images/one.png differ
diff --git a/src/assets/images/pageBg.png b/src/assets/images/pageBg.png
new file mode 100644
index 0000000..8e03594
Binary files /dev/null and b/src/assets/images/pageBg.png differ
diff --git a/src/assets/images/refresh.png b/src/assets/images/refresh.png
new file mode 100644
index 0000000..9b6fbbd
Binary files /dev/null and b/src/assets/images/refresh.png differ
diff --git a/src/assets/images/rwdcl.png b/src/assets/images/rwdcl.png
new file mode 100644
index 0000000..1d0179c
Binary files /dev/null and b/src/assets/images/rwdcl.png differ
diff --git a/src/assets/images/rylbylb.png b/src/assets/images/rylbylb.png
new file mode 100644
index 0000000..b72a7cf
Binary files /dev/null and b/src/assets/images/rylbylb.png differ
diff --git a/src/assets/images/tabSelected.png b/src/assets/images/tabSelected.png
new file mode 100644
index 0000000..a4206a6
Binary files /dev/null and b/src/assets/images/tabSelected.png differ
diff --git a/src/assets/images/three.png b/src/assets/images/three.png
new file mode 100644
index 0000000..3df3b29
Binary files /dev/null and b/src/assets/images/three.png differ
diff --git a/src/assets/images/two.png b/src/assets/images/two.png
new file mode 100644
index 0000000..b3735fe
Binary files /dev/null and b/src/assets/images/two.png differ
diff --git a/src/assets/images/weaverlogo.png b/src/assets/images/weaverlogo.png
new file mode 100644
index 0000000..42106a4
Binary files /dev/null and b/src/assets/images/weaverlogo.png differ
diff --git a/src/assets/images/xmys.png b/src/assets/images/xmys.png
new file mode 100644
index 0000000..d1bc40a
Binary files /dev/null and b/src/assets/images/xmys.png differ
diff --git a/src/assets/images/xsje.png b/src/assets/images/xsje.png
new file mode 100644
index 0000000..f3fe62a
Binary files /dev/null and b/src/assets/images/xsje.png differ
diff --git a/src/assets/images/yjgz.png b/src/assets/images/yjgz.png
new file mode 100644
index 0000000..aee88ce
Binary files /dev/null and b/src/assets/images/yjgz.png differ
diff --git a/src/assets/images/zgxcfftj.png b/src/assets/images/zgxcfftj.png
new file mode 100644
index 0000000..07744ca
Binary files /dev/null and b/src/assets/images/zgxcfftj.png differ
diff --git a/src/assets/images/zs.png b/src/assets/images/zs.png
new file mode 100644
index 0000000..7d60f57
Binary files /dev/null and b/src/assets/images/zs.png differ
diff --git a/src/layouts/index.tsx b/src/layouts/index.tsx
index 9369776..6243e07 100644
--- a/src/layouts/index.tsx
+++ b/src/layouts/index.tsx
@@ -15,6 +15,7 @@ import { layoutConfig } from "@/layouts/config";
import stores from "@/store";
import "moment/locale/zh-cn";
import "antd/dist/antd.variable.min.css";
+import "../utils/flexible";
moment.locale("zh-cn");
diff --git a/src/pages/personnelReport/constants.js b/src/pages/personnelReport/constants.js
index 3c52dfa..0885a7b 100644
--- a/src/pages/personnelReport/constants.js
+++ b/src/pages/personnelReport/constants.js
@@ -2,6 +2,58 @@ import { G2, measureTextWidth } from "@ant-design/plots";
const G = G2.getEngine("canvas");
+export const structureCardList = [
+ {
+ title: "当期总人数",
+ active: 0,
+ number: 489,
+ unit: "人",
+ color: "#FFBB31",
+ tabList: ["本月", "上月"]
+ },
+ {
+ title: "本月入职",
+ active: 0,
+ number: 100,
+ unit: "人",
+ color: "#3DA5F6",
+ tabList: ["本月", "上月"]
+ },
+ {
+ title: "本月离职",
+ active: 0,
+ number: 23,
+ unit: "人",
+ color: "#5FD5C7",
+ tabList: ["本月", "上月"]
+ },
+ {
+ title: "年度累计入职",
+ active: 0,
+ number: 238,
+ unit: "人",
+ color: "#2B6DF6",
+ tabList: ["本年", "去年"]
+ },
+ {
+ title: "年度累计离职",
+ active: 0,
+ number: 198,
+ unit: "人",
+ color: "#B571EA",
+ tabList: ["本年", "去年"]
+ },
+ {
+ title: "平均年龄",
+ active: 0,
+ number: 28.0,
+ unit: "岁",
+ color: "#5FCC7B",
+ tabList: ["本年", "去年"]
+ }
+];
+
+
//人员流动数据
export const flowingData = [
{
@@ -44,14 +96,10 @@ export const flowingConfig = {
offset: "-2%",
content: "{name}",
style: {
- fontSize: 10
+ fontSize: 15
}
},
- interactions: [
- {
- type: "element-active"
- }
- ],
+ interactions: [],
pieStyle: {
lineWidth: 0
}
@@ -179,11 +227,7 @@ export const seniorityConfig = {
textAlign: "center"
}
},
- interactions: [
- {
- type: "element-active"
- }
- ]
+ interactions: []
};
//人员流动情况趋势图数据信息
@@ -279,8 +323,8 @@ export const institutionConfig = {
data: institutionData,
xField: "stage",
yField: "number",
- dynamicHeight: true,
- legend: false
+ dynamicHeight: true
+ // legend: false
};
//人员异动分析数数据
@@ -300,7 +344,7 @@ export const personChangeData = [
];
export const personChangeConfig = {
appendPadding: 10,
- data:[],
+ data: [],
angleField: "value",
colorField: "type",
radius: 0.75,
@@ -309,104 +353,46 @@ export const personChangeConfig = {
labelHeight: 28,
content: "{name}\n{percentage}"
},
- interactions: [
- {
- type: "element-active"
- }
- ]
+ interactions: []
};
//详细图表柱状图
export const multiplData = [
- {
- "name": "全员离职率",
- "年份": "2022",
- "年份流动信息": 18.9
- },
- {
- "name": "全员离职率",
- "年份": "2023",
- "年份流动信息": 28.8
- },
- {
- "name": "主动离职率",
- "年份": "2022",
- "年份流动信息": 12.4
- },
- {
- "name": "主动离职率",
- "年份": "2023",
- "年份流动信息": 23.2
- },
- {
- "name": "被动离职率",
- "年份": "2022",
- "年份流动信息": 12.4
- },
- {
- "name": "被动离职率",
- "年份": "2023",
- "年份流动信息": 23.2
- },
- {
- "name": "关键岗位离职率",
- "年份": "2022",
- "年份流动信息": 12.4
- },
- {
- "name": "关键岗位离职率",
- "年份": "2023",
- "年份流动信息": 23.2
- },
- {
- "name": "绩优员工离职率",
- "年份": "2022",
- "年份流动信息": 12.4
- },
- {
- "name": "绩优员工离职率",
- "年份": "2023",
- "年份流动信息": 23.2
- },
- {
- "name": "转正率",
- "年份": "2022",
- "年份流动信息": 12.4
- },
- {
- "name": "转正率",
- "年份": "2023",
- "年份流动信息": 23.2
- },
+ { "city": "12", "type": "今年", "value": 18000 },
+ { "city": "12", "type": "去年", "value": 11000 },
+ { "city": "11", "type": "今年", "value": 18000 },
+ { "city": "11", "type": "去年", "value": 11000 },
+ { "city": "10", "type": "今年", "value": 18000 },
+ { "city": "10", "type": "去年", "value": 11000 },
+ { "city": "09", "type": "今年", "value": 18000 },
+ { "city": "09", "type": "去年", "value": 11000 },
+ { "city": "08", "type": "今年", "value": 18000 },
+ { "city": "08", "type": "去年", "value": 11000 },
+ { "city": "07", "type": "今年", "value": 17000 },
+ { "city": "07", "type": "去年", "value": 6000 },
+ { "city": "06", "type": "今年", "value": 9000 },
+ { "city": "06", "type": "去年", "value": 8500 },
+ { "city": "05", "type": "今年", "value": 14000 },
+ { "city": "05", "type": "去年", "value": 9000 },
+ { "city": "04", "type": "今年", "value": 14000 },
+ { "city": "04", "type": "去年", "value": 9000 },
+ { "city": "03", "type": "今年", "value": 16000 },
+ { "city": "03", "type": "去年", "value": 5000 },
+ { "city": "02", "type": "今年", "value": 9000 },
+ { "city": "02", "type": "去年", "value": 8500 },
+ { "city": "01", "type": "今年", "value": 14500 },
+ { "city": "01", "type": "去年", "value": 8500 }
];
//人员流动情况趋势图配置信息
export const multipleConfig = {
+ data: [],
+ xField: "city",
+ yField: "value",
+ seriesField: "type",
isGroup: true,
- xField: "年份",
- yField: "年份流动信息",
- seriesField: "name",
- // 分组柱状图 组内柱子间的间距 (像素级别)
- dodgePadding: 2,
- // 分组柱状图 组间的间距 (像素级别)
- intervalPadding: 50,
- label: {
- // 可手动配置 label 数据标签位置
- position: "middle",
- // 'top', 'middle', 'bottom'
- // 可配置附加的布局方法
- layout: [
- // 柱形图数据标签位置自动调整
- {
- type: "interval-adjust-position"
- }, // 数据标签防遮挡
- {
- type: "interval-hide-overlap"
- }, // 数据标签文颜色自动调整
- {
- type: "adjust-color"
- }
- ]
+ columnStyle: {
+ radius: [20, 20, 0, 0]
}
};
@@ -423,104 +409,69 @@ export const trainingData = [
];
//培训排名
-export const rankingData =[
- {
- name: '机构一',
- month: 'Jan.',
- grades: 18.9,
- },
- {
- name: '机构一',
- month: 'Feb.',
- grades: 28.8,
- },
- {
- name: '机构一',
- month: 'Mar.',
- grades: 39.3,
- },
+export const rankingData = [
{
- name: '机构一',
- month: 'Apr.',
- grades: 81.4,
+ label: "财务部",
+ type: "前五",
+ value: 2800
},
{
- name: '机构一',
- month: 'May',
- grades: 47,
+ label: "销售部",
+ type: "前五",
+ value: 1800
},
{
- name: '机构一',
- month: 'Jun.',
- grades: 20.3,
+ label: "策划部",
+ type: "前五",
+ value: 950
},
{
- name: '机构一',
- month: 'Jul.',
- grades: 24,
+ label: "运营部",
+ type: "前五",
+ value: 500
},
{
- name: '机构一',
- month: 'Aug.',
- grades: 35.6,
+ label: "后勤部",
+ type: "前五",
+ value: 170
},
{
- name: '机构二',
- month: 'Jan.',
- grades: 12.4,
+ label: "财务部1",
+ type: "后五",
+ value: 2260
},
{
- name: '机构二',
- month: 'Feb.',
- grades: 23.2,
+ label: "销售部1",
+ type: "后五",
+ value: 1300
},
{
- name: '机构二',
- month: 'Mar.',
- grades: 34.5,
+ label: "策划部1",
+ type: "后五",
+ value: 900
},
{
- name: '机构二',
- month: 'Apr.',
- grades: 99.7,
+ label: "运营部1",
+ type: "后五",
+ value: 390
},
{
- name: '机构二',
- month: 'May',
- grades: 52.6,
- },
- {
- name: '机构二',
- month: 'Jun.',
- grades: 35.5,
- },
- {
- name: '机构二',
- month: 'Jul.',
- grades: 37.4,
- },
- {
- name: '机构二',
- month: 'Aug.',
- grades: 42.4,
- },
-]
+ label: "后勤部1",
+ type: "后五",
+ value: 100
+ }
+];
export const rankingConfig = {
+ data: [],
isGroup: true,
- xField: "month",
- yField: "grades",
- seriesField: "name",
- // 分组柱状图 组内柱子间的间距 (像素级别)
- dodgePadding: 2,
- // 分组柱状图 组间的间距 (像素级别)
- intervalPadding: 10,
- columnStyle: {
- radius: [20, 20, 0],
- },
+ xField: "value",
+ yField: "label",
+ seriesField: "type",
+ dodgePadding: 4,
label: {
// 可手动配置 label 数据标签位置
position: "middle",
- // 'top', 'middle', 'bottom'
+ // 'left', 'middle', 'right'
// 可配置附加的布局方法
layout: [
// 柱形图数据标签位置自动调整
@@ -602,257 +553,249 @@ export const humanAnalysisconfig = {
//人效排名数据
export const humanEfficiencyRankingData = [
{
- title: '员工1',
+ title: "员工1",
description: "公司1",
- rank:1
+ rank: 1
},
{
- title: '员工2',
+ title: "员工2",
description: "公司2",
- rank:2
+ rank: 2
},
{
- title: '员工3',
+ title: "员工3",
description: "公司3",
- rank:3
+ rank: 3
},
{
- title: '员工4',
+ title: "员工4",
description: "公司4",
- rank:4
- },
+ rank: 4
+ }
];
//销售新客户合同数量排名
export const saleEfficiencyRankingData = [
{
- title: '员工5',
+ title: "员工5",
description: "公司1",
- rank:1
+ rank: 1
},
{
- title: '员工6',
+ title: "员工6",
description: "公司2",
- rank:2
+ rank: 2
},
{
- title: '员工7',
+ title: "员工7",
description: "公司3",
- rank:3
+ rank: 3
},
{
- title: '员工8',
+ title: "员工8",
description: "公司4",
- rank:4
- },
+ rank: 4
+ }
];
//新销售有效合同
export const newSaleEfficiencyRankingData = [
{
- title: '员工9',
+ title: "员工9",
description: "公司1",
- rank:1
+ rank: 1
},
{
- title: '员工10',
+ title: "员工10",
description: "公司2",
- rank:2
+ rank: 2
},
{
- title: '员工11',
+ title: "员工11",
description: "公司3",
- rank:3
+ rank: 3
},
{
- title: '员工12',
+ title: "员工12",
description: "公司4",
- rank:4
- },
+ rank: 4
+ }
];
-
//人工总成本数据
export const totalLaborCostdata = [
{
- time: 'Jan.',
+ time: "Jan.",
value: 350,
- count: 800,
+ count: 800
},
{
- time: 'Feb.',
+ time: "Feb.",
value: 900,
- count: 600,
+ count: 600
},
{
- time: 'Mar.',
+ time: "Mar.",
value: 300,
- count: 400,
+ count: 400
},
{
- time: 'Apr.',
+ time: "Apr.",
value: 450,
- count: 380,
+ count: 380
},
{
- time: 'May.',
+ time: "May.",
value: 470,
- count: 220,
+ count: 220
},
{
- time: 'Jun.',
+ time: "Jun.",
value: 470,
- count: 220,
+ count: 220
},
{
- time: 'Jul.',
+ time: "Jul.",
value: 470,
- count: 220,
+ count: 220
},
{
- time: 'Aug.',
+ time: "Aug.",
value: 470,
- count: 220,
- },
+ count: 220
+ }
];
export const totalLaborCostConfig = {
data: [totalLaborCostdata, totalLaborCostdata],
- xField: 'time',
- yField: ['value', 'count'],
+ xField: "time",
+ yField: ["value", "count"],
yAxis: {
// 格式化左坐标轴
value: {
min: 0,
label: {
- formatter: (val) => `${val}W`,
- },
+ formatter: (val) => `${val}W`
+ }
},
// 隐藏右坐标轴
- count: false,
+ count: false
},
geometryOptions: [
{
- geometry: 'column',
- color: '#5B8FF9',
+ geometry: "column",
+ color: "#5B8FF9",
columnWidthRatio: 0.4,
label: {
- position: 'middle',
- },
+ position: "middle"
+ }
},
{
- geometry: 'line',
+ geometry: "line",
smooth: true,
- color: '#5AD8A6',
- },
- ],
- interactions: [
- {
- type: 'element-highlight',
- },
- {
- type: 'active-region',
- },
+ color: "#5AD8A6"
+ }
],
+ interactions: [],
annotations: {
value: [
{
- type: 'text',
- position: ['2019-06', 'max'],
- content: '柱线混合图',
- },
+ type: "text",
+ position: ["2019-06", "max"],
+ content: "柱线混合图"
+ }
],
count: [
{
- type: 'dataMarker',
+ type: "dataMarker",
top: true,
- position: ['2019-05', 400],
+ position: ["2019-05", 400],
line: {
- length: 20,
+ length: 20
},
text: {
- content: '2019-05, 发布新版本',
+ content: "",
style: {
- textAlign: 'left',
- },
- },
- },
- ],
- },
+ textAlign: "left"
+ }
+ }
+ }
+ ]
+ }
};
//人均收入配置数据 1、人均固定收入 2、人均浮动收入
export const fixedIncomePerData = [
{
- type: '销售',
- value: 27,
+ type: "销售",
+ value: 27
},
{
- type: '项目',
- value: 25,
+ type: "项目",
+ value: 25
},
{
- type: '开发',
- value: 18,
+ type: "开发",
+ value: 18
},
{
- type: '客服',
- value: 15,
+ type: "客服",
+ value: 15
},
{
- type: '其他',
- value: 10,
+ type: "其他",
+ value: 10
},
{
- type: '其他',
- value: 5,
- },
+ type: "其他",
+ value: 5
+ }
];
export const floatingIncomePerData = [
{
- type: '销售',
- value: 18,
+ type: "销售",
+ value: 18
},
{
- type: '项目',
- value: 29,
+ type: "项目",
+ value: 29
},
{
- type: '开发',
- value: 23,
+ type: "开发",
+ value: 23
},
{
- type: '客服',
- value: 3,
+ type: "客服",
+ value: 3
},
{
- type: '其他',
- value: 22,
+ type: "其他",
+ value: 22
},
{
- type: '其他',
- value: 5,
- },
+ type: "其他",
+ value: 5
+ }
];
//人均收入配置信息
export const perCapitaIncomeConfig = {
appendPadding: 10,
- data:[],
- angleField: 'value',
- colorField: 'type',
+ data: [],
+ angleField: "value",
+ colorField: "type",
radius: 1,
innerRadius: 0.64,
meta: {
value: {
- formatter: (v) => `${v} ¥`,
- },
+ formatter: (v) => `${v} ¥`
+ }
},
label: {
- type: 'inner',
- offset: '-50%',
+ type: "inner",
+ offset: "-50%",
style: {
- textAlign: 'center',
+ textAlign: "center"
},
autoRotate: false,
- content: '{value}',
+ content: "{value}"
},
statistic: {
title: {
@@ -861,119 +804,117 @@ export const perCapitaIncomeConfig = {
const { width, height } = container.getBoundingClientRect();
const d = Math.sqrt(Math.pow(width / 2, 2) + Math.pow(height / 2, 2));
//总计
- const text = datum ? datum.type : '';
+ const text = datum ? datum.type : "";
return renderStatistic(d, text, {
- fontSize: 28,
+ fontSize: 28
});
- },
+ }
},
content: {
offsetY: 4,
style: {
- fontSize: '32px',
+ fontSize: "32px"
},
customHtml: (container, view, datum, data) => {
const { width } = container.getBoundingClientRect();
const text = datum ? `¥ ${datum.value}` : `¥ ${data.reduce((r, d) => r + d.value, 0)}`;
return renderStatistic(width, "", {
- fontSize: 32,
+ fontSize: 32
});
- },
- },
+ }
+ }
},
// 添加 中心统计文本 交互
- interactions: [
- ],
+ interactions: []
};
-
//人均人工成本数据
export const laborCostsPerCapitaData = [
{
- year: 'Jan.',
+ year: "Jan.",
value: 3,
- count: 10,
+ count: 10
},
{
- year: 'Feb.',
+ year: "Feb.",
value: 4,
- count: 4,
+ count: 4
},
{
- year: 'Mar.',
+ year: "Mar.",
value: 3.5,
- count: 5,
+ count: 5
},
{
- year: 'Apr.',
+ year: "Apr.",
value: 5,
- count: 5,
+ count: 5
},
{
- year: 'May.',
+ year: "May.",
value: 4.9,
- count: 4.9,
+ count: 4.9
},
{
- year: 'Jun.',
+ year: "Jun.",
value: 6,
- count: 35,
+ count: 35
},
{
- year: 'Jul.',
+ year: "Jul.",
value: 7,
- count: 7,
+ count: 7
},
{
- year: 'Aug.',
+ year: "Aug.",
value: 9,
- count: 1,
- },
+ count: 1
+ }
];
export const laborCostsPerCapitaConfig = {
data: [laborCostsPerCapitaData, laborCostsPerCapitaData],
- xField: 'year',
- yField: ['value', 'count'],
+ xField: "year",
+ yField: ["value", "count"],
geometryOptions: [
{
- geometry: 'line',
+ geometry: "line",
smooth: true,
- color: '#5B8FF9',
+ color: "#5B8FF9",
label: {
formatter: (datum) => {
return `${datum.value}w`;
- },
+ }
},
lineStyle: {
lineWidth: 3,
- lineDash: [5, 5],
- },
+ lineDash: [5, 5]
+ }
},
{
- geometry: 'line',
+ geometry: "line",
smooth: true,
- color: '#5AD8A6',
+ color: "#5AD8A6",
lineStyle: {
lineWidth: 4,
- opacity: 0.5,
+ opacity: 0.5
},
label: {
formatter: (datum) => {
return `${datum.count}w`;
- },
+ }
},
point: {
- shape: 'circle',
+ shape: "circle",
size: 4,
style: {
opacity: 0.5,
- stroke: '#5AD8A6',
- fill: '#fff',
- },
- },
- },
- ],
+ stroke: "#5AD8A6",
+ fill: "#fff"
+ }
+ }
+ }
+ ]
};
function renderStatistic(containerWidth, text, style) {
@@ -987,7 +928,7 @@ function renderStatistic(containerWidth, text, style) {
}
const textStyleStr = `width:${containerWidth}px;`;
- return `
${text}
`;
+ return `${text}
`;
}
diff --git a/src/pages/personnelReport/index.less b/src/pages/personnelReport/index.less
deleted file mode 100644
index ec9a462..0000000
--- a/src/pages/personnelReport/index.less
+++ /dev/null
@@ -1,64 +0,0 @@
-.chartWrapper {
- display: flex;
- flex-direction: column;
- width: 100%;
- height: 100%;
- background: #e5e5e5;
- padding: 8px;
- overflow: hidden;
-
- .talentTableBox, .flowRateTableBox, .profitTableBox {
- display: flex;
- align-items: center;
-
- & > div:not(:last-child) {
- margin-right: 8px;
- }
-
- & > div {
- flex: 1;
- height: 100%;
- position: relative;
- background: #fff;
- padding: 40px 10px 8px;
- overflow: hidden;
-
- :global {
- .ant-tabs {
- height: 100%;
- line-height: normal;
-
- .ant-tabs-content-holder {
- flex: 1;
-
- .ant-tabs-content {
- height: 100%;
-
- .ant-tabs-tabpane {
- overflow-y: auto;
-
- & > div {
- height: 100% !important;
- }
- }
- }
- }
- }
- }
-
- .title {
- position: absolute;
- left: 2%;
- top: 2%;
- font-size: 16px;
- font-weight: 700;
- }
- }
- }
-
- & > div {
- margin-bottom: 8px;
- flex: 1;
- overflow: hidden;
- }
-}
diff --git a/src/pages/personnelReport/peopleFlowTable/index.less b/src/pages/personnelReport/peopleFlowTable/index.less
new file mode 100644
index 0000000..4ac2fa7
--- /dev/null
+++ b/src/pages/personnelReport/peopleFlowTable/index.less
@@ -0,0 +1,6 @@
+.peopleFlowWrapper {
+ width: 100%;
+ height: 100%;
+ background: #e5e5e5;
+ overflow: auto;
+}
diff --git a/src/pages/personnelReport/peopleFlowTable/index.tsx b/src/pages/personnelReport/peopleFlowTable/index.tsx
new file mode 100644
index 0000000..6fdbba3
--- /dev/null
+++ b/src/pages/personnelReport/peopleFlowTable/index.tsx
@@ -0,0 +1,23 @@
+/*
+ * Author: 黎永顺
+ * name: 人员流量表
+ * Description:
+ * Date: 2023/4/27
+ */
+import React, { FunctionComponent } from "react";
+import styles from "./index.less";
+
+interface OwnProps {
+}
+
+type Props = OwnProps;
+
+const index: FunctionComponent = (props) => {
+
+ return (
+
+
+ );
+};
+
+export default index;
diff --git a/src/pages/personnelReport/reportScreen/components/echarts/ageStructureBar.tsx b/src/pages/personnelReport/reportScreen/components/echarts/ageStructureBar.tsx
new file mode 100644
index 0000000..439e612
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/components/echarts/ageStructureBar.tsx
@@ -0,0 +1,116 @@
+const AgeStructureBar = (echarts: any) => {
+ // 实例化对象
+ const myChart = echarts.init(document.getElementById("ageStructure"));
+ // 配置项
+ const option = {
+ legend: {
+ icon: "circle",
+ top: "-1%",
+ right: "0%",
+ itemGap: 20,
+ textStyle:{
+ fontSize: 12,//字体大小
+ color: '#ffffff'//字体颜色
+ },
+ },
+ tooltip: {
+ // 坐标轴指示器,坐标轴触发有效
+ trigger: "axis",
+ axisPointer: {
+ // 默认为直线,可选为:'line' | 'shadow'
+ type: "shadow"
+ }
+ },
+ grid: {
+ left: "0%",
+ top: 20,
+ right: "0%",
+ bottom: "0%",
+ containLabel: true
+ },
+ xAxis: {
+ type: "value",
+ show: false,
+ axisLine: {
+ show: false
+ },
+ splitLine: {
+ show: false
+ },
+ axisTick: {
+ show: false // 不显示坐标轴刻度线
+ }
+ },
+ yAxis: {
+ type: "category",
+ data: ["30岁以下", "30~40岁", "40~50岁", "50~60岁", "60岁以上"],
+ // 修改坐标值样式
+ axisLine: {
+ show: false
+ },
+ axisLabel: {
+ color: "rgba(255, 255, 255, 1)",
+ fontSize: 10,
+ show: true
+ },
+ axisTick: {
+ show: false // 不显示坐标轴刻度线
+ }
+ },
+ series: [
+ {
+ name: "男",
+ type: "bar",
+ stack: "total",
+ barWidth: "30%",
+ label: {
+ show: true,
+ color: "rgba(255, 255, 255, 1)",
+ fontSize: 10
+ },
+ emphasis: {
+ focus: "series"
+ },
+ data: [320, 302, 301, 334, 390],
+ // bar 样式修改
+ itemStyle: {
+ barBorderRadius: [10, 0 , 0 , 10],
+ color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+ { offset: 0, color: "#3EA1FF" },
+ { offset: 0.5, color: "#72CFFF" },
+ { offset: 1, color: "#72CFFF" }
+ ]),
+ },
+ },
+ {
+ name: "女",
+ type: "bar",
+ stack: "total",
+ barWidth: "30%",
+ label: {
+ show: true,
+ color: "rgba(255, 255, 255, 1)",
+ fontSize: 10
+ },
+ emphasis: {
+ focus: "series"
+ },
+ data: [120, 132, 101, 134, 90],
+ // bar 样式修改
+ itemStyle: {
+ barBorderRadius: [0, 10 , 10 , 0],
+ color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
+ { offset: 0, color: "#B2FDB2" },
+ { offset: 0.5, color: "#00D5FF" },
+ { offset: 1, color: "#00D5FF" }
+ ]),
+ },
+ }
+ ]
+ };
+ // 配置项给实例对象
+ myChart.setOption(option);
+ return myChart;
+};
+
+export default AgeStructureBar;
diff --git a/src/pages/personnelReport/reportScreen/components/echarts/changeStatisticsBar.tsx b/src/pages/personnelReport/reportScreen/components/echarts/changeStatisticsBar.tsx
new file mode 100644
index 0000000..55d1bea
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/components/echarts/changeStatisticsBar.tsx
@@ -0,0 +1,119 @@
+const PersonnelCategoryBar = (echarts: any) => {
+ // 实例化对象
+ const myChart = echarts.init(document.getElementById("changeStatistics"));
+ // 配置项
+ const option = {
+ tooltip: {
+ // 坐标轴指示器,坐标轴触发有效
+ trigger: "axis",
+ axisPointer: {
+ // 默认为直线,可选为:'line' | 'shadow'
+ type: "shadow"
+ }
+ },
+ grid: {
+ left: "0%",
+ top: 10,
+ right: "0%",
+ bottom: "4%",
+ // true: 数值离DOM盒子的距离 false: 坐标轴离DOM盒子的距离
+ containLabel: true
+ },
+ xAxis: [
+ {
+ type: "category",
+ data: ["公司本部", "公司1", "公司2", "公司3", "公司4", "公司5", "公司6", "公司7"],
+ axisTick: {
+ alignWithLabel: true
+ },
+ // 修改坐标值样式
+ axisLabel: {
+ color: "rgba(255, 255, 255, 1)",
+ fontSize: 10,
+ show: true
+ },
+ axisLine: {
+ show: false
+ }
+ }
+ ],
+ yAxis: [
+ {
+ type: "value",
+ // 修改坐标值样式
+ axisLabel: {
+ color: "rgba(255, 255, 255, 1)",
+ fontSize: 12
+ },
+ // 修改坐标轴线样式
+ axisLine: {
+ show: false
+ },
+ axisTick: {
+ show: false // 不显示坐标轴刻度线
+ },
+ splitLine: {
+ lineStyle: {
+ type: "dashed",
+ color: "rgba(93,126,158,1)"
+ }
+ }
+ }
+ ],
+ series: [
+ {
+ name: "入职",
+ type: "bar",
+ showBackground: false,
+ barWidth: "10%",
+ data: [250, 250, 320, 410, 280, 320, 405, 405],
+ // bar 样式修改
+ itemStyle: {
+ barBorderRadius: 10,
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: "#3EA1FF" },
+ { offset: 0.5, color: "#72CFFF" },
+ { offset: 1, color: "#72CFFF" }
+ ])
+ }
+ },
+ {
+ name: "离职",
+ type: "bar",
+ showBackground: false,
+ barWidth: "10%",
+ data: [370, 370, 260, 110, 390, 280, 110, 110],
+ // bar 样式修改
+ itemStyle: {
+ barBorderRadius: 10,
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: "#00D5FF" },
+ { offset: 0.5, color: "#B2FDB2" },
+ { offset: 1, color: "#B2FDB2" }
+ ])
+ }
+ },
+ {
+ name: "调职",
+ type: "bar",
+ showBackground: false,
+ barWidth: "10%",
+ data: [310, 310, 80, 280, 310, 70, 280, 280],
+ // bar 样式修改
+ itemStyle: {
+ barBorderRadius: 10,
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: "#1455FF" },
+ { offset: 0.5, color: "#5F9CFF" },
+ { offset: 1, color: "#5F9CFF" }
+ ])
+ }
+ }
+ ]
+ };
+ // 配置项给实例对象
+ myChart.setOption(option);
+ return myChart;
+};
+
+export default PersonnelCategoryBar;
diff --git a/src/pages/personnelReport/reportScreen/components/echarts/degreeStructurePie.tsx b/src/pages/personnelReport/reportScreen/components/echarts/degreeStructurePie.tsx
new file mode 100644
index 0000000..acec05d
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/components/echarts/degreeStructurePie.tsx
@@ -0,0 +1,103 @@
+import { getPie3D } from "@/utils/chart";
+
+const color = ["#FE772D", "#FEDB4B", "#2A71FF", "#00EDFE"];
+
+const DegreeStructurePie = (echarts: any) => {
+ // 实例化对象
+ const myChart = echarts.init(document.getElementById("degreeStructure"));
+ // 配置项
+ const option = {
+ ...getPie3D(setLabel([
+ {
+ name: "研究生(博士)",
+ value: 176
+ },
+ {
+ name: "研究生(硕士)",
+ value: 288
+ },
+ {
+ name: "本科",
+ value: 588
+ },
+ {
+ name: "大专及以下",
+ value: 78
+ }
+ ], color), 0.6, 240, 26, 18, 1, true)
+ };
+ // 配置项给实例对象
+ myChart.setOption({
+ ...option,
+ legend: {
+ orient: "vertical",
+ icon: "circle",
+ top: "25%",
+ left: "10%",
+ itemGap: 28,
+ textStyle: {
+ fontSize: 12,//字体大小
+ color: "#ffffff"//字体颜色
+ }
+ }
+ });
+ return myChart;
+};
+
+export default DegreeStructurePie;
+
+export const setLabel = (optionData: any, color: any) => {
+ return optionData.map((item: any, index: number) => {
+ return {
+ ...item,
+ itemStyle: {
+ color: color[index]
+ },
+ label: {
+ normal: {
+ show: false,
+ color: color[index],
+ position: "right",
+ // distance:-10,
+ offset: [0, 3],
+ formatter: [
+ "{d|{d}%}",
+ "————",
+ // '{c|{c}}{b|台}',
+ "{b|{b}}"
+ ].join("\n"), // 用\n来换行
+ rich: {
+ b: {
+ // color: '#fff',
+ lineHeight: 25,
+ align: "left",
+ color: color[index]
+ },
+ c: {
+ fontSize: 22,
+ textShadowColor: "#1c90a6",
+ textShadowOffsetX: 0,
+ textShadowOffsetY: 2,
+ textShadowBlur: 5,
+ color: color[index]
+ },
+ d: {
+ color: color[index],
+ align: "left"
+ }
+ }
+ }
+ },
+ labelLine: {
+ normal: {
+ show: false,
+ length2: 30,
+ lineStyle: {
+ width: 1,
+ color: color[index]
+ }
+ }
+ }
+ };
+ });
+};
diff --git a/src/pages/personnelReport/reportScreen/components/echarts/gradAnalysisPie.tsx b/src/pages/personnelReport/reportScreen/components/echarts/gradAnalysisPie.tsx
new file mode 100644
index 0000000..f1c0ce1
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/components/echarts/gradAnalysisPie.tsx
@@ -0,0 +1,47 @@
+import { getPie3D } from "@/utils/chart";
+import { setLabel } from "./degreeStructurePie";
+
+const color = ["#BD42EF", "#6D45F3", "#3358F3", "#6ECDE5"];
+const GradAnalysisPie = (echarts: any) => {
+ // 实例化对象
+ const myChart = echarts.init(document.getElementById("gradAnalysis"));
+ // 配置项
+ const option = {
+ ...getPie3D(setLabel([
+ {
+ name: "正高级",
+ value: 500
+ },
+ {
+ name: "副高级",
+ value: 1120
+ },
+ {
+ name: "中级",
+ value: 4567
+ },
+ {
+ name: "初级",
+ value: 5278
+ }
+ ], color), 0.6, 240, 26, 18, 1, false)
+ };
+ // 配置项给实例对象
+ myChart.setOption({
+ ...option,
+ legend: {
+ orient: "vertical",
+ icon: "circle",
+ top: "25%",
+ left: "10%",
+ itemGap: 28,
+ textStyle: {
+ fontSize: 12,//字体大小
+ color: "#ffffff"//字体颜色
+ }
+ }
+ });
+ return myChart;
+};
+
+export default GradAnalysisPie;
diff --git a/src/pages/personnelReport/reportScreen/components/echarts/personnelCategoryBar.tsx b/src/pages/personnelReport/reportScreen/components/echarts/personnelCategoryBar.tsx
new file mode 100644
index 0000000..caca20a
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/components/echarts/personnelCategoryBar.tsx
@@ -0,0 +1,96 @@
+const PersonnelCategoryBar = (echarts: any) => {
+ // 实例化对象
+ const myChart = echarts.init(document.getElementById("personnelCategory"));
+ // 配置项
+ const option = {
+ tooltip: {
+ // 坐标轴指示器,坐标轴触发有效
+ trigger: "axis",
+ axisPointer: {
+ // 默认为直线,可选为:'line' | 'shadow'
+ type: "shadow"
+ }
+ },
+ grid: {
+ left: "0%",
+ top: 10,
+ right: "0%",
+ bottom: "4%",
+ // true: 数值离DOM盒子的距离 false: 坐标轴离DOM盒子的距离
+ containLabel: true
+ },
+ xAxis: [
+ {
+ type: "category",
+ data: ["领导班子", "海外中国籍", "正式在岗", "海外外籍", "退休返聘", "其他临时", "劳务派遣", "内退"],
+ axisTick: {
+ alignWithLabel: true
+ },
+ // 修改坐标值样式
+ axisLabel: {
+ color: "rgba(255, 255, 255, 1)",
+ fontSize: 10,
+ rotate: 60,
+ show: true
+ },
+ axisLine: {
+ show: false
+ }
+ }
+ ],
+ yAxis: [
+ {
+ type: "value",
+ // 修改坐标值样式
+ axisLabel: {
+ color: "rgba(255, 255, 255, 1)",
+ fontSize: 12
+ },
+ // 修改坐标轴线样式
+ axisLine: {
+ show: false
+ },
+ axisTick: {
+ show: false // 不显示坐标轴刻度线
+ },
+ splitLine: {
+ lineStyle: {
+ type: "dashed",
+ color: "rgba(93,126,158,1)"
+ }
+ }
+ }
+ ],
+ series: [
+ {
+ name: "直接访问",
+ type: "bar",
+ showBackground: true,
+ barWidth: "30%",
+ data: [10, 52, 200, 334, 390, 1030, 220, 210],
+ // bar 样式修改
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: "#3EA1FF" },
+ { offset: 0.5, color: "#72CFFF" },
+ { offset: 1, color: "#72CFFF" }
+ ]),
+ emphasis: {
+ itemStyle: {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: "#AFD8FF" },
+ { offset: 0.7, color: "#AFD8FF" },
+ { offset: 1, color: "#AFD8FF" }
+ ])
+ }
+ }
+ }
+ }
+ ]
+ };
+ // 配置项给实例对象
+ myChart.setOption(option);
+ return myChart;
+};
+
+export default PersonnelCategoryBar;
diff --git a/src/pages/personnelReport/reportScreen/components/frameComp.tsx b/src/pages/personnelReport/reportScreen/components/frameComp.tsx
new file mode 100644
index 0000000..648cc10
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/components/frameComp.tsx
@@ -0,0 +1,64 @@
+/*
+ * Author: 黎永顺
+ * name: 框架组件
+ * Description:
+ * Date: 2023/5/4
+ */
+import React, { FC, useState } from "react";
+import cs from "classnames";
+import styles from "./index.less";
+
+interface OwnProps {
+ position: string;
+ tabList: Array;
+ children: any;
+ titleImg: any;
+ type?: string;
+}
+
+type Props = OwnProps;
+const FrameComp: FC = (props) => {
+ const { position, children, tabList, titleImg } = props;
+ const [active, setActive] = useState(0);
+
+ return (
+
+
+
+

+ {
+ position === "right" &&
+
+ {
+ _.map(tabList, (item, index) => {
+ const classes = cs({
+ [styles["liActive"]]: index === active
+ });
+ return - setActive(index)} className={classes}>{item}
;
+ })
+ }
+
+ }
+
+
More })
+
+ {
+ position === "bottom" &&
+
+ {
+ _.map(tabList, (item, index) => {
+ const classes = cs({
+ [styles["liActive"]]: index === active
+ });
+ return - setActive(index)} className={classes}>{item}
;
+ })
+ }
+
+ }
+ {children}
+
+ );
+};
+
+export default FrameComp;
diff --git a/src/pages/personnelReport/reportScreen/components/index.less b/src/pages/personnelReport/reportScreen/components/index.less
new file mode 100644
index 0000000..661c4ca
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/components/index.less
@@ -0,0 +1,125 @@
+.topPageWrapper {
+ height: 1.25rem;
+ position: relative;
+ background: url("../../../../assets/images/head_bg1.png") no-repeat;
+ background-size: 100% 100%;
+
+ .title {
+ text-align: center;
+ line-height: 0.875rem;
+ position: relative;
+
+ .updateTime {
+ color: #fff;
+ line-height: 0;
+ margin-top: 0.0625rem;
+
+ img {
+ width: 0.225rem;
+ margin-right: .2rem;
+ }
+ }
+
+ img {
+ width: 4.475rem;
+ }
+ }
+
+ .logoWrapper, .showTime {
+ position: absolute;
+ }
+
+ .showTime {
+ right: 2.375rem;
+ top: 0.4rem;
+ text-align: right;
+ color: #fff;
+
+ .dateDay {
+ padding: 0 .35rem;
+ }
+ }
+
+ .logoWrapper {
+ top: 0.1rem;
+ left: 2.375rem;
+ line-height: 0.875rem;
+
+ img {
+ width: 1.675rem;
+ }
+ }
+}
+
+.mapWrapper {
+ width: 10.625rem;
+ height: 8.125rem;
+ margin-top: 1rem;
+}
+
+.frameWrapper {
+ background: url("../../../../assets/images/frame_bg.png") no-repeat;
+ background-size: 100% 100%;
+ margin-bottom: 0.2rem;
+
+ .headerTop {
+ height: 0.475rem;
+ position: relative;
+ background: url("../../../../assets/images/frame_title_bg.png") no-repeat;
+ background-size: 100% 100%;
+ display: flex;
+ justify-content: flex-end;
+
+ .halfHeaderLeft {
+ left: 1.45rem !important;
+ }
+
+ .headerLeft {
+ position: absolute;
+ left: 0.7375rem;
+ top: 0.0625rem;
+ display: flex;
+
+ img {
+ height: 0.3rem;
+ }
+ }
+
+ .moreWrapper {
+ color: #fff;
+ font-size: 0.175rem;
+ position: absolute;
+ right: 0.3375rem;
+ top: 0.1rem;
+ cursor: pointer;
+
+ img {
+ width: 0.2375rem;
+ }
+ }
+
+ .tabWrapper {
+ margin-left: 0.775rem;
+ padding: 0;
+ }
+ }
+
+ .tabWrapper {
+ display: flex;
+ margin: 0;
+ padding: 0 0.3375rem;
+
+ li {
+ padding: 0.1rem 0.175rem;
+ font-size: 14px;
+ color: #ACACAC;
+ cursor: pointer;
+ }
+
+ li.liActive {
+ background: url("../../../../assets/images/tabSelected.png") no-repeat;
+ background-size: 100% 100%;
+ background-position-y: .125rem;
+ }
+ }
+}
diff --git a/src/pages/personnelReport/reportScreen/components/map.tsx b/src/pages/personnelReport/reportScreen/components/map.tsx
new file mode 100644
index 0000000..11bbd11
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/components/map.tsx
@@ -0,0 +1,25 @@
+/*
+ * Author: 黎永顺
+ * name: 地图组件
+ * Description:
+ * Date: 2023/5/4
+ */
+import React, { FC } from "react";
+import Chart from "@/utils/chart";
+import { mapOptions } from "./options";
+import styles from "./index.less";
+
+interface OwnProps {
+}
+
+type Props = OwnProps;
+const Map: FC = (props) => {
+
+ return (
+
+
+
+ );
+};
+
+export default Map;
diff --git a/src/pages/personnelReport/reportScreen/components/options.js b/src/pages/personnelReport/reportScreen/components/options.js
new file mode 100644
index 0000000..cbe2bd6
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/components/options.js
@@ -0,0 +1,243 @@
+import "echarts/map/js/china";
+// 地图数据
+const mapData = {
+ citys: [
+ {
+ name: "浙江",
+ value: [120.15, 29.28, -2],
+ symbolSize: 2,
+ itemStyle: {
+ normal: {
+ color: "#FFF"
+ }
+ }
+ },
+ {
+ name: "四川",
+ value: [103.36, 30.65, -5],
+ symbolSize: 2,
+ itemStyle: {
+ normal: {
+ color: "#FFF"
+ }
+ }
+ },
+ {
+ name: "内蒙古",
+ value: [112.17, 42.81, -23],
+ symbolSize: 2,
+ itemStyle: {
+ normal: {
+ color: "#FFF"
+ }
+ }
+ },
+ {
+ name: "江苏",
+ value: [120.26, 32.54, -1],
+ symbolSize: 2,
+ itemStyle: {
+ normal: {
+ color: "#FFF"
+ }
+ }
+ },
+ {
+ name: "西藏",
+ value: [89.13, 30.66, -1],
+ symbolSize: 2,
+ itemStyle: {
+ normal: {
+ color: "#FFF"
+ }
+ }
+ }
+ ]
+};
+export const salaryData = {
+ header: ["业务板块", "二级机构", "人员类型", "起始时间", "截止时间", "发薪人数", "固定薪酬", "浮动薪酬", "薪酬合计", "薪酬固浮化"],
+ data: [
+ ["国内工程", "建设集团", "领导班子", "2023.1", "2023.1", "23", "20,000", "20,000", "20,000", "20,000"],
+ ["国内工程", "建设集团", "领导班子", "2023.1", "2023.1", "23", "20,000", "20,000", "20,000", "20,000"],
+ ["国内工程", "建设集团", "领导班子", "2023.1", "2023.1", "23", "20,000", "20,000", "20,000", "20,000"],
+ ["国内工程", "建设集团", "领导班子", "2023.1", "2023.1", "23", "20,000", "20,000", "20,000", "20,000"],
+ ["国内工程", "建设集团", "领导班子", "2023.1", "2023.1", "23", "20,000", "20,000", "20,000", "20,000"],
+ ["国内工程", "建设集团", "领导班子", "2023.1", "2023.1", "23", "20,000", "20,000", "20,000", "20,000"],
+ ["国内工程", "建设集团", "领导班子", "2023.1", "2023.1", "23", "20,000", "20,000", "20,000", "20,000"],
+ ["国内工程", "建设集团", "领导班子", "2023.1", "2023.1", "23", "20,000", "20,000", "20,000", "20,000"]
+ ]
+};
+
+export const mapOptions = (params) => ({
+ title: {
+ show: false,
+ text: "全国物流输送图",
+ left: "center",
+ textStyle: {
+ color: "#fff"
+ }
+ },
+ legend: {
+ show: false
+ },
+ geo: [
+ {
+ nameMap: {
+ China: "中国"
+ },
+ map: "china",
+ zlevel: 5,
+ label: {
+ normal: {
+ show: true,
+ formatter: function (params) {
+ //圆环显示文字
+ return params.name === "江苏" || params.name === "浙江" || params.name === "四川" || params.name === "内蒙古" || params.name === "西藏" ? params.name : "";
+ },
+ fontSize: 12,
+ color: "#FFF"
+ },
+ emphasis: {
+ show: true,
+ color: "#FFF"
+ }
+ },
+ zoom: 1.2,
+ itemStyle: {
+ normal: {
+ borderColor: "rgba(148,224,250, .5)", //区域边框颜色
+ areaColor: "rgba(82,164,238,.1)", //区域颜色
+ borderWidth: 1, //区域边框宽度
+ shadowBlur: 5,
+ shadowColor: "rgba(3,113,173,.7)"
+ },
+ emphasis: {
+ borderColor: "rgba(148,224,250, .5)",
+ areaColor: "rgba(6,89,176,.3)",
+ borderWidth: 2.5,
+ shadowBlur: 5,
+ shadowColor: "rgba(3,113,173,.5)"
+ }
+ }
+ },
+ {
+ nameMap: {
+ China: "中国"
+ },
+ map: "china",
+ zlevel: 4,
+ top: "11%",
+ label: {
+ emphasis: {
+ show: false
+ }
+ },
+ zoom: 1.2,
+ itemStyle: {
+ normal: {
+ // borderColor: 'rgba(255,209,163, .5)', //区域边框颜色
+ areaColor: "rgba(73,86,166,.1)", //区域颜色
+ borderWidth: 0.5, //区域边框宽度
+ shadowBlur: 5,
+ shadowColor: "rgba(107,91,237,.7)"
+ },
+ emphasis: {
+ borderColor: "transparent",
+ areaColor: "transparent",
+ borderWidth: 1,
+ shadowBlur: 5,
+ shadowColor: "transparent"
+ }
+ }
+ },
+ {
+ nameMap: {
+ China: "中国"
+ },
+ map: "china",
+ zlevel: 3,
+ top: "12%",
+ label: {
+ emphasis: {
+ show: false
+ }
+ },
+ zoom: 1.2,
+ itemStyle: {
+ normal: {
+ areaColor: "rgba(73,86,166,.1)", //区域颜色
+ borderWidth: 0.5, //区域边框宽度
+ shadowBlur: 5,
+ shadowColor: "rgba(107,91,237,.7)"
+ },
+ emphasis: {
+ borderColor: "transparent",
+ areaColor: "transparent",
+ borderWidth: 1,
+ shadowBlur: 5,
+ shadowColor: "transparent"
+ }
+ }
+ },
+ {
+ nameMap: {
+ China: "中国"
+ },
+ map: "china",
+ zlevel: 2,
+ top: "13%",
+ label: {
+ emphasis: {
+ show: false
+ }
+ },
+ zoom: 1.2,
+ itemStyle: {
+ normal: {
+ // borderColor: 'rgba(255,209,163, .5)', //区域边框颜色
+ areaColor: "rgba(73,86,166,.1)", //区域颜色
+ borderWidth: 0.5, //区域边框宽度
+ shadowBlur: 5,
+ shadowColor: "rgba(107,91,237,.7)"
+ },
+ emphasis: {
+ borderColor: "transparent",
+ areaColor: "transparent",
+ borderWidth: 1,
+ shadowBlur: 5,
+ shadowColor: "transparent"
+ }
+ }
+ }
+ ],
+ series: [
+ {
+ name: "地点",
+ type: "custom",
+ coordinateSystem: "geo",
+ zlevel: 12,
+ renderItem(params, api) {
+ //具体实现自定义图标的方法
+ return {
+ type: "image",
+ style: {
+ image: require("../../../../assets/images/zs.png"),
+ x: api.coord([
+ mapData.citys[params.dataIndex].value[0],
+ mapData.citys[params.dataIndex].value[1]
+ ])[0],
+ y: api.coord([
+ mapData.citys[params.dataIndex].value[0],
+ mapData.citys[params.dataIndex].value[1]
+ ])[1]
+ }
+ };
+ },
+ data: mapData.citys
+ }
+ ]
+});
+export const userOptions = (params = {}) => ({
+ header: params.header,
+ data: params.data
+});
diff --git a/src/pages/personnelReport/reportScreen/components/topPage.tsx b/src/pages/personnelReport/reportScreen/components/topPage.tsx
new file mode 100644
index 0000000..01930f7
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/components/topPage.tsx
@@ -0,0 +1,53 @@
+/*
+ * Author: 黎永顺
+ * name: 大屏头部组件
+ * Description:
+ * Date: 2023/5/4
+ */
+import React, { FC, useEffect, useRef, useState } from "react";
+import { formatTime } from "@/utils/common";
+import styles from "./index.less";
+
+interface OwnProps {
+}
+
+type Props = OwnProps;
+const weekday = ["星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
+const TopPage: FC = (props) => {
+ const [timeStr, setTimeStr] = useState({});
+ const timing = useRef(null);
+ useEffect(() => {
+ setTimingFn();
+ return () => {
+ timing.current = null;
+ };
+ }, []);
+
+ const setTimingFn = () => {
+ timing.current = setInterval(() => {
+ let dateYear = formatTime(new Date(), "yyyy-MM-dd");
+ let dateDay = formatTime(new Date(), "HH:mm:ss");
+ let dateWeek = weekday[new Date().getDay()];
+ setTimeStr({ dateYear, dateDay, dateWeek });
+ }, 1000);
+ };
+
+ return (
+
+
})
+
+
})
+
+
})
+ 数据更新时间:16:02:09
+
+
+
{timeStr?.dateYear}{timeStr?.dateDay}{timeStr?.dateWeek}
+
+ );
+};
+
+export default TopPage;
diff --git a/src/pages/personnelReport/reportScreen/index.less b/src/pages/personnelReport/reportScreen/index.less
new file mode 100644
index 0000000..b0dd1bd
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/index.less
@@ -0,0 +1,115 @@
+.screenWrapperRoot {
+ width: 100%;
+ height: 100%;
+ overflow-y: auto;
+
+ .screenWrapper {
+ line-height: 1.15;
+ min-height: 100vh;
+ background: url("../../../assets/images/pageBg.png") top center no-repeat;
+ background-size: 100% 100%;
+
+ .screenMain {
+ display: flex;
+ min-width: 1024px;
+ max-width: 1920px;
+ margin: 0 auto;
+ padding: 0 0.6875rem;
+
+ .screenColCenter {
+ flex: 5 1;
+ margin: 0 0.125rem;
+ position: relative;
+
+ .cardWrapper {
+ display: flex;
+ width: 100%;
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 99;
+ padding: 0.25rem 0.125rem 0;
+
+ & > li:not(:last-child) {
+ margin-right: 0.275rem;
+ }
+
+ & > li {
+ flex: 1;
+ min-height: 1.1625rem;
+ background: url("../../../assets/images/card_bg.png") no-repeat;
+ background-size: 100% 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ img {
+ width: 0.725rem;
+ margin-right: 0.2rem;
+ }
+
+ .cardInner {
+ display: flex;
+ flex-direction: column;
+ color: #FFF;
+ min-width: 1.125rem;
+ text-align: center;
+
+ span:first-child {
+ font-size: 0.275rem;
+ margin-bottom: 0.1rem;
+ }
+
+ span:last-child {
+ font-size: 0.2rem;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .screenCol {
+ flex: 3 1;
+
+ .personnelCate, .ageStruct, .degreeStructure, .gradAnalysis {
+ height: 3.875rem;
+ padding: 0 0.3375rem;
+ }
+ }
+
+ .screenFooter {
+ display: flex;
+ min-width: 1024px;
+ max-width: 1920px;
+ margin: 0 auto;
+ padding: 0 0.6875rem;
+
+ & > div:first-child {
+ margin-right: 0.125rem;
+ }
+
+ .screenFooterCol {
+ flex: 1;
+
+ .payrollStatistics {
+ padding-bottom: 0.2375rem !important;
+
+ :global {
+ .dv-scroll-board {
+ .rows .row-item, .header {
+ font-size: 0.15rem !important;
+ }
+ }
+ }
+ }
+
+ .payrollStatistics, .personnelChangeStatistics {
+ height: 3.5rem;
+ padding: 0 0.3375rem;
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/pages/personnelReport/reportScreen/index.tsx b/src/pages/personnelReport/reportScreen/index.tsx
new file mode 100644
index 0000000..1a82add
--- /dev/null
+++ b/src/pages/personnelReport/reportScreen/index.tsx
@@ -0,0 +1,147 @@
+/*
+ * Author: 黎永顺
+ * name: 报表大屏
+ * Description:
+ * Date: 2023/5/4
+ */
+import React, { FC, useEffect } from "react";
+// @ts-ignore
+import echarts from "echarts";
+import "echarts-gl";
+import TopPage from "./components/topPage";
+import Map from "./components/map";
+import FrameComp from "./components/frameComp";
+import PersonnelCategoryBar from "./components/echarts/personnelCategoryBar";
+import AgeStructureBar from "./components/echarts/ageStructureBar";
+import DegreeStructurePie from "./components/echarts/degreeStructurePie";
+import GradAnalysisPie from "./components/echarts/gradAnalysisPie";
+import ChangeStatisticsBar from "./components/echarts/changeStatisticsBar";
+import { salaryData, userOptions } from "./components/options";
+// @ts-ignore
+import { ScrollBoard } from "@jiaminghi/data-view-react";
+import styles from "./index.less";
+
+interface OwnProps {
+}
+
+type Props = OwnProps;
+const Index: FC = (props) => {
+ useEffect(() => {
+ const personnelCategoryBar = PersonnelCategoryBar(echarts);
+ const ageStructureBar = AgeStructureBar(echarts);
+ const degreeStructurePie = DegreeStructurePie(echarts);
+ const gradAnalysisPie = GradAnalysisPie(echarts);
+ const changeStatisticsBar = ChangeStatisticsBar(echarts);
+ // 屏幕缩放对chart图表进行自适应处理,调用实例的resize方法
+ window.onresize = () => {
+ personnelCategoryBar.resize();
+ ageStructureBar.resize();
+ degreeStructurePie.resize();
+ gradAnalysisPie.resize();
+ changeStatisticsBar.resize();
+ };
+ return () => {
+ };
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+ -
+
+
+ 8,29,000
+ 销售金额
+
+
+ -
+
+
+ 3,29,000
+ 项目验收
+
+
+ -
+
+
+ 12,000
+ 月均工资
+
+
+ -
+
+
+ 98%
+ 任务达成率
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Index;
diff --git a/src/pages/personnelReport/talentProfitTable/index.less b/src/pages/personnelReport/talentProfitTable/index.less
new file mode 100644
index 0000000..e88969a
--- /dev/null
+++ b/src/pages/personnelReport/talentProfitTable/index.less
@@ -0,0 +1,114 @@
+.profitWrapper {
+ display: flex;
+ width: 100%;
+ height: 100%;
+ background: #e5e5e5;
+ padding: 8px;
+ overflow: hidden;
+
+ .profitLeft {
+ display: flex;
+ flex-direction: column;
+ width: 580px;
+ overflow: hidden;
+
+ & > :not(:last-child) {
+ margin-bottom: 16px;
+ }
+
+ & > div:first-child {
+ & > div {
+ height: 100% !important;
+ }
+ }
+
+ & > div {
+ flex: 1;
+ background: #FFF;
+ position: relative;
+ padding: 40px 10px 8px;
+ overflow: hidden;
+
+ .title {
+ display: inline-block;
+ position: absolute;
+ left: 1%;
+ top: 2%;
+ font-size: 16px;
+ font-weight: 700;
+ }
+
+ :global {
+ .ant-tabs {
+ height: 100%;
+ line-height: normal;
+
+ .ant-tabs-content-holder {
+ flex: 1;
+
+ .ant-tabs-content {
+ height: 100%;
+
+ .ant-tabs-tabpane {
+ overflow-y: auto;
+
+ & > div {
+ height: 100% !important;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ .profitRight {
+ flex: 1;
+ position: relative;
+ margin-left: 16px;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+
+ & > div:first-child {
+ margin-bottom: 16px;
+ }
+
+ & > div {
+ background: #fff;
+ flex: 1;
+ padding: 40px 10px 8px;
+ position: relative;
+ height: 100px;
+
+ :global {
+ .ant-tabs {
+ height: 100%;
+ line-height: normal;
+
+ .ant-tabs-content-holder {
+ flex: 1;
+
+ .ant-tabs-content {
+ height: 100%;
+
+ .ant-tabs-tabpane {
+ overflow-y: auto;
+ }
+ }
+ }
+ }
+ }
+
+ .title {
+ display: inline-block;
+ position: absolute;
+ left: 1%;
+ top: 2%;
+ font-size: 16px;
+ font-weight: 700;
+ }
+ }
+ }
+}
diff --git a/src/pages/personnelReport/index.tsx b/src/pages/personnelReport/talentProfitTable/index.tsx
similarity index 73%
rename from src/pages/personnelReport/index.tsx
rename to src/pages/personnelReport/talentProfitTable/index.tsx
index 18fc776..5244dc9 100644
--- a/src/pages/personnelReport/index.tsx
+++ b/src/pages/personnelReport/talentProfitTable/index.tsx
@@ -1,29 +1,24 @@
+/*
+ * Author: 黎永顺
+ * name:人才利润报表
+ * Description:
+ * Date: 2023/4/27
+ */
import React, { FC } from "react";
+import styles from "./index.less";
import { Avatar, List, Tabs } from "antd";
-import { Column, Funnel, Pie, DualAxes } from "@ant-design/plots";
import {
- degreeData,
- flowingConfig,
- flowingTrendconfig,
- genderData,
+ fixedIncomePerData,
+ floatingIncomePerData,
humanAnalysisconfig,
humanEfficiencyRankingData,
- institutionConfig,
- internData,
- linesData,
- multiplData,
- multipleConfig, newSaleEfficiencyRankingData,
- personChangeConfig,
- personChangeData,
- rankingConfig,
- rankingData, saleEfficiencyRankingData,
- seniorityConfig,
- seniorityData,
- trainingData,totalLaborCostConfig,
laborCostsPerCapitaConfig,
- perCapitaIncomeConfig, fixedIncomePerData, floatingIncomePerData
-} from "./constants";
-import styles from "./index.less";
+ newSaleEfficiencyRankingData,
+ perCapitaIncomeConfig,
+ saleEfficiencyRankingData,
+ totalLaborCostConfig
+} from "@/pages/personnelReport/constants";
+import { Column, DualAxes, Pie } from "@ant-design/plots";
interface OwnProps {
}
@@ -31,51 +26,42 @@ interface OwnProps {
type Props = OwnProps;
const index: FC = (props) => {
- // @ts-ignore
+
return (
-
- {/*人才结构表*/}
-
-
-
人员流动情况
-
+
+
+
+ 人效分析
+ {/*@ts-ignore*/}
+
-
+
+
人均收入
-
-
-
-
-
+
+
-
-
+
+
-
-
+
+
+
+
人工成本
+
+
+ {/*@ts-ignore*/}
+
-
-
+
+
-
-
- {/*人才利润报表*/}
-
+
-
-
人效分析排名
+
人效分析排名
= (props) => {
-
团队效能排名
+
团队效能排名
= (props) => {
-
-
-
- {/*人员流量表*/}
-
);
diff --git a/src/pages/personnelReport/talentStructureTable/components/ageStaticsCharts.ts b/src/pages/personnelReport/talentStructureTable/components/ageStaticsCharts.ts
new file mode 100644
index 0000000..4e7a7e4
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/components/ageStaticsCharts.ts
@@ -0,0 +1,48 @@
+const AgeStaticsPie = (echarts: any) => {
+ // 实例化对象
+ const myChart = echarts.init(document.getElementById("ageStatics"));
+ // 配置项
+ const option = {
+ legend: {
+ icon: "circle",
+ bottom: "0%",
+ left: "center",
+ itemGap: 20,
+ textStyle: {
+ fontSize: 12,//字体大小
+ color: "#787E95"//字体颜色
+ }
+ },
+ color: ["#5FCD7B", "#F5CB49", "#7599F5", "#64BFDB"],
+ series: [
+ {
+ name: "司龄统计",
+ type: "pie",
+ radius: ["45%", "60%"],
+ avoidLabelOverlap: false,
+ animation: false,
+ label: {
+ normal: {
+ formatter: "{d}%",
+ padding: [0, -25],
+ position: "outer" //文字显示在内部,如果在外边把这个去掉就好
+ }
+ },
+ labelLine: {
+ show: false
+ },
+ data: [
+ { value: 40, name: "1-3年" },
+ { value: 35, name: "3-5年" },
+ { value: 20, name: "5-8年" },
+ { value: 5, name: "8年以上" }
+ ]
+ }
+ ]
+ };
+ // 配置项给实例对象
+ myChart.setOption(option);
+ return myChart;
+};
+
+export default AgeStaticsPie;
diff --git a/src/pages/personnelReport/talentStructureTable/components/educationStaticsCharts.ts b/src/pages/personnelReport/talentStructureTable/components/educationStaticsCharts.ts
new file mode 100644
index 0000000..d426de5
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/components/educationStaticsCharts.ts
@@ -0,0 +1,56 @@
+const EducationStaticsRedar = (echarts: any) => {
+ // 实例化对象
+ const myChart = echarts.init(document.getElementById("educationStatics"));
+ // 配置项
+ const option = {
+ tooltip: {
+ show: true
+ },
+ radar: {
+ // shape: 'circle',
+ indicator: [
+ { name: "博士及以上", max: 800, axisLabel: { show: true } },
+ { name: "硕士", max: 800 },
+ { name: "本科", max: 800 },
+ { name: "大专", max: 800 },
+ { name: "大专一下", max: 800 }
+ ],
+ splitArea: {
+ show: false
+ },
+ axisLine: {
+ show: false
+ }
+ },
+ series: [
+ {
+ name: "学历统计",
+ type: "radar",
+ data: [
+ {
+ value: [210, 400, 800, 230, 180],
+ name: "学历统计"
+ }
+ ],
+ label: {
+ show: false,
+ formatter: function (params: any) {
+ return params.value;
+ }
+ },
+ itemStyle: { //此属性的颜色和下面areaStyle属性的颜色都设置成相同色即可实现
+ color: "#4D95E9",
+ borderColor: "#4D95E9"
+ },
+ areaStyle: {
+ color: "rgba(77,149,233,0.26)"
+ }
+ }
+ ]
+ };
+ // 配置项给实例对象
+ myChart.setOption(option);
+ return myChart;
+};
+
+export default EducationStaticsRedar;
diff --git a/src/pages/personnelReport/talentStructureTable/components/genderStaticsCharts.ts b/src/pages/personnelReport/talentStructureTable/components/genderStaticsCharts.ts
new file mode 100644
index 0000000..34d336a
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/components/genderStaticsCharts.ts
@@ -0,0 +1,44 @@
+const GenderStaticsPie = (echarts: any) => {
+ // 实例化对象
+ const myChart = echarts.init(document.getElementById("genderStatics"));
+ // 配置项
+ const option = {
+ legend: {
+ icon: "circle",
+ bottom: "0%",
+ left: "center",
+ itemGap: 20,
+ textStyle: {
+ fontSize: 12,//字体大小
+ color: "#787E95"//字体颜色
+ }
+ },
+ color: ["#A6BEF3", "#205CE1"],
+ grid: {
+ bottom: "10%",
+ containLabel: true
+ },
+ series: [
+ {
+ name: "性别统计",
+ type: "pie",
+ startAngle:-180,
+ radius: [40, 70],
+ roseType: "radius",
+ animation: false,
+ label: {
+ show: false
+ },
+ data: [
+ { value: 70, name: "男" },
+ { value: 30, name: "女" }
+ ]
+ }
+ ]
+ };
+ // 配置项给实例对象
+ myChart.setOption(option);
+ return myChart;
+};
+
+export default GenderStaticsPie;
diff --git a/src/pages/personnelReport/talentStructureTable/components/index.less b/src/pages/personnelReport/talentStructureTable/components/index.less
new file mode 100644
index 0000000..071bab9
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/components/index.less
@@ -0,0 +1,141 @@
+.structureCardWrapper {
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+
+ .top {
+ display: flex;
+
+ & > span {
+ flex: 1;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ font-size: 14px;
+ color: #333333;
+ font-weight: 700;
+ }
+
+ ul {
+ display: flex;
+
+ li:last-child {
+ margin-left: 16px;
+ }
+
+ li.active {
+ color: #333333;
+ }
+
+ li {
+ font-size: 12px;
+ color: #D4D4D4;
+ cursor: pointer;
+ }
+ }
+ }
+
+ .center {
+ display: flex;
+ align-items: flex-end;
+
+ & > div:first-child {
+ & > span:first-child {
+ font-size: 24px;
+ letter-spacing: 0;
+ font-weight: 700;
+ }
+
+ & > span:last-child {
+ font-size: 14px;
+ color: #D4D4D4;
+ font-weight: 400;
+ }
+ }
+
+ & > div {
+ flex: 1;
+ }
+
+ .charts {
+ height: 62px;
+ }
+ }
+
+ .bottom {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-top: 0.5px solid #e5e5e5;
+ padding-top: 10px;
+
+ & > span {
+ & > span:first-child {
+ font-size: 12px;
+ color: #D4D4D4;
+ font-weight: 400;
+ margin-right: 8px;
+ }
+
+ & > span:last-child {
+ font-size: 12px;
+ color: #333333;
+ font-weight: 400;
+ }
+ }
+ }
+}
+
+.structureFrameWrapper {
+ width: 100%;
+ min-height: 100px;
+ display: flex;
+ flex-direction: column;
+ background: #fff;
+ padding: 16px;
+ border-radius: 5px;
+
+ .header {
+ display: flex;
+ align-items: center;
+ border-bottom: .5px solid #e5e5e5;
+ padding-bottom: 14px;
+
+ img {
+ width: 28px;
+ }
+
+ span {
+ display: inline-block;
+ font-size: 18px;
+ color: #333333;
+ letter-spacing: 0;
+ font-weight: 700;
+ margin-left: 8px;
+ }
+ }
+
+ .tabBox {
+ margin: 0;
+ display: flex;
+ justify-content: flex-end;
+ padding: 20px 32px 0 0;
+
+ li:last-child {
+ margin-left: 16px;
+ }
+
+ li.active {
+ color: #1E66F6;
+ }
+
+ li {
+ font-size: 14px;
+ color: #999999;
+ cursor: pointer;
+ font-weight: 550;
+ }
+ }
+}
diff --git a/src/pages/personnelReport/talentStructureTable/components/internStaticsCharts.ts b/src/pages/personnelReport/talentStructureTable/components/internStaticsCharts.ts
new file mode 100644
index 0000000..39ecef5
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/components/internStaticsCharts.ts
@@ -0,0 +1,85 @@
+const InternStaticsBar = (echarts: any) => {
+ // 实例化对象
+ const myChart = echarts.init(document.getElementById("internStatics"));
+ // 配置项
+ const option = {
+ xAxis: [
+ {
+ type: "value",
+ axisLabel: {
+ formatter: "{value} "
+ },
+ splitLine: {
+ show: true,
+ lineStyle: {
+ type: "dashed",
+ color: "#1D3039"
+ }
+ },
+ axisTick: {
+ show: false
+ },
+ axisLine: {
+ show: false,
+ lineStyle: {
+ fontSize: 12,
+ color: "#D4D4D4"
+ }
+ }
+ }
+ ],
+ grid: {
+ top: "10%",
+ left: "5%",
+ right: "5%",
+ bottom: "3%",
+ containLabel: true
+ },
+ yAxis: [
+ {
+ type: "category",
+ offset: 0,
+ data: ["项目实习生", "销售实习生", "技术实习生", "大区实习生", "客服实习生"],
+ axisPointer: {
+ type: "shadow"
+ },
+ axisLine: {
+ //这是x轴文字颜色
+ show: false
+ },
+ axisTick: {
+ show: false
+ },
+ axisLabel: {
+ color: "#787E95",
+ fontSize: 10
+ }
+ }
+ ],
+ series: [
+ {
+ data: [34, 19, 15, 32, 11],
+ type: "bar",
+ barWidth: "25%",
+ realtimeSort: true,
+ yAxisIndex: 0,
+ itemStyle: {
+ color: "#4CAEFF" //设定单个柱子颜色
+ },
+ label: {
+ normal: {
+ show: true,
+ position: "right",
+ fontWeight: "bold",
+ fontSize: 12
+ }
+ }
+ }
+ ]
+ };
+ // 配置项给实例对象
+ myChart.setOption(option);
+ return myChart;
+};
+
+export default InternStaticsBar;
diff --git a/src/pages/personnelReport/talentStructureTable/components/lineStaticsCharts.ts b/src/pages/personnelReport/talentStructureTable/components/lineStaticsCharts.ts
new file mode 100644
index 0000000..30c08a6
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/components/lineStaticsCharts.ts
@@ -0,0 +1,50 @@
+const LineStaticsPie = (echarts: any) => {
+ // 实例化对象
+ const myChart = echarts.init(document.getElementById("lineStatics"));
+ // 配置项
+ const option = {
+ legend: {
+ icon: "circle",
+ bottom: "0%",
+ left: "center",
+ itemGap: 20,
+ textStyle: {
+ fontSize: 12,//字体大小
+ color: "#787E95"//字体颜色
+ }
+ },
+ color: ["#61D485", "#F4CB48", "#7499F5", "#65BFDC", "#ED9C5F"],
+ series: [
+ {
+ name: "司龄统计",
+ type: "pie",
+ radius: ["45%", "60%"],
+ center: ['50%', '41%'],
+ avoidLabelOverlap: false,
+ animation: false,
+ label: {
+ normal: {
+ formatter: "{d}%",
+ padding: [0, -25],
+ position: "outer" //文字显示在内部,如果在外边把这个去掉就好
+ }
+ },
+ labelLine: {
+ show: false
+ },
+ data: [
+ { value: 40, name: "项目" },
+ { value: 15, name: "市场" },
+ { value: 20, name: "销售" },
+ { value: 15, name: "支撑" },
+ { value: 10, name: "销售1" }
+ ]
+ }
+ ]
+ };
+ // 配置项给实例对象
+ myChart.setOption(option);
+ return myChart;
+};
+
+export default LineStaticsPie;
diff --git a/src/pages/personnelReport/talentStructureTable/components/monthlyTrendsCharts.ts b/src/pages/personnelReport/talentStructureTable/components/monthlyTrendsCharts.ts
new file mode 100644
index 0000000..0f412a9
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/components/monthlyTrendsCharts.ts
@@ -0,0 +1,149 @@
+const MonthlyTrendsBar = (echarts: any) => {
+ // 实例化对象
+ const myChart = echarts.init(document.getElementById("monthlyTrendsCharts"));
+ // 配置项
+ const option = {
+ tooltip: {
+ // 坐标轴指示器,坐标轴触发有效
+ trigger: "axis",
+ axisPointer: {
+ // 默认为直线,可选为:'line' | 'shadow'
+ type: "shadow"
+ }
+ },
+ grid: {
+ top: "10%",
+ left: "2%",
+ right: "2%",
+ bottom: "3%",
+ containLabel: true
+ },
+ xAxis: [
+ {
+ type: "category",
+ data: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
+ axisTick: {
+ alignWithLabel: true,
+ show: false
+ },
+ // 修改坐标值样式
+ axisLabel: {
+ color: "#B8B8B8",
+ fontSize: 16,
+ show: true
+ },
+ axisLine: {
+ show: false
+ }
+ }
+ ],
+ yAxis: [
+ {
+ type: "value",
+ name: "人",
+ // 修改坐标值样式
+ axisLabel: {
+ color: "#787E95",
+ fontSize: 14
+ // formatter: '{value} 人'
+ },
+ nameTextStyle: {
+ color: "#787E95",
+ fontSize: 16
+ },
+ // 修改坐标轴线样式
+ axisLine: {
+ show: true,
+ lineStyle: {
+ color: "transparent"
+ }
+ },
+ axisTick: {
+ show: false // 不显示坐标轴刻度线
+ },
+ splitLine: {
+ lineStyle: {
+ type: "dashed",
+ color: "rgba(93,126,158,1)"
+ }
+ }
+ }
+ ],
+ series: [
+ {
+ name: "入职",
+ type: "bar",
+ showBackground: false,
+ barWidth: "8%",
+ barGap: "100%",
+ data: [250, 250, 320, 410, 280, 320, 405, 405, 320, 250, 280, 405],
+ // bar 样式修改
+ itemStyle: {
+ barBorderRadius: 5,
+ color: "#0FC482"
+ }
+ },
+ {
+ name: "离职",
+ type: "bar",
+ showBackground: false,
+ barWidth: "8%",
+ data: [370, 370, 260, 110, 390, 280, 110, 110, 370, 260, 390, 110],
+ // bar 样式修改
+ itemStyle: {
+ barBorderRadius: 5,
+ color: "#FFA500"
+ }
+ },
+ {
+ name: "在职",
+ type: "bar",
+ showBackground: false,
+ barWidth: "8%",
+ data: [310, 310, 80, 280, 310, 70, 280, 280, 80, 280, 310, 280],
+ // bar 样式修改
+ itemStyle: {
+ barBorderRadius: 5,
+ color: "#FFD600"
+ }
+ },
+ {
+ name: "离职",
+ type: "line",
+ yAxisIndex: 0,
+ data: [370, 370, 260, 110, 390, 280, 110, 110, 370, 260, 390, 110],
+ itemStyle: {
+ normal: {
+ color: "#FFD700",
+ lineStyle: {
+ color: "#FFD700"
+ }
+ }
+ },
+ areaStyle: {
+ normal: {
+ color: {//分隔区域的颜色
+ x0: 0,
+ y0: 0,
+ x2: 0,
+ y2: 1,
+ colorStops: [{
+ offset: 0,
+ color: "#FFD700" // 0% 处的颜色
+ }, {
+ offset: 1,
+ color: "rgba(255,215,0,0)" // 100% 处的颜色;中间还可以设置50%、20%、70%时的颜色
+ }],
+ globalCoord: false // 缺省为 false,以确保上面的x,y,x2,y2表示的是百分比
+ }
+ }
+ }
+ }
+ ]
+ };
+ // 配置项给实例对象
+ myChart.setOption(option);
+ return myChart;
+};
+
+export default MonthlyTrendsBar;
diff --git a/src/pages/personnelReport/talentStructureTable/components/rankingCharts.ts b/src/pages/personnelReport/talentStructureTable/components/rankingCharts.ts
new file mode 100644
index 0000000..4b4a2e0
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/components/rankingCharts.ts
@@ -0,0 +1,182 @@
+const RankingBar = (echarts: any) => {
+ // 实例化对象
+ const colorList = ["#1E66F6", "#70CDFF", "#00C48B", "#FFD700", "#1E66F6", "#70CDFF", "#00C48B", "#FFD700"];
+ const myChart = echarts.init(document.getElementById("rankingCharts"));
+ // 配置项
+ const option = {
+ xAxis: [
+ {
+ type: "value",
+ axisLabel: {
+ formatter: "{value} "
+ },
+ splitLine: {
+ show: true,
+ lineStyle: {
+ type: "dashed",
+ color: "#1D3039"
+ }
+ },
+ axisTick: {
+ show: false
+ },
+ axisLine: {
+ show: false,
+ lineStyle: {
+ fontSize: 12,
+ color: "#D4D4D4"
+ }
+ }
+ }
+ ],
+ grid: {
+ top: "10%",
+ left: "5%",
+ right: "5%",
+ bottom: "3%",
+ containLabel: true
+ },
+ yAxis: [
+ {
+ type: "category",
+ offset: 0,
+ inverse: true, //升序
+ // axisLabel: {
+ // color: "#787E95",
+ // fontSize: 16
+ // },
+ data: ["契约锁", "泛微北京", "泛微上海", "产品研发中心", "泛微华南一部", "泛微广州一部", "泛微杭州", "EBU事业一部"],
+ axisPointer: {
+ type: "shadow"
+ },
+ axisLine: {
+ //这是x轴文字颜色
+ show: false
+ },
+ axisTick: {
+ show: false
+ },
+ axisLabel: {
+ color: "#787E95",
+ fontSize: 14,
+ formatter: function (value: any, index: number) {
+ if (index == 0) {
+ return "{one|" + "} {a| " + value + "}";
+ } else if (index == 1) {
+ return "{two|" + "} {a|" + value + "}";
+ } else if (index == 2) {
+ return "{three|" + "} {a|" + value + "}";
+ }
+ return value;
+ },
+ rich: {
+ a: {
+ color: "#787E95",
+ fontSize: 14
+ },
+ // 第一名
+ one: {
+ width: 40,
+ height: 20,
+ margin: 10,
+ align: "center",
+ backgroundColor: {
+ image: require("../../../../assets/images/one.png")
+ }
+ },
+ two: {
+ width: 40,
+ height: 20,
+ margin: 10,
+ align: "center",
+ backgroundColor: {
+ image: require("../../../../assets/images/two.png")
+ }
+ },
+ three: {
+ width: 40,
+ height: 20,
+ marginRight: 20,
+ align: "center",
+ backgroundColor: {
+ image: require("../../../../assets/images/three.png")
+ }
+ }
+ }
+ }
+ },
+ {
+ type: "category",
+ data: [4096, 1412, 1337, 788, 788, 347, 332, 291],
+ inverse: true,//数组翻转显示
+ axisTick: {
+ alignWithLabel: true,
+ show: false
+ },
+ axisLine: {
+ show: false//不显示y轴的线
+ },
+ axisLabel: {
+ textStyle: {
+ fontSize: 16,
+ color: function (params: any, index: any) {
+ return colorList[index];
+ }
+ }
+ }
+ }
+ ],
+ series: [
+ {
+ data: _.map([4096, 1412, 1337, 788, 788, 347, 332, 291], (it, idx) => ({
+ value: it,
+ itemStyle: {
+ color: colorList[idx], //设定单个柱子颜色
+ borderColor: colorList[idx], //设定单个柱子边框颜色
+ barBorderRadius: [10, 10, 10, 10]
+ }
+ })),
+ type: "bar",
+ barWidth: "20%",
+ realtimeSort: true,
+ yAxisIndex: 0,
+ label: {
+ normal: {
+ show: false,
+ position: "right",
+ fontWeight: "bold",
+ fontSize: 14
+ }
+ },
+ showBackground: true,
+ backgroundStyle: {
+ color: "rgba(220, 220, 220, 0.8)",
+ barBorderRadius: [10, 10, 10, 10]
+ }
+ },
+ {
+ name: "",
+ type: "bar",
+ yAxisIndex: 1,//使两个柱状图重合的效果
+ barWidth: "25%",
+ data: _.map([5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000], (it, idx) => ({
+ value: it,
+ itemStyle: {
+ color: "none",
+ borderColor: colorList[idx],
+ borderWidth: 2,
+ barBorderRadius: [10, 10, 10, 10]
+ }
+ })),
+ label: {
+ show: false
+ }
+ }
+ ]
+ };
+ // 配置项给实例对象
+ myChart.setOption(option);
+ return myChart;
+};
+
+export default RankingBar;
diff --git a/src/pages/personnelReport/talentStructureTable/components/structureCard.tsx b/src/pages/personnelReport/talentStructureTable/components/structureCard.tsx
new file mode 100644
index 0000000..d84b70a
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/components/structureCard.tsx
@@ -0,0 +1,68 @@
+/*
+ * Author: 黎永顺
+ * name: 卡片组件
+ * Description:
+ * Date: 2023/5/5
+ */
+import React, { FC } from "react";
+import { TinyArea } from "@ant-design/plots";
+import styles from "./index.less";
+import cs from "classnames";
+
+interface OwnProps {
+ title: string;
+ active: number;
+ number: string;
+ unit: string;
+ color: string;
+ tabList: Array
;
+}
+
+type Props = OwnProps;
+const config = {
+ height: 60,
+ autoFit: false,
+ data: [264, 417, 438, 887, 309, 397, 550],
+ smooth: true,
+ areaStyle: {
+ fill: "#d6e3fd"
+ },
+ tooltip: {
+ showCrosshairs: false,
+ showContent: false
+ }
+};
+const StructureCard: FC = (props) => {
+ const { active, tabList, title, number, unit, color } = props;
+
+ return (
+
+
+
{title}
+
+ {
+ _.map(tabList, (it, idx) => {
+ const classes = cs({
+ [styles["active"]]: idx === active
+ });
+ return - {it}
;
+ })
+ }
+
+
+
+
+ 同比:4.75%
+ 环比:1.75%
+
+
+ );
+};
+
+export default StructureCard;
diff --git a/src/pages/personnelReport/talentStructureTable/components/structureFrame.tsx b/src/pages/personnelReport/talentStructureTable/components/structureFrame.tsx
new file mode 100644
index 0000000..49366de
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/components/structureFrame.tsx
@@ -0,0 +1,48 @@
+/*
+ * Author: 黎永顺
+ * name: 人才结构表框组件
+ * Description:
+ * Date: 2023/5/5
+ */
+import React, { FC, useState } from "react";
+import styles from "./index.less";
+import cs from "classnames";
+
+interface OwnProps {
+ title: string;
+ children: any;
+ tabList?: Array;
+}
+
+type Props = OwnProps;
+
+const StructureFrame: FC = (props) => {
+ const { children, tabList, title } = props;
+ const [active, setActive] = useState(0);
+
+ return (
+
+
+
})
+
{title}
+
+ {
+ !_.isEmpty(tabList) &&
+
+ {
+ _.map(tabList, (it, idx) => {
+ const classes = cs({
+ [styles["active"]]: idx === active
+ });
+ return - setActive(idx)}>{it}
;
+ })
+ }
+
+ }
+ {children}
+
+ );
+};
+
+export default StructureFrame
+;
diff --git a/src/pages/personnelReport/talentStructureTable/index.less b/src/pages/personnelReport/talentStructureTable/index.less
new file mode 100644
index 0000000..6f6e2d1
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/index.less
@@ -0,0 +1,111 @@
+.structureWrapper {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ height: 100%;
+ background: #e5e5e5;
+ overflow: auto;
+
+ .structureColumn_1 {
+ display: flex;
+ margin: 0 0 10px;
+ padding: 0;
+
+ & > li:not(:last-child) {
+ margin-right: 16px;
+ }
+
+ & > li {
+ flex: 1;
+ border-radius: 5px;
+ background: #FFF;
+ max-height: 160px;
+ min-height: 100px;
+ padding: 16px;
+ }
+ }
+
+ .structureColumn_2 {
+ margin-bottom: 10px;
+
+ .multipleCharts {
+ height: 330px;
+ display: flex;
+
+ & > div:not(:last-child) {
+ div {
+ border-right: .5px solid #e5e5e5;
+ }
+ }
+
+ & > div {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+
+ span {
+ display: inline-block;
+ width: 100%;
+ text-align: center;
+ font-size: 16px;
+ color: #333333;
+ font-weight: 700;
+ margin-top: 20px;
+ }
+
+ div {
+ flex: 1;
+ }
+ }
+ }
+ }
+
+ .structureColumn_3 {
+ display: flex;
+
+ & > div:first-child {
+ flex: 4 1;
+ margin-right: 16px;
+ }
+
+ & > div:last-child {
+ flex: 2 1;
+ }
+
+ .monthlyTrendsChartsBox {
+ width: 100%;
+ min-height: 438px;
+ max-height: 438px;
+ }
+
+ .rankingChartsBox {
+ width: 100%;
+ min-height: 480px;
+ max-height: 480px;
+ height: 480px;
+
+ :global {
+ .dv-capsule-chart {
+ width: 100%;
+ height: 100%;
+
+ .capsule-container {
+ .unit-label {
+ font-size: 12px;
+ color: #D4D4D4;
+ text-align: right;
+ font-weight: 400;
+ }
+ }
+
+ .label-column {
+ font-size: 16px;
+ color: #787E95;
+ text-align: right;
+ font-weight: 400;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/pages/personnelReport/talentStructureTable/index.tsx b/src/pages/personnelReport/talentStructureTable/index.tsx
new file mode 100644
index 0000000..3591afa
--- /dev/null
+++ b/src/pages/personnelReport/talentStructureTable/index.tsx
@@ -0,0 +1,99 @@
+/*
+ * Author: 黎永顺
+ * name: 人才结构表
+ * Description:
+ * Date: 2023/4/27
+ */
+import React, { FC, useEffect, useState } from "react";
+// @ts-ignore
+import echarts from "echarts";
+// @ts-ignore
+import { CapsuleChart } from "@jiaminghi/data-view-react";
+import StructureCard from "./components/structureCard";
+import StructureFrame from "./components/structureFrame";
+import MonthlyTrendsBar from "./components/monthlyTrendsCharts";
+import RankingBar from "./components/rankingCharts";
+import AgeStaticsPie from "./components/ageStaticsCharts";
+import GenderStaticsPie from "./components/genderStaticsCharts";
+import LineStaticsPie from "./components/lineStaticsCharts";
+import InternStaticsBar from "./components/internStaticsCharts";
+import EducationStaticsRedar from "./components/educationStaticsCharts";
+import { structureCardList } from "../constants";
+import styles from "./index.less";
+
+interface OwnProps {
+}
+
+type Props = OwnProps;
+
+const index: FC = (props) => {
+ const [card, setCard] = useState(structureCardList);
+ useEffect(() => {
+ const monthlyTrendsBar = MonthlyTrendsBar(echarts);
+ const rankingBar = RankingBar(echarts);
+ const ageStaticsPie = AgeStaticsPie(echarts);
+ const genderStaticsPie = GenderStaticsPie(echarts);
+ const lineStaticsPie = LineStaticsPie(echarts);
+ const internStaticsBar = InternStaticsBar(echarts);
+ const educationStaticsRedar = EducationStaticsRedar(echarts);
+ // 屏幕缩放对chart图表进行自适应处理,调用实例的resize方法
+ window.onresize = () => {
+ monthlyTrendsBar.resize();
+ rankingBar.resize();
+ ageStaticsPie.resize();
+ genderStaticsPie.resize();
+ lineStaticsPie.resize();
+ internStaticsBar.resize();
+ educationStaticsRedar.resize();
+ };
+ return () => {
+ };
+ }, []);
+
+ return (
+
+
+ {
+ _.map(card, (it, idx) => {
+ return ;
+ })
+ }
+
+
+
+
+ );
+};
+
+export default index;
diff --git a/src/utils/chart.js b/src/utils/chart.js
new file mode 100644
index 0000000..13645a7
--- /dev/null
+++ b/src/utils/chart.js
@@ -0,0 +1,381 @@
+/*
+ * ECharts 组件基础部分
+ * 传入 option 和渲染方式 renderer
+ * */
+
+import React, { PureComponent } from "react";
+import * as echarts from "echarts";
+import "zrender/lib/svg/svg";
+import { debounce } from "./common"; // 一个节流函数
+
+export default class Chart extends PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = {
+ width: "100%",
+ height: "100%"
+ };
+ this.chart = null;
+ }
+
+ async componentDidMount() {
+ // 初始化图表
+ await this.initChart(this.el);
+ // 将传入的配置(包含数据)注入
+ this.setOption(this.props.option);
+ // 监听屏幕缩放,重新绘制 echart 图表
+ window.addEventListener("resize", debounce(this.resize, 100));
+ }
+
+ componentDidUpdate() {
+ // 每次更新组件都重置
+ this.setOption(this.props.option);
+ }
+
+ componentWillUnmount() {
+ // 组件卸载前卸载图表
+ this.dispose();
+ }
+
+ render() {
+ const { width, height } = this.state;
+
+ return (
+ (this.el = el)}
+ style={{ width, height }}
+ />
+ );
+ }
+
+ initChart = el => {
+ // renderer 用于配置渲染方式 可以是 svg 或者 canvas
+ const renderer = this.props.renderer || "canvas";
+
+ return new Promise(resolve => {
+ setTimeout(() => {
+ this.chart = echarts.init(el, null, {
+ renderer,
+ width: "auto",
+ height: "auto"
+ });
+ resolve();
+ }, 0);
+ });
+ };
+ setOption = option => {
+ if (!this.chart) {
+ return;
+ }
+
+ const notMerge = this.props.notMerge;
+ const lazyUpdate = this.props.lazyUpdate;
+
+ this.chart.setOption(option, notMerge, lazyUpdate);
+ };
+ dispose = () => {
+ if (!this.chart) {
+ return;
+ }
+
+ this.chart.dispose();
+ this.chart = null;
+ };
+ resize = () => {
+ this.chart && this.chart.resize();
+ };
+ getInstance = () => {
+ return this.chart;
+ };
+}
+
+/**
+ * 绘制3d图
+ * @param pieData 总数据
+ * @param internalDiameterRatio:透明的空心占比
+ * @param distance 视角到主体的距离
+ * @param alpha 旋转角度
+ * @param pieHeight 立体的高度
+ * @param opacity 饼或者环的透明度
+ * @param isSameHeight 饼或者环的透明度
+ */
+const getPie3D = (
+ pieData,
+ internalDiameterRatio,
+ distance,
+ alpha,
+ pieHeight,
+ opacity = 1,
+ isSameHeight
+) => {
+ const series = [];
+ let sumValue = 0;
+ let startValue = 0;
+ let endValue = 0;
+ let legendData = [];
+ let legendBfb = [];
+ const k = 1 - internalDiameterRatio;
+ pieData.sort((a, b) => {
+ return b.value - a.value;
+ });
+ // 为每一个饼图数据,生成一个 series-surface 配置
+ for (let i = 0; i < pieData.length; i++) {
+ sumValue += pieData[i].value;
+ const seriesItem = {
+ name:
+ typeof pieData[i].name === "undefined" ? `series${i}` : pieData[i].name,
+ type: "surface",
+ parametric: true,
+ wireframe: {
+ show: false
+ },
+ pieData: pieData[i],
+ pieStatus: {
+ selected: false,
+ hovered: false,
+ k: k
+ },
+ center: ["10%", "50%"]
+ };
+ if (typeof pieData[i].itemStyle !== "undefined") {
+ const itemStyle = {};
+ itemStyle.color =
+ typeof pieData[i].itemStyle.color !== "undefined"
+ ? pieData[i].itemStyle.color
+ : opacity;
+ itemStyle.opacity =
+ typeof pieData[i].itemStyle.opacity !== "undefined"
+ ? pieData[i].itemStyle.opacity
+ : opacity;
+ seriesItem.itemStyle = itemStyle;
+ }
+ series.push(seriesItem);
+ }
+
+ // 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
+ // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
+ legendData = [];
+ legendBfb = [];
+ for (let i = 0; i < series.length; i++) {
+ endValue = startValue + series[i].pieData.value;
+ series[i].pieData.startRatio = startValue / sumValue;
+ series[i].pieData.endRatio = endValue / sumValue;
+ series[i].parametricEquation = getParametricEquation(
+ series[i].pieData.startRatio,
+ series[i].pieData.endRatio,
+ false,
+ false,
+ k,
+ !isSameHeight && series[i].pieData.value
+ );
+ startValue = endValue;
+ const bfb = fomatFloat(series[i].pieData.value / sumValue, 4);
+ legendData.push({
+ name: series[i].name,
+ value: bfb
+ });
+ legendBfb.push({
+ name: series[i].name,
+ value: bfb
+ });
+ }
+ const boxHeight = getHeight3D(series, pieHeight); // 通过pieHeight设定3d饼/环的高度,单位是px
+ // 准备待返回的配置项,把准备好的 legendData、series 传入。
+ const option = {
+ legend: {
+ show: false,
+ data: legendData,
+ orient: "vertical",
+ left: 10,
+ top: 10,
+ itemGap: 10,
+ textStyle: {
+ color: "#A1E2FF"
+ },
+ icon: "circle",
+ formatter: function (param) {
+ const item = legendBfb.filter((item) => item.name === param)[0];
+ const bfs = fomatFloat(item.value * 100, 2) + "%";
+ return `${item.name} ${bfs}`;
+ }
+ },
+ labelLine: {
+ show: true,
+ lineStyle: {
+ color: "#fff"
+ }
+ },
+ label: {
+ show: true,
+ position: "outside",
+ formatter: "{b} \n{c} {d}%"
+ },
+ tooltip: {
+ backgroundColor: "#033b77",
+ borderColor: "#21f2c4",
+ textStyle: {
+ color: "#fff",
+ fontSize: 13
+ },
+ formatter: (params) => {
+ if (
+ params.seriesName !== "mouseoutSeries" &&
+ params.seriesName !== "信用评价"
+ ) {
+ // console.log(option.series, params.seriesName, "option.series[params.seriesIndex].pieData");
+ const bfb = (
+ (option.series[params.seriesIndex].pieData.endRatio -
+ option.series[params.seriesIndex].pieData.startRatio) *
+ 100
+ ).toFixed(2);
+ return (
+ // ${params.seriesName}
+ `数量
` +
+ `` +
+ `${option.series[params.seriesIndex].pieData.value}(${bfb}%)`
+ );
+ }
+ }
+ },
+ xAxis3D: {
+ min: -1,
+ max: 1
+ },
+ yAxis3D: {
+ min: -1,
+ max: 1
+ },
+ zAxis3D: {
+ min: -1,
+ max: 1
+ },
+ grid3D: {
+ show: false,
+ left: "18%",
+ boxHeight: !isSameHeight ? boxHeight : 15, // 圆环的高度
+ viewControl: {
+ // 3d效果可以放大、旋转等,请自己去查看官方配置
+ alpha, // 角度
+ distance, // 调整视角到主体的距离,类似调整zoom
+ rotateSensitivity: 0, // 设置为0无法旋转
+ zoomSensitivity: 0, // 设置为0无法缩放
+ panSensitivity: 0, // 设置为0无法平移
+ autoRotate: false // 自动旋转
+ }
+ },
+ series: series
+ };
+ return option;
+};
+
+/**
+ * 生成扇形的曲面参数方程,用于 series-surface.parametricEquation
+ */
+const getParametricEquation = (
+ startRatio,
+ endRatio,
+ isSelected,
+ isHovered,
+ k,
+ h = 1
+) => {
+ // 计算
+ const midRatio = (startRatio + endRatio) / 2;
+ const startRadian = startRatio * Math.PI * 2;
+ const endRadian = endRatio * Math.PI * 2;
+ const midRadian = midRatio * Math.PI * 2;
+ // 如果只有一个扇形,则不实现选中效果。
+ if (startRatio === 0 && endRatio === 1) {
+ isSelected = false;
+ }
+ // 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
+ k = typeof k !== "undefined" ? k : 1 / 3;
+ // 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
+ const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
+ const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
+ // 计算高亮效果的放大比例(未高亮,则比例为 1)
+ const hoverRate = isHovered ? 1.05 : 1;
+ // 返回曲面参数方程
+ return {
+ u: {
+ min: -Math.PI,
+ max: Math.PI * 3,
+ step: Math.PI / 32
+ },
+ v: {
+ min: 0,
+ max: Math.PI * 2,
+ step: Math.PI / 20
+ },
+ x: function (u, v) {
+ if (u < startRadian) {
+ return (
+ offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate
+ );
+ }
+ if (u > endRadian) {
+ return (
+ offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate
+ );
+ }
+ return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
+ },
+ y: function (u, v) {
+ if (u < startRadian) {
+ return (
+ offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate
+ );
+ }
+ if (u > endRadian) {
+ return (
+ offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate
+ );
+ }
+ return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
+ },
+ z: function (u, v) {
+ if (u < -Math.PI * 0.5) {
+ return Math.sin(u);
+ }
+ if (u > Math.PI * 2.5) {
+ return Math.sin(u) * h * 0.1;
+ }
+ return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
+ }
+ };
+};
+
+/**
+ * 获取3d丙图的最高扇区的高度
+ */
+const getHeight3D = (series, height) => {
+ series.sort((a, b) => {
+ return b.pieData.value - a.pieData.value;
+ });
+ return (height * 25) / series[0].pieData.value;
+};
+
+/**
+ * 格式化浮点数
+ */
+const fomatFloat = (num, n) => {
+ let f = parseFloat(num);
+ if (isNaN(f)) {
+ return false;
+ }
+ f = Math.round(num * Math.pow(10, n)) / Math.pow(10, n); // n 幂
+ let s = f.toString();
+ let rs = s.indexOf(".");
+ // 判定如果是整数,增加小数点再补0
+ if (rs < 0) {
+ rs = s.length;
+ s += ".";
+ }
+ while (s.length <= rs + n) {
+ s += "0";
+ }
+ return s;
+};
+
+export { getPie3D, getParametricEquation };
diff --git a/src/utils/common.js b/src/utils/common.js
index 13c0b0e..e82eba6 100644
--- a/src/utils/common.js
+++ b/src/utils/common.js
@@ -60,6 +60,75 @@ export const exceptStr = (str) => {
return {};
}
};
+/**
+ * @param {date} time 需要转换的时间
+ * @param {String} fmt 需要转换的格式 如 yyyy-MM-dd、yyyy-MM-dd HH:mm:ss
+ */
+export const formatTime = (time, fmt) => {
+ if (!time) return "";
+ else {
+ const date = new Date(time);
+ const o = {
+ "M+": date.getMonth() + 1,
+ "d+": date.getDate(),
+ "H+": date.getHours(),
+ "m+": date.getMinutes(),
+ "s+": date.getSeconds(),
+ "q+": Math.floor((date.getMonth() + 3) / 3),
+ S: date.getMilliseconds()
+ };
+ if (/(y+)/.test(fmt))
+ fmt = fmt.replace(
+ RegExp.$1,
+ (date.getFullYear() + "").substr(4 - RegExp.$1.length)
+ );
+ for (const k in o) {
+ if (new RegExp("(" + k + ")").test(fmt)) {
+ fmt = fmt.replace(
+ RegExp.$1,
+ RegExp.$1.length === 1
+ ? o[k]
+ : ("00" + o[k]).substr(("" + o[k]).length)
+ );
+ }
+ }
+ return fmt;
+ }
+};
+export const debounce = (func, wait, immediate) => {
+ let timeout, args, context, timestamp, result;
+
+ const later = function () {
+ // 据上一次触发时间间隔
+ const last = +new Date() - timestamp;
+
+ // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
+ if (last < wait && last > 0) {
+ timeout = setTimeout(later, wait - last);
+ } else {
+ timeout = null;
+ // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
+ if (!immediate) {
+ result = func.apply(context, args);
+ if (!timeout) context = args = null;
+ }
+ }
+ };
+
+ return function (...args) {
+ context = this;
+ timestamp = +new Date();
+ const callNow = immediate && !timeout;
+ // 如果延时不存在,重新设定延时
+ if (!timeout) timeout = setTimeout(later, wait);
+ if (callNow) {
+ result = func.apply(context, args);
+ context = args = null;
+ }
+
+ return result;
+ };
+};
export const paginationFun = (tableListPageObj, sizeChange, onChange) => {
return {
@@ -76,8 +145,8 @@ export const paginationFun = (tableListPageObj, sizeChange, onChange) => {
onChange({
pageNum: page,
size,
- total,
+ total
});
- },
+ }
};
};
diff --git a/src/utils/flexible.js b/src/utils/flexible.js
new file mode 100644
index 0000000..44412fe
--- /dev/null
+++ b/src/utils/flexible.js
@@ -0,0 +1,147 @@
+(function(win, lib) {
+ const doc = win.document;
+ const docEl = doc.documentElement;
+ let metaEl = doc.querySelector("meta[name=\"viewport\"]");
+ const flexibleEl = doc.querySelector("meta[name=\"flexible\"]");
+ let dpr = 0;
+ let scale = 0;
+ let tid;
+ const flexible = lib.flexible || (lib.flexible = {});
+
+ if (metaEl) {
+ console.warn("将根据已有的meta标签来设置缩放比例");
+ const match = metaEl
+ .getAttribute("content")
+ // eslint-disable-next-line no-useless-escape
+ .match(/initial\-scale=([\d\.]+)/);
+ if (match) {
+ scale = parseFloat(match[1]);
+ dpr = parseInt(1 / scale);
+ }
+ } else if (flexibleEl) {
+ const content = flexibleEl.getAttribute("content");
+ if (content) {
+ // eslint-disable-next-line no-useless-escape
+ const initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
+ // eslint-disable-next-line no-useless-escape
+ const maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
+ if (initialDpr) {
+ dpr = parseFloat(initialDpr[1]);
+ scale = parseFloat((1 / dpr).toFixed(2));
+ }
+ if (maximumDpr) {
+ dpr = parseFloat(maximumDpr[1]);
+ scale = parseFloat((1 / dpr).toFixed(2));
+ }
+ }
+ }
+
+ if (!dpr && !scale) {
+ // eslint-disable-next-line no-unused-vars
+ const isAndroid = win.navigator.appVersion.match(/android/gi);
+ const isIPhone = win.navigator.appVersion.match(/iphone/gi);
+ const devicePixelRatio = win.devicePixelRatio;
+ if (isIPhone) {
+ // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
+ if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
+ dpr = 3;
+ } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
+ dpr = 2;
+ } else {
+ dpr = 1;
+ }
+ } else {
+ // 其他设备下,仍旧使用1倍的方案
+ dpr = 1;
+ }
+ scale = 1 / dpr;
+ }
+
+ docEl.setAttribute("data-dpr", dpr);
+ if (!metaEl) {
+ metaEl = doc.createElement("meta");
+ metaEl.setAttribute("name", "viewport");
+ metaEl.setAttribute(
+ "content",
+ "initial-scale=" +
+ scale +
+ ", maximum-scale=" +
+ scale +
+ ", minimum-scale=" +
+ scale +
+ ", user-scalable=no"
+ );
+ if (docEl.firstElementChild) {
+ docEl.firstElementChild.appendChild(metaEl);
+ } else {
+ const wrap = doc.createElement("div");
+ wrap.appendChild(metaEl);
+ doc.write(wrap.innerHTML);
+ }
+ }
+
+ function refreshRem() {
+ let width = docEl.getBoundingClientRect().width;
+ // 最小1366px,最大适配2560px
+ if (width / dpr < 1366) {
+ width = 1366 * dpr;
+ } else if (width / dpr > 2560) {
+ width = 2560 * dpr;
+ }
+ // 设置成24等份,设计稿时1920px的,这样1rem就是80px
+ const rem = width / 24;
+ docEl.style.fontSize = rem + "px";
+ flexible.rem = win.rem = rem;
+ }
+
+ win.addEventListener(
+ "resize",
+ function() {
+ clearTimeout(tid);
+ tid = setTimeout(refreshRem, 300);
+ },
+ false
+ );
+ win.addEventListener(
+ "pageshow",
+ function(e) {
+ if (e.persisted) {
+ clearTimeout(tid);
+ tid = setTimeout(refreshRem, 300);
+ }
+ },
+ false
+ );
+
+ if (doc.readyState === "complete") {
+ doc.body.style.fontSize = 12 * dpr + "px";
+ } else {
+ doc.addEventListener(
+ "DOMContentLoaded",
+ // eslint-disable-next-line no-unused-vars
+ function(e) {
+ doc.body.style.fontSize = 12 * dpr + "px";
+ },
+ false
+ );
+ }
+
+ refreshRem();
+
+ flexible.dpr = win.dpr = dpr;
+ flexible.refreshRem = refreshRem;
+ flexible.rem2px = function(d) {
+ let val = parseFloat(d) * this.rem;
+ if (typeof d === "string" && d.match(/rem$/)) {
+ val += "px";
+ }
+ return val;
+ };
+ flexible.px2rem = function(d) {
+ let val = parseFloat(d) / this.rem;
+ if (typeof d === "string" && d.match(/px$/)) {
+ val += "rem";
+ }
+ return val;
+ };
+})(window, window["lib"] || (window["lib"] = {}));