Commit 52cddbc6 authored by 李纪文's avatar 李纪文

Merge branch 'dev' into 'master'

Dev See merge request !58
parents 9bf86abe 31df5253
Pipeline #65078 failed with stages
in 6 seconds
variables: variables:
DEPLOY_PATH: 'F:/WisdomComponents' DEPLOY_PATH: "F:/WisdomComponents"
stages: stages:
- init - init
...@@ -16,21 +16,22 @@ before_script: ...@@ -16,21 +16,22 @@ before_script:
init: init:
stage: init stage: init
script: script:
- cd /d %DEPLOY_PATH%/src/wisdom-components - 'cd ${DEPLOY_PATH}/src/wisdom-components'
- dir - dir
- git branch
- git pull - git pull
- npm install - npm install --registry=https://g.civnet.cn:4873/
bootstrap: bootstrap:
stage: bootstrap stage: bootstrap
script: script:
- cd /d %DEPLOY_PATH%/src/wisdom-components - 'cd ${DEPLOY_PATH}/src/wisdom-components'
- dir - dir
build: build:
stage: build stage: build
script: script:
- cd /d %DEPLOY_PATH%/src/wisdom-components - 'cd ${DEPLOY_PATH}/src/wisdom-components'
- echo 开始打包... - echo 开始打包...
- npm run site - npm run site
- echo 打包完成 - echo 打包完成
...@@ -38,7 +39,8 @@ build: ...@@ -38,7 +39,8 @@ build:
release: release:
stage: release stage: release
script: script:
- cd /d %DEPLOY_PATH%/src/wisdom-components - 'cd ${DEPLOY_PATH}/src/wisdom-components'
- echo 开始拷贝发布包... - echo 开始拷贝发布包...
- robocopy dist %DEPLOY_PATH%/dist /e || cmd /c "exit /b 0" - 'robocopy "${DEPLOY_PATH}/src/wisdom-components/dist" "${DEPLOY_PATH}/dist" /S ;
IF ((${LASTEXITCODE} -le 8)) {cmd /c "exit /b 0"}'
- echo 发布完成. - echo 发布完成.
...@@ -90,9 +90,12 @@ export default { ...@@ -90,9 +90,12 @@ export default {
'TimeRangePicker', 'TimeRangePicker',
'MqttView', 'MqttView',
'ExportExcel', 'ExportExcel',
'DatePickerCustom',
'LoadBox', 'LoadBox',
'TipTool', 'TipTool',
'RichText',
'DatePickerCustom',
'SelectCustom',
'TreeCustom',
], ],
}, },
{ {
...@@ -119,9 +122,12 @@ export default { ...@@ -119,9 +122,12 @@ export default {
}, },
proxy: { proxy: {
'/api': { '/api': {
target: 'http://192.168.12.71:8080', target: 'http://192.168.10.150:8669',
changeOrigin: true, changeOrigin: true,
pathRewrite: { '^/api': '' }, pathRewrite: { '^/api': '' },
}, },
}, },
define: {
DUMI_TYPE: 'dumi',
},
}; };
...@@ -40,11 +40,11 @@ ...@@ -40,11 +40,11 @@
"@ant-design/pro-skeleton": "^1.0.0-beta.2", "@ant-design/pro-skeleton": "^1.0.0-beta.2",
"@babel/core": "^7.8.3", "@babel/core": "^7.8.3",
"@babel/plugin-proposal-object-rest-spread": "^7.8.3", "@babel/plugin-proposal-object-rest-spread": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.17.10",
"@babel/preset-env": "^7.8.3", "@babel/preset-env": "^7.8.3",
"@babel/preset-react": "^7.8.3", "@babel/preset-react": "^7.8.3",
"@babel/preset-typescript": "^7.8.3", "@babel/preset-typescript": "^7.8.3",
"@babel/runtime": "^7.17.9", "@babel/runtime": "^7.17.9",
"@babel/plugin-transform-runtime": "^7.17.10",
"@octokit/core": "^3.2.5", "@octokit/core": "^3.2.5",
"@size-limit/preset-big-lib": "^4.5.5", "@size-limit/preset-big-lib": "^4.5.5",
"@testing-library/react": "^10.0.2", "@testing-library/react": "^10.0.2",
...@@ -147,17 +147,20 @@ ...@@ -147,17 +147,20 @@
"@wisdom-components/basictable": "^1.5.14", "@wisdom-components/basictable": "^1.5.14",
"@wisdom-components/empty": "^1.3.9", "@wisdom-components/empty": "^1.3.9",
"@wisdom-components/exportexcel": "^1.1.2", "@wisdom-components/exportexcel": "^1.1.2",
"@wisdom-components/loadbox": "1.1.4",
"@wisdom-components/timerangepicker": "^1.3.4", "@wisdom-components/timerangepicker": "^1.3.4",
"@wisdom-utils/utils": "0.0.46", "@wisdom-utils/utils": "0.0.46",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"cross-spawn": "^7.0.3", "cross-spawn": "^7.0.3",
"echarts": "^5.4.0",
"echarts-for-react": "^3.0.2",
"form-render": "^0.9.12", "form-render": "^0.9.12",
"highcharts": "^9.0.1", "highcharts": "^9.0.1",
"highcharts-react-official": "^3.0.0", "highcharts-react-official": "^3.0.0",
"js-export-excel": "^1.1.4", "js-export-excel": "^1.1.4",
"jszip": "^3.5.0", "jszip": "^3.5.0",
"mqtt-client": "^1.0.12", "mqtt-client": "^1.0.12",
"parseForm": "0.0.8", "parseForm": "1.0.0",
"sha1": "^1.1.1" "sha1": "^1.1.1"
}, },
"size-limit": [ "size-limit": [
...@@ -304,6 +307,18 @@ ...@@ -304,6 +307,18 @@
"limit": "2 s", "limit": "2 s",
"webpack": false, "webpack": false,
"running": false "running": false
},
{
"path": "packages/base-components/RichText/lib/**/*.js",
"limit": "2 s",
"webpack": false,
"running": false
},
{
"path": "packages/base-components/RichText/es/**/*.js",
"limit": "2 s",
"webpack": false,
"running": false
} }
], ],
"name": "wisdom-components" "name": "wisdom-components"
......
...@@ -2,6 +2,16 @@ ...@@ -2,6 +2,16 @@
All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [1.4.0](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/basicchart@1.3.5...@wisdom-components/basicchart@1.4.0) (2022-12-01)
### Bug Fixes
- echarts 图表 ([bf6c74b](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/bf6c74b774048f1bc4cddffd4f89d44b7ba2aa7d))
### Features
- 添加基本图表 ([1c02955](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/1c0295546c236d0ac570e75ac1f7213912c9ce4a))
## [1.3.5](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/basicchart@1.3.4...@wisdom-components/basicchart@1.3.5) (2022-06-02) ## [1.3.5](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/basicchart@1.3.4...@wisdom-components/basicchart@1.3.5) (2022-06-02)
### Bug Fixes ### Bug Fixes
......
{ {
"name": "@wisdom-components/basicchart", "name": "@wisdom-components/basicchart",
"version": "1.3.5", "version": "1.4.0",
"description": "> TODO: description", "description": "> TODO: description",
"author": "tuqian <webtuqian@163.com>", "author": "tuqian <webtuqian@163.com>",
"homepage": "", "homepage": "",
......
import React, { useMemo, forwardRef } from 'react';
import ECharts from './ECharts';
import * as echarts from 'echarts/core';
import propTypes from 'prop-types';
import _ from 'lodash';
// 基础柱状图
const isCategory = (category) => category !== undefined;
const isStack = (stack) => stack === undefined || stack === null;
const gradientColors = [
['#1685ff', '#74bcff'],
['#00b809', '#66d46b'],
['#ffa200', '#ffc766'],
['#00c4bd', '#66dccd'],
['#ff6b37', '#ff9773'],
['#986aff', '#c1a6ff'],
].map(
([from, to]) =>
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: from },
{ offset: 1, color: to },
]),
);
const BarChart = forwardRef(({ category, dataSource }, ref) => {
const option = useMemo(() => {
const xAxis = isCategory(category)
? {
type: 'category',
data: category,
}
: {
type: 'time',
};
const hasUnitItem = dataSource.find((item) => item.unit);
const yAxis = !!hasUnitItem ? { name: `(${hasUnitItem.unit})` } : {};
const series = dataSource.map((item, index) => {
const config = _.omit(item, ['type']);
const itemStyle = isStack(config.stack)
? {
color: gradientColors[index % gradientColors.length],
}
: {};
return {
type: 'bar',
...itemStyle,
...config,
};
});
return { xAxis, yAxis, series };
}, [category, dataSource]);
return <ECharts ref={ref} option={option} />;
});
BarChart.PropTypes = {
category: propTypes.array,
dataSource: propTypes.objectOf({
name: propTypes.string,
data: propTypes.array,
unit: propTypes.unit,
}),
};
export default BarChart;
...@@ -7,27 +7,105 @@ group: ...@@ -7,27 +7,105 @@ group:
path: / path: /
--- ---
# BasicChart 标准图表 ## BasicChart 标准图表
基础组件 基础组件
- 支持的图表类型有直线图、曲线图等 20 种图表,其中很多图表可以集成在同一个图形中形成混合图 - 支持的图表类型有直线图、曲线图等 20 种图表,其中很多图表可以集成在同一个图形中形成混合图
## 何时使用 tooltip 规范
- 当需要展现图表时; - 头部显示数据名\类目名
- 内容部分显示各系列数据信息:系列色、系列名称、系列值、系列单位
- 头部和内容通过分割线隔开
- 缺省的数据系列不显示在内容部分上
- 数值颜色跟随系列色
## 代码演示 xAxis 规范
### 常规使用 - 显示轴线、刻度线、文字标签,不显示网格线
- 轴线、刻度线、文字标签色彩样式一致
- 刻度线方向向内
- <font color="red">类目类型图表中,两边是否采用留白?</font>
<code src="./demos/Basic.tsx"> yAxis 规范
## API - 不显示轴线、刻度线、文字标签,显示网格线
- 网格线使用虚线`dashed`类型
- 坐标轴名称显示在顶部,和坐标轴对齐
api 参考 highcharts 库 https://api.highcharts.com.cn/highcharts axisPointer 规范
- 类目类型图表中,指示器采用阴影`shadow`类型
- 非类目类型图标中,指示器采用`line`类型,line 为虚线,在图形上方,标记下方
### 基本柱状图
`BasicChart.BarChart`拥有默认配置的柱状图,适用于仅包含柱状图的使用场景。
#### 类目类型柱状图
<code src="./demos/BaseBar.tsx">
#### 时间类型柱状图
<code src="./demos/TimeTypeBar.tsx">
#### 堆叠柱状图
<code src="./demos/StackBar.tsx">
### 基本折线图
`BasicChart.LineChart`拥有默认配置的折线图,适用于仅包含折线图的使用场景。
#### 类目类型折线图
<code src="./demos/BaseLine.tsx">
#### 面积图
<code src="./demos/AreaLine.tsx">
#### 时间类型折线图
<code src="./demos/TimeTypeLine.tsx">
### 自定义图表
`BasicChart`通用 echarts 图表,通过`option`传递配置项。 <code src="./demos/Basic.tsx">
### 获取 echarts 实例对象
通过传递`ref`可以获取到创建出来的 echarts 实例对象。 `BasicChart``BasicChart.BarChart``BasicChart.LineChart`都支持。 <code src="./demos/ChartInstance.tsx">
### API
#### BasicChart
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
| --------- | -------------------------- | ------ | ------ | ------ |
| className | 图表容器类名 | string | - | - |
| option | echarts 图表配置项`option` | object | - | - |
`option` 参考 echarts 库 https://echarts.apache.org/zh/index.html
#### BasicChart.BarChart(基本柱状图)
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
| --- | --- | --- | --- | --- | --- |
| className | 图表容器类名 | string | - | - |
| category | x 轴类目配置,有该配置则为`category`类型图表,否则为`time`类型的图表 | Array[string | number] | - | - |
| dataSource | 图表容器类名 | object | - | - |
dataSource | 参数 | 说明 | 类型 | 默认值 | 可选值 | | --- | --- | --- | --- | --- | | name | 数据系列名称,有 name 时才会显示图例 | string | - | - | | unit | 数据单位,显示在`tooltip``yAxis`上 | string | - | - | | data | 图表数据,`category`类型和 `time`类型有所区别,<font color="#008dff">详见案例</font> | Array[] | - | - |
#### BasicChart.LineChart(基本折线图)
| 参数 | 说明 | 类型 | 默认值 | 可选值 | | 参数 | 说明 | 类型 | 默认值 | 可选值 |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| constructorType | 标题 | string | chart | - 'chart' 用于 Highcharts 图表 <br/> - 'stockChart' 用于 Highstock 图表 <br/> - 'mapChart' 用于 Highmaps 图表 <br/> - 'ganttChart' 用于甘特图 | | className | 图表容器类名 | string | - | - |
| chartOptions`必需` | Highcharts 图表配置对象 | object | { } | - | | category | x 轴类目配置,有该配置则为`category`类型图表,否则为`time`类型的图表 | Array[string | number] | - | - |
| dataSource | 图表容器类名 | object | - | - |
dataSource | 参数 | 说明 | 类型 | 默认值 | 可选值 | | --- | --- | --- | --- | --- | | name | 数据系列名称,有 name 时才会显示图例 | string | - | - | | smooth | 平滑曲线模式 | boolean | true | - | | lienType | 折线图/面积图显示 | string | `line` | `line``area` | | unit | 数据单位,显示在`tooltip``yAxis`上 | string | - | - | | data | 图表数据,`category`类型和 `time`类型有所区别,<font color="#008dff">详见案例</font> | Array[] | - | - |
import React, { useMemo } from 'react';
import { ConfigProvider } from 'antd';
import classNames from 'classnames';
import ReactEcharts from 'echarts-for-react';
import { omit } from 'lodash';
import buildOption from './utils';
const ECharts = React.forwardRef((props, ref) => {
const { getPrefixCls } = React.useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('basic-chart');
const chartProps = omit(props, ['className', 'option']);
const option = useMemo(() => {
return buildOption(props.option);
}, [props.option]);
// const chartProps = pick(props, ['option', 'notMerge', 'lazyUpdate', 'style', 'className', 'theme', 'onChartReady', 'loadingOption', 'showLoading', 'onEvents', 'opts']);
return (
<ReactEcharts
ref={ref}
className={classNames(prefixCls, props.className)}
option={option}
{...chartProps}
/>
);
});
export default ECharts;
import React, { forwardRef, useMemo } from 'react';
import ECharts from './ECharts';
import propTypes from 'prop-types';
import _ from 'lodash';
// 基础柱状图
const isCategory = (category) => category !== undefined;
const isArea = (lineType) => lineType === 'area';
const LineChart = forwardRef(({ category, lineType, smooth, dataSource }, ref) => {
const option = useMemo(() => {
const xAxis = isCategory(category)
? {
type: 'category',
data: category,
}
: {
type: 'time',
};
const hasUnitItem = dataSource.find((item) => item.unit);
const yAxis = !!hasUnitItem ? { name: `(${hasUnitItem.unit})` } : {};
const series = dataSource.map((item, index) => {
const config = _.omit(item, ['type']);
const itemStyle = isArea(lineType)
? {
areaStyle: {},
}
: {};
return {
type: 'line',
smooth,
...itemStyle,
...config,
};
});
return { xAxis, yAxis, series };
}, [category, smooth, lineType, dataSource]);
return <ECharts ref={ref} option={option} />;
});
LineChart.PropTypes = {
smooth: propTypes.boolean,
lineType: propTypes.oneOf(['line', 'area']),
category: propTypes.array,
dataSource: propTypes.objectOf({
name: propTypes.string,
data: propTypes.array,
unit: propTypes.unit,
}),
};
LineChart.defaultProps = {
smooth: true,
lineType: 'line',
};
export default LineChart;
import React from 'react';
import { BasicChart } from '../index';
const { LineChart } = BasicChart;
export default () => {
const category = ['11-01', '11-02', '11-03', '11-04', '11-05', '11-06', '11-07'];
const dataSource = [
{
name: '用水量',
unit: 'm³',
data: [120, 200, 150, 80, 70, 110, 130],
},
{
name: '供水量',
unit: 'm³',
data: [1120, 1200, 1150, 1180, 1170, 1110, 1130],
},
];
return <LineChart lineType="area" category={category} dataSource={dataSource} />;
};
import React from 'react';
import { BasicChart } from '../index';
const { BarChart } = BasicChart;
export default () => {
const category = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
const dataSource = [
{
name: '用水量',
unit: 'm³',
data: [120, 200, 150, 80, 70, 110, 130],
},
{
name: '供水量',
unit: 'm³',
data: [120, 200, 150, 80, 70, 110, 130],
},
];
return <BarChart category={category} dataSource={dataSource} />;
};
import React from 'react';
import { BasicChart } from '../index';
const { LineChart } = BasicChart;
export default () => {
const category = ['11-01', '11-02', '11-03', '11-04', '11-05', '11-06', '11-07'];
const dataSource = [
{
name: '用水量',
unit: 'm³',
data: [120, 200, 150, 80, 70, 110, 130],
},
{
name: '供水量',
unit: 'm³',
data: [1120, 1200, 1150, 1180, 1170, 1110, 1130],
},
];
return <LineChart smooth={false} category={category} dataSource={dataSource} />;
};
import React from 'react';
import ECharts from '../ECharts';
const Demo = () => {
const option = {
title: {
text: 'Referer of a Website',
subtext: 'Fake Data',
left: 'center',
},
tooltip: {
trigger: 'item',
},
// xAxis: {
// data: [],
// },
legend: {
orient: 'vertical',
left: 'left',
},
series: [
{
name: 'Access From',
type: 'pie',
radius: '50%',
data: [
{ value: 1048, name: 'Search Engine' },
{ value: 735, name: 'Direct' },
{ value: 580, name: 'Email' },
{ value: 484, name: 'Union Ads' },
{ value: 300, name: 'Video Ads' },
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)',
},
},
},
],
};
return <ECharts option={option} />;
};
export default Demo;
import React from 'react'; import React from 'react';
import BasicChart from '../index'; import { BasicChart } from '../index';
const Demo = () => { const Demo = () => {
return ( const colors = ['#5470C6', '#91CC75', '#EE6666'];
<div> const option = {
<h3>折线图</h3> color: colors,
<div style={{ height: '600px' }}> tooltip: {
<BasicChart chartOptions={chartOptions1} /> trigger: 'axis',
</div> axisPointer: {
<h3 style={{ marginTop: '40px' }}>曲线面积图</h3> type: 'cross',
<div style={{ height: '600px' }}> },
<BasicChart chartOptions={chartOptions2} /> },
</div> grid: {
<h3 style={{ marginTop: '40px' }}>带滚动条曲线图</h3> right: '20%',
<div style={{ height: '600px' }}> },
<BasicChart chartOptions={chartOptions3} constructorType={'stockChart'} /> toolbox: {
</div> feature: {
</div> dataView: { show: true, readOnly: false },
); restore: { show: true },
}; saveAsImage: { show: true },
},
export default Demo; },
legend: {
const chartOptions1 = { data: ['Evaporation', 'Precipitation', 'Temperature'],
// ... },
series: [ xAxis: [
{ {
name: '今日供水量', type: 'category',
color: '#1884EC', axisTick: {
data: [ alignWithLabel: true,
[1620720173000, 122], },
[1620720473000, 122], // prettier-ignore
[1620720773000, 122], data: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
[1620721073000, 123],
[1620721373000, 123],
[1620721673000, 123],
[1620721973000, 124],
[1620722274000, 124],
[1620722724000, 125],
[1620723024000, 125],
[1620723324000, 125],
],
}, },
], ],
}; yAxis: [
const chartOptions2 = {
// ...
series: [
{ {
type: 'areaspline', type: 'value',
name: '出水瞬时流量', name: 'Evaporation',
color: '#68cbd1', position: 'right',
data: [ alignTicks: true,
[1620720173000, 1.85], axisLine: {
[1620720473000, 8.22], show: true,
[1620720773000, 2.83], lineStyle: {
[1620721073000, 2.62], color: colors[0],
[1620721373000, 2.05],
[1620721673000, 8.7],
[1620721973000, 2.38],
[1620722274000, 3.31],
[1620722724000, 2.36],
[1620723024000, 2.98],
[1620723324000, 2.58],
],
marker: {
enabled: false,
}, },
}, },
], axisLabel: {
plotOptions: { formatter: '{value} ml',
areaspline: { },
fillOpacity: 0.5, },
{
type: 'value',
name: 'Precipitation',
position: 'right',
alignTicks: true,
offset: 80,
axisLine: {
show: true,
lineStyle: {
color: colors[1],
},
},
axisLabel: {
formatter: '{value} ml',
}, },
}, },
};
const chartOptions3 = {
// ...
series: [
{ {
type: 'spline', type: 'value',
name: '进水压力', name: '温度',
color: '#1884EC', position: 'left',
data: [ alignTicks: true,
[1620720173000, 0.08], axisLine: {
[1620720473000, 0.09], show: true,
[1620720773000, 0.09], lineStyle: {
[1620721073000, 0.09], color: colors[2],
[1620721373000, 0.09], },
[1620721673000, 0.08], },
[1620721973000, 0.09], axisLabel: {
[1620722274000, 0.09], formatter: '{value} °C',
[1620722724000, 0.09], },
[1620723024000, 0.08], },
[1620723324000, 0.08],
], ],
series: [
{
name: 'Evaporation',
type: 'bar',
data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3],
},
{
name: 'Precipitation',
type: 'bar',
yAxisIndex: 1,
data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3],
},
{
name: 'Temperature',
type: 'line',
yAxisIndex: 2,
data: [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2],
}, },
], ],
};
return <BasicChart option={option} />;
}; };
export default Demo;
import React from 'react';
import { useEffect } from 'react';
import { useRef } from 'react';
import { BasicChart } from '../index';
const Demo = () => {
const ref = useRef();
const option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: {
type: 'value',
},
series: [
{
data: [150, 230, 224, 218, 135, 147, 260],
type: 'line',
},
],
};
useEffect(() => {
console.log(ref.current);
}, []);
return <BasicChart ref={ref} option={option} />;
};
export default Demo;
import React from 'react';
import { BasicChart } from '../index';
const { BarChart } = BasicChart;
export default () => {
const category = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
const dataSource = [
{
name: '小区-A栋',
unit: 'm³',
data: [120, 200, 150, 80, 70, 110, 130],
stack: '分组A',
},
{
name: '小区-B栋',
unit: 'm³',
data: [120, 200, 150, 80, 70, 110, 130],
stack: '分组A',
},
{
name: '商区',
unit: 'm³',
data: [1120, 1200, 1150, 180, 170, 1110, 1130],
stack: '分组B',
},
];
return <BarChart category={category} dataSource={dataSource} />;
};
import React from 'react';
import { BasicChart } from '../index';
const { BarChart } = BasicChart;
// 数据格式: [[时间戳, value]]
const getData = () => {
let base = +new Date(2000, 9, 3);
let oneDay = 24 * 3600 * 1000;
let data = [[base, Math.random() * 300]];
for (let i = 1; i < 20; i++) {
let now = new Date((base += oneDay));
data.push([+now, Math.round(Math.random() * 20 + data[i - 1][1])]);
}
return data;
};
export default () => {
const dataSource = [
{
name: '用水量',
unit: 'm³',
data: getData(),
},
];
return <BarChart dataSource={dataSource} />;
};
import React from 'react';
import { BasicChart } from '../index';
const { LineChart } = BasicChart;
// 数据格式: [[时间戳, value]]
const getData = () => {
let base = +new Date(2000, 9, 3);
let oneDay = 24 * 3600 * 1000;
let data = [[base, Math.random() * 300]];
for (let i = 1; i < 20; i++) {
let now = new Date((base += oneDay));
data.push([+now, Math.round(Math.random() * 20 + data[i - 1][1])]);
}
return data;
};
export default () => {
const dataSource = [
{
name: '用水量',
unit: 'm³',
data: getData(),
},
];
return <LineChart lineType="area" dataSource={dataSource} />;
};
import React, { useContext, useEffect, useRef, useState } from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import Highcharts from 'highcharts/highstock';
import HighchartsReact from 'highcharts-react-official';
import { ConfigProvider } from 'antd';
import './index.less';
let chartWidth = 0; // chart width
let chartHeight = 0; // chart height
const BasicChart = (props) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('basic-chart');
const { chartOptions, constructorType } = props;
const [options, setOptions] = useState(defaultOptions);
const container = useRef(null);
// 处理图表options
const handleChartOptions = () => {
const options = {
...defaultOptions,
...chartOptions,
};
if (container.current) {
if (container.current.offsetWidth !== 0) {
chartWidth = container.current.offsetWidth;
chartHeight = container.current.offsetHeight;
}
Highcharts.setOptions({
// 处理 chart 高度坍塌
chart: {
width: container.current.offsetWidth === 0 ? chartWidth : container.current.offsetWidth,
height:
container.current.offsetHeight === 0 ? chartHeight : container.current.offsetHeight,
},
});
}
Highcharts.setOptions({
global: { timezoneOffset: -8 * 60 },
});
return options;
};
useEffect(() => {
setOptions({ ...handleChartOptions() });
}, [chartOptions]);
return (
<div className={classNames(prefixCls)} ref={container}>
<HighchartsReact
immutable={true}
highcharts={Highcharts}
constructorType={constructorType}
options={options}
{...props}
/>
</div>
);
};
BasicChart.defaultProps = {
constructorType: 'chart',
chartOptions: {},
};
BasicChart.propTypes = {
columns: PropTypes.string,
chartOptions: PropTypes.object,
};
export default BasicChart;
const defaultOptions = {
chart: {
zoomType: 'x',
backgroundColor: 'rgba(255, 255, 255, 0.5)',
},
title: null,
credits: false,
rangeSelector: {
enabled: false,
},
xAxis: [
{
lineWidth: 0,
crosshair: true,
type: 'datetime',
dateTimeLabelFormats: {
second: '%H:%M:%S',
minute: '%H:%M',
hour: '%H:%M',
day: '%d',
week: '%d',
month: '%d',
year: '%Y',
},
},
],
yAxis: [
{
title: null,
opposite: false, // 即坐标轴会显示在对立面
lineWidth: 1,
},
],
tooltip: {
shared: true,
split: false,
valueDecimals: 3,
dateTimeLabelFormats: {
second: '%H:%M:%S',
minute: '%H:%M',
hour: '%H:%M',
day: '%d',
week: '%d',
month: '%d',
year: '%Y',
},
},
plotOptions: {
series: {
showInNavigator: true,
connectNulls: false,
zoneAxis: 'x',
},
},
legend: {
verticalAlign: 'top',
},
series: [],
};
import React, { useContext, useEffect, useRef, useState } from 'react'; import * as echarts from 'echarts/core';
import classNames from 'classnames'; import Echarts from './ECharts';
import PropTypes from 'prop-types'; import BarChart from './BarChart';
import Highcharts from 'highcharts/highstock'; import LineChart from './LineChart';
import HighchartsReact from 'highcharts-react-official';
import { ConfigProvider } from 'antd';
import './index.less';
let chartWidth = 0; // chart width const BasicChart = Echarts;
let chartHeight = 0; // chart height
const BasicChart = (props) => { BasicChart.BarChart = BarChart;
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); BasicChart.LineChart = LineChart;
const prefixCls = getPrefixCls('basic-chart');
const { chartOptions, constructorType } = props; export { BasicChart, echarts };
const [options, setOptions] = useState(defaultOptions);
const container = useRef(null);
// 处理图表options
const handleChartOptions = () => {
const options = {
...defaultOptions,
...chartOptions,
};
if (container.current) {
if (container.current.offsetWidth !== 0) {
chartWidth = container.current.offsetWidth;
chartHeight = container.current.offsetHeight;
}
Highcharts.setOptions({
// 处理 chart 高度坍塌
chart: {
width: container.current.offsetWidth === 0 ? chartWidth : container.current.offsetWidth,
height:
container.current.offsetHeight === 0 ? chartHeight : container.current.offsetHeight,
},
});
}
Highcharts.setOptions({
global: { timezoneOffset: -8 * 60 },
});
return options;
};
useEffect(() => {
setOptions({ ...handleChartOptions() });
}, [chartOptions]);
return (
<div className={classNames(prefixCls)} ref={container}>
<HighchartsReact
immutable={true}
highcharts={Highcharts}
constructorType={constructorType}
options={options}
{...props}
/>
</div>
);
};
BasicChart.defaultProps = {
constructorType: 'chart',
chartOptions: {},
};
BasicChart.propTypes = {
columns: PropTypes.string,
chartOptions: PropTypes.object,
};
export default BasicChart;
const defaultOptions = {
chart: {
zoomType: 'x',
backgroundColor: 'rgba(255, 255, 255, 0.5)',
},
title: null,
credits: false,
rangeSelector: {
enabled: false,
},
xAxis: [
{
lineWidth: 0,
crosshair: true,
type: 'datetime',
dateTimeLabelFormats: {
second: '%H:%M:%S',
minute: '%H:%M',
hour: '%H:%M',
day: '%d',
week: '%d',
month: '%d',
year: '%Y',
},
},
],
yAxis: [
{
title: null,
opposite: false, // 即坐标轴会显示在对立面
lineWidth: 1,
},
],
tooltip: {
shared: true,
split: false,
valueDecimals: 3,
dateTimeLabelFormats: {
second: '%H:%M:%S',
minute: '%H:%M',
hour: '%H:%M',
day: '%d',
week: '%d',
month: '%d',
year: '%Y',
},
},
plotOptions: {
series: {
showInNavigator: true,
connectNulls: false,
zoneAxis: 'x',
},
},
legend: {
verticalAlign: 'top',
},
series: [],
};
import _ from 'lodash';
// 坐标轴图表类型
export const AXIS_CHART_TYPES = ['line', 'bar', 'scatter', 'effectScatter'];
/**
* 推断图表类型是否为坐标轴类图表
*
* @param {Object} option 图表配置项
* @returns Boolean: true坐标轴类图表, false 非坐标轴类图表
*/
export const isAxisChart = (option) => {
const { series: origin } = option;
const series = Array.isArray(origin) ? origin : _.isObject(origin) ? [origin] : [];
return !series.some((item) => AXIS_CHART_TYPES.indexOf(item.type) === -1);
};
export const isLineType = (series) => series.type === 'line';
export const isBarType = (series) => series.type === 'bar';
import _ from 'lodash';
import * as echarts from 'echarts/core';
/**
* 16进制颜色值转rgba颜色值
*
* @param {string} hex 16进制颜色值
* @param {number} opacity 透明度,缺省默认为1
* @returns Rgba颜色值
*/
export const hexToRgba = (hex, opacity = 1) => {
let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return `rgba(${parseInt(result[1], 16)},${parseInt(result[2], 16)},${parseInt(
result[3],
16,
)}, ${opacity})`;
};
// 图表基础配色
export const DEF_COLORS = [
'#1685ff',
'#00b809',
'#ffa200',
'#00d0c7',
'#ff6b37',
'#986aff',
'#2f54eb',
'#ff9e69',
'#ffcb66',
'#99ceff',
];
// 图表基础配色对应的线性渐变色, 适用面积曲线图
export const DEF_GRAD_COLORS = DEF_COLORS.map((color) => {
return new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: hexToRgba(color, 0.2),
},
{
offset: 1,
color: hexToRgba(color, 0.02),
},
]);
});
/**
* 根据系列的序列下标获取对应的颜色
*
* @param {number} index 系列所在的下标
* @param {Array} colors 配色方案
* @returns 颜色值,可以是16进制, rgb, LinearGradient
*/
export const colorOfSeries = (index, colors = DEF_COLORS) => {
return colors[index % colors.length];
};
import _ from 'lodash';
import { DEF_COLORS, DEF_GRAD_COLORS, colorOfSeries } from './color';
import { isAxisChart, isLineType } from './chart';
import { buildDefaultTooltip } from './tooltip';
// 默认标题配置
export const deafultTitle = { show: false };
export const defaultGrid = {
right: 40,
left: 60,
};
export const defaultLegend = {
show: true,
right: 40,
icon: 'react',
itemWidth: 14,
itemHeight: 8,
itemGap: 20,
textStyle: {
padding: [0, 0, 0, 4],
color: '#2d2d2d',
},
};
export const defaultDataZoom = [
{
type: 'inside',
},
];
// 直角坐标系图表x轴默认配置(非直角坐标系图表不能有xAxis配置,会报错)
export const buildDefaultXAxis = (axis) => {
const cfg = {
show: true,
axisLine: {
show: true,
lineStyle: {
color: '#e2e2e2',
},
},
axisTick: {
show: true,
inside: true,
lineStyle: {
color: '#e2e2e2',
},
},
axisLabel: {
show: true,
color: '#5b5b5b',
hideOverlap: true,
},
splitLine: {
show: false,
lineStyle: {
color: '#e2e2e2',
},
},
};
if (axis.type === 'time') {
cfg.axisLabel.formatter = {
year: '{yyyy}',
month: '{MM}月',
day: '{MM}-{dd}',
hour: '{HH}:{mm}',
minute: '{HH}:{mm}',
second: '{HH}:{mm}:{ss}',
millisecond: '{hh}:{mm}:{ss} {SSS}',
none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss} {SSS}',
};
}
return cfg;
};
export const defaultXAxis = {
show: true,
axisLine: {
show: true,
lineStyle: {
color: '#e2e2e2',
},
},
axisTick: {
show: true,
inside: true,
lineStyle: {
color: '#e2e2e2',
},
},
axisLabel: {
show: true,
color: '#5b5b5b',
hideOverlap: true,
},
splitLine: {
show: false,
lineStyle: {
color: '#e2e2e2',
},
},
};
export const defaultYAxis = {
show: true,
alignTicks: true,
nameGap: 25,
nameTextStyle: {
align: 'right',
padding: 0,
color: '#8e8e8e',
},
axisLine: {
show: false,
lineStyle: {
color: '#e2e2e2',
},
},
axisTick: {
show: false,
inside: true,
lineStyle: {
color: '#e2e2e2',
},
},
axisLabel: {
show: true,
color: '#8e8e8e',
},
splitLine: {
show: true,
lineStyle: {
color: '#e2e2e2',
type: 'dashed',
},
},
};
export const buildAxisPointer = (option) => {
if (!option || !option.xAxis) return null;
const { xAxis: x } = option;
const xAxis = Array.isArray(x) ? x : _.isObject(x) ? [x] : [];
const type = xAxis.some((item) => item.type === 'category') ? 'shadow' : 'line';
const typeConfig =
type === 'line'
? {
lineStyle: {
type: 'solid',
color: 'rgba(22,133,255,0.3)',
},
}
: {};
return {
z: 3,
type,
...typeConfig,
};
};
// 折线图: 圆形标记点
// 曲线图: 不加标记点
// 折线面积图: 圆形标记点、面积渐变色配置
// 曲线面积图: 不加标记点、面积渐变色配置
const seriesItem = (series, index) => {
const cfg = {};
if (isLineType(series)) {
// cfg.symbol = 'ciecle';
cfg.symbolSize = 4;
cfg.showSymbol = !series.smooth;
cfg.areaStyle = series.areaStyle && {
opacity: 1,
color: colorOfSeries(index, DEF_GRAD_COLORS),
};
}
return _.merge(cfg, series);
};
export const buildDefaultSeries = (option) => {
const { series } = option;
const serieArr = Array.isArray(series) ? series : !!series ? [series] : [];
const defaultSeries = serieArr.map(seriesItem);
return Array.isArray(series) ? defaultSeries : !!series ? defaultSeries[0] : null;
};
export const buildDefaultOption = (option) => {
const exports = {};
exports.color = DEF_COLORS;
exports.title = deafultTitle;
(option.dataZoom == undefined || option.dataZoom === null) &&
(exports.dataZoom = defaultDataZoom);
exports.tooltip = buildDefaultTooltip(option);
return exports;
};
export const buildSpecificOption = (option) => {
const { xAxis, yAxis, grid, legend } = option;
// 直角坐标系类图标
if (isAxisChart(option)) {
return _.merge(
{},
{
xAxis: Array.isArray(xAxis)
? xAxis.map((item) => ({ ...buildDefaultXAxis(item) }))
: buildDefaultXAxis(xAxis),
yAxis: Array.isArray(yAxis) ? yAxis.map(() => ({ ...defaultYAxis })) : defaultYAxis,
grid: Array.isArray(grid) ? grid.map(() => ({ ...defaultGrid })) : defaultGrid,
legend: Array.isArray(legend) ? legend.map(() => ({ ...defaultLegend })) : defaultLegend,
series: buildDefaultSeries(option),
tooltip: {
axisPointer: buildAxisPointer(option),
},
},
);
}
};
import _ from 'lodash';
import { buildDefaultOption, buildSpecificOption } from './default';
import * as color from './color';
const buildOption = (option) => {
const exports = {};
const defaultOption = buildDefaultOption(option);
const specificOption = buildSpecificOption(option);
return _.merge(exports, defaultOption, specificOption, option);
};
export { buildOption, color };
export default buildOption;
import _ from 'lodash';
const isArray = (arr) => Array.isArray(arr);
/**
* 转换echarts线性渐变方向 成 css渐变角度 css线性渐变方向为从上往下时为0deg。(0: 上 -> 下)。
* 根据echarts渐变方向计算出角度,以水平方向为基准顺时针旋转的角度。(0: 左 -> 右) 所以需要多旋转90度,转为css角度。
*
* @param {any} x1 Echarts.graphic.LinearGradient.x
* @param {any} y1 Echarts.graphic.LinearGradient.y
* @param {any} x2 Echarts.graphic.LinearGradient.x2
* @param {any} y2 Echarts.graphic.LinearGradient.y2
* @returns Deg角度
*/
const toCssAngle = (x1, y1, x2, y2) => {
const deltaX = x2 - x1;
const deltaY = y2 - y1;
return Math.atan2(deltaY, deltaX) * (180 / Math.PI) + 90;
};
/**
* 获取系列真实值
*
* @param {Object} param Formatter 单个数据集
* @returns 系列真实值
*/
const valueAccessor = (param) => {
// 数据可能通过series配置,也可能通过dataset配置。
const { value, encode, dimensionNames } = param;
if (isArray(value)) {
return value[encode.y[0]];
} else if (_.isObject(value)) {
return value[dimensionNames[encode.y[0]]];
} else {
return value;
}
};
/**
* 获取系列单位
*
* @param {Object} option 图表配置项
* @param {Object} param Formatter 单个数据集
* @returns 系列单位
*/
const unitAccessor = (option, param) => {
const { yAxis, series } = option;
const { seriesIndex } = param;
// 规范 yAxis 和 series 都为数组, 方便通过下标访问
const axisArr = isArray(yAxis) ? yAxis : !!yAxis ? [yAxis] : [];
const serieArr = isArray(series) ? series : !!series ? [series] : [];
const serie = serieArr[seriesIndex];
// 构造单位
let unit = '';
if (serie && serie.showUnit !== false) {
unit =
serie.unit !== null && serie.unit !== undefined
? serie.unit
: _.get(axisArr, [_.get(serie, 'yAxisIndex', 0), 'name'], ''); // 根据serie去yAxis配置找name属性当做单位
}
return unit;
};
/**
* 获取可渐变背景颜色值
*
* @param {Object} param Formatter 单个数据集
* @returns 系列背景颜色
*/
const bgcolorAccessor = (param) => {
if (!param || !param.color) return null;
const { color } = param;
if (color.type === 'linear') {
const { x, y, x2, y2, colorStops } = color;
const angle = toCssAngle(x, y, x2, y2);
const hint = colorStops.map((item) => {
return `${item.color} ${item.offset * 100}%`;
});
return `linear-gradient(${angle}deg, ${hint.join(',')})`;
} else if (color.type === 'radial') {
const { x, y, r, colorStops } = color;
const hint = colorStops.map((item) => {
return `${item.color} ${item.offset * 100}%`;
});
return `radial-gradient(circle farthest-side at ${x} ${y}, ${hint.join(',')})`;
} else {
return color;
}
};
/**
* 获取文字颜色值
*
* @param {Object} param Formatter 单个数据集
* @returns 系列文字颜色
*/
const colorAccessor = (param) => {
if (!param || !param.color) return null;
const { color } = param;
if (color.type === 'linear' || color.type === 'radial') {
const { colorStops } = color;
return colorStops[0].color;
} else {
return color;
}
};
// const xlabelAccessor = (option, param) => {
// const { xAxis, series } = option;
// const { name, seriesIndex, axisValueLabel } = param;
// const axisArr = isArray(xAxis) ? xAxis : !!xAxis ? [xAxis] : [];
// const serieArr = isArray(series) ? series : !!series ? [series] : [];
// const serie = serieArr[seriesIndex];
// const type = _.get(axisArr, [_.get(serie, 'xAxisIndex', 0), 'type'], 'category');
// // const formatter = _.get(axisArr, [_.get(serie, 'xAxisIndex', 0), 'axisLabel', 'formatter'], '{yyyy}-{MM}-{dd}');
// if (type === 'time') {
// return axisValueLabel
// } else {
// return name;
// }
// };
/**
* Tooltip头部样式内容
*
* @param {Object} param Formatter 单个数据集
* @returns
*/
const headTemplate = (option, param) => {
if (!param) return '';
const { name, axisValueLabel } = param;
return `<div style="border-bottom: 1px solid #F0F0F0; color: #808080; margin-bottom: 5px; padding-bottom: 5px;">${
name || axisValueLabel
}</div>`;
};
/**
* Tooltip每个系列样式内容
*
* @param {Object} option 图表配置项
* @param {Object} param Formatter 单个数据集
* @returns
*/
const seriesTemplate = (option, param) => {
if (!param) return '';
const value = valueAccessor(param);
const unit = unitAccessor(option, param);
const bgcolor = bgcolorAccessor(param);
const color = colorAccessor(param);
if (value === void 0 || value === null) return '';
return `
<div>
<span style="display:inline-block;margin: 0 7px 2px 0;border-radius:5px;width:5px;height:5px;background:${bgcolor}"></span>
<span>${param.seriesName}</span><span style="display:inline-block;">:</span><span style="color:${color};margin-left:10px">${value}</span>
<span>${unit}</span>
</div>
`;
};
// 默认tooltip配置
export const buildDefaultTooltip = (option) => {
const cfg = {
show: true,
padding: [5, 10],
trigger: 'axis', // 一般柱状图/曲线图都用axis,饼图/散点图等无类目的用item
triggerOn: 'mousemove|click',
renderMode: 'html',
confine: true, // *是否限制在图表区域内
appendToBody: false, // *不挂到body标签下,挂载到图表容器节点
formatter: (params) => {
let tooltipHeader = '',
tooltipContent = '';
if (isArray(params)) {
tooltipHeader = headTemplate(option, params[0]);
params.forEach((param) => {
tooltipContent += seriesTemplate(option, param);
});
} else {
tooltipHeader = headTemplate(option, params);
tooltipContent += seriesTemplate(option, params);
}
return `
<div>
${tooltipHeader}
<div>${tooltipContent}</div>
</div>
`;
},
};
return cfg;
};
...@@ -2,6 +2,42 @@ ...@@ -2,6 +2,42 @@
All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.5.25](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/basictable@1.5.24...@wisdom-components/basictable@1.5.25) (2022-07-13)
### Bug Fixes
- 修改表格 ([cc6cace](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/cc6cace17e5e6b47a17ffffc8b18082142eba274))
## [1.5.24](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/basictable@1.5.23...@wisdom-components/basictable@1.5.24) (2022-07-13)
### Bug Fixes
- 修改表格 ([8442f8c](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/8442f8ca4a674db74ef69afb4b5211977318ff1e))
## [1.5.23](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/basictable@1.5.22...@wisdom-components/basictable@1.5.23) (2022-07-13)
### Bug Fixes
- 修改表格 ([e4bf2fc](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/e4bf2fc5a51a612aba8a7fae294d4b60ed64edbe))
## [1.5.22](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/basictable@1.5.21...@wisdom-components/basictable@1.5.22) (2022-07-08)
### Bug Fixes
- 表格组件样式修改 ([7bb20e8](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/7bb20e8a134670ff0187714292b63fd3369c8cd8))
## [1.5.21](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/basictable@1.5.20...@wisdom-components/basictable@1.5.21) (2022-07-08)
### Bug Fixes
- 表格组件样式修改 ([7f27780](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/7f277806ecf04f3d568e06c9eb26b0c9fe4fcd5b))
## [1.5.20](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/basictable@1.5.19...@wisdom-components/basictable@1.5.20) (2022-07-08)
### Bug Fixes
- 表格组件样式修改 ([baf1597](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/baf15977aa99fa06fe1d52af50448a53973400cc))
## [1.5.19](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/basictable@1.5.18...@wisdom-components/basictable@1.5.19) (2022-06-02) ## [1.5.19](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/basictable@1.5.18...@wisdom-components/basictable@1.5.19) (2022-06-02)
### Bug Fixes ### Bug Fixes
......
{ {
"name": "@wisdom-components/basictable", "name": "@wisdom-components/basictable",
"version": "1.5.19", "version": "1.5.25",
"description": "> TODO: description", "description": "> TODO: description",
"author": "tuqian <webtuqian@163.com>", "author": "tuqian <webtuqian@163.com>",
"homepage": "", "homepage": "",
......
...@@ -13,6 +13,7 @@ const BasicTable = (props) => { ...@@ -13,6 +13,7 @@ const BasicTable = (props) => {
total / (props.pagination ? props.pagination.pageSize || 10 : 10), total / (props.pagination ? props.pagination.pageSize || 10 : 10),
)} 页 / 共 ${total} 条记录`; )} 页 / 共 ${total} 条记录`;
}; };
return ( return (
<Table <Table
className={classNames(prefixCls)} className={classNames(prefixCls)}
......
...@@ -28,7 +28,11 @@ ...@@ -28,7 +28,11 @@
.@{ant-prefix}-table-thead > tr > th { .@{ant-prefix}-table-thead > tr > th {
font-weight: 600; font-weight: 600;
background: white; background: white;
border-bottom: 2px solid #dbe7fb; border-bottom: 1px solid #dbe7fb !important;
}
.@{ant-prefix}-table-body {
border-top: 1px solid #dbe7fb;
} }
.@{ant-prefix}-table-thead > tr > th .@{ant-prefix}-table-column-sorters { .@{ant-prefix}-table-thead > tr > th .@{ant-prefix}-table-column-sorters {
...@@ -163,6 +167,10 @@ ...@@ -163,6 +167,10 @@
border-left: 1px solid #dbe7fb; border-left: 1px solid #dbe7fb;
} }
.@{ant-prefix}-table.@{ant-prefix}-table-bordered .@{ant-prefix}-table-header {
border-right: 1px solid #dbe7fb;
}
.@{ant-prefix}-table-cell-scrollbar { .@{ant-prefix}-table-cell-scrollbar {
border-left: 0px; border-left: 0px;
box-shadow: none; box-shadow: none;
......
...@@ -2,6 +2,31 @@ ...@@ -2,6 +2,31 @@
All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.1.10](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/datepickercustom@1.1.9...@wisdom-components/datepickercustom@1.1.10) (2022-11-30)
### Bug Fixes
- 修改 ([88eb730](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/88eb730c9e4c3f560d170d22ef5731da341288fd))
## [1.1.9](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/datepickercustom@1.1.8...@wisdom-components/datepickercustom@1.1.9) (2022-11-30)
### Bug Fixes
- 增加组件 ([36db543](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/36db54378a9ae4bad1fda184af57a2d46c71867b))
## [1.1.8](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/datepickercustom@1.1.6...@wisdom-components/datepickercustom@1.1.8) (2022-11-23)
### Bug Fixes
- 修改 ([aa52f31](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/aa52f3107232b839b233de6ebf050c10ecae06c2))
- 修改组态查看组件 ([66c76de](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/66c76dee8e0a2528b7f5eec4da94e7397e023706))
## [1.1.7](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/datepickercustom@1.1.6...@wisdom-components/datepickercustom@1.1.7) (2022-11-23)
### Bug Fixes
- 修改组态查看组件 ([66c76de](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/66c76dee8e0a2528b7f5eec4da94e7397e023706))
## [1.1.6](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/datepickercustom@1.1.5...@wisdom-components/datepickercustom@1.1.6) (2022-05-05) ## [1.1.6](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/datepickercustom@1.1.5...@wisdom-components/datepickercustom@1.1.6) (2022-05-05)
### Bug Fixes ### Bug Fixes
......
{ {
"name": "@wisdom-components/datepickercustom", "name": "@wisdom-components/datepickercustom",
"version": "1.1.6", "version": "1.1.10",
"description": "> TODO: description", "description": "> TODO: description",
"author": "lijiwen <961370825@qq.com>", "author": "lijiwen <961370825@qq.com>",
"homepage": "", "homepage": "",
......
--- ---
title: DatePicker - 时间选择器 title: DatePickerCustom - 时间选择器
nav: nav:
title: 基础组件 title: 基础组件
path: /components path: /components
...@@ -11,6 +11,18 @@ group: ...@@ -11,6 +11,18 @@ group:
## 代码演示 ## 代码演示
### 时间选择器 - 时间
<code src="./demos/base1.tsx">
## API
api 参考 Antd DatePicker 组件 https://ant.design/components/date-picker-cn/#API
## 代码演示
### 时间选择器 - 日期
<code src="./demos/base.tsx"> <code src="./demos/base.tsx">
## API ## API
...@@ -20,3 +32,13 @@ api 参考 Antd DatePicker 组件 https://ant.design/components/date-picker-cn/# ...@@ -20,3 +32,13 @@ api 参考 Antd DatePicker 组件 https://ant.design/components/date-picker-cn/#
| 参数 | 说明 | 类型 | 默认值 | | 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- | | --- | --- | --- | --- |
| onChange | 改变选择的时间,重写 antd 方法,返回起始时间对象 | function(date, dateString){ } | -- | | onChange | 改变选择的时间,重写 antd 方法,返回起始时间对象 | function(date, dateString){ } | -- |
## 代码演示
### 时间选择器 - 范围
<code src="./demos/base2.tsx">
## API
api 参考 Antd DatePicker 组件 https://ant.design/components/date-picker-cn/#API
...@@ -2,7 +2,7 @@ import React, { useContext, useEffect, useState } from 'react'; ...@@ -2,7 +2,7 @@ import React, { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { Input } from 'antd'; import { Input } from 'antd';
import DatePickerCustom from '../index'; import DatePickerCustom, { TimePickerCustom, RangePickerCustom } from '../index';
const Demo = (props) => { const Demo = (props) => {
const [startTime, setStartTime] = useState(''); const [startTime, setStartTime] = useState('');
...@@ -14,11 +14,32 @@ const Demo = (props) => { ...@@ -14,11 +14,32 @@ const Demo = (props) => {
}; };
return ( return (
<> <>
<DatePickerCustom onChange={onChange} picker="date" style={{ marginRight: '10px' }} /> <DatePickerCustom
<DatePickerCustom onChange={onChange} picker="week" style={{ marginRight: '10px' }} /> onChange={onChange}
<DatePickerCustom onChange={onChange} picker="month" style={{ marginRight: '10px' }} /> picker="date"
<DatePickerCustom onChange={onChange} picker="year" style={{ marginRight: '10px' }} /> style={{ marginRight: '10px', marginBottom: '10px' }}
<div style={{ display: 'flex', marginTop: '10px' }}> />
<DatePickerCustom
onChange={onChange}
picker="week"
style={{ marginRight: '10px', marginBottom: '10px' }}
/>
<DatePickerCustom
onChange={onChange}
picker="month"
style={{ marginRight: '10px', marginBottom: '10px' }}
/>
<DatePickerCustom
onChange={onChange}
picker="quarter"
style={{ marginRight: '10px', marginBottom: '10px' }}
/>
<DatePickerCustom
onChange={onChange}
picker="year"
style={{ marginRight: '10px', marginBottom: '10px' }}
/>
<div style={{ display: 'flex' }}>
<Input <Input
value={startTime} value={startTime}
placeholder="起始时间" placeholder="起始时间"
......
import React, { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Input } from 'antd';
import DatePickerCustom, { TimePickerCustom, RangePickerCustom } from '../index';
const Demo1 = (props) => {
return (
<>
<TimePickerCustom style={{ marginRight: '10px', marginBottom: '10px' }} />
</>
);
};
export default Demo1;
import React, { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Input } from 'antd';
import DatePickerCustom, { TimePickerCustom, RangePickerCustom } from '../index';
const Demo = (props) => {
return (
<>
<RangePickerCustom style={{ marginRight: '10px', marginBottom: '10px' }} />
</>
);
};
export default Demo;
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
import React from 'react'; import React, { useContext } from 'react';
import moment from 'moment'; import moment from 'moment';
// eslint-disable-next-line no-unused-vars import classNames from 'classnames';
import { DatePicker } from 'antd'; import { DatePicker, ConfigProvider, TimePicker } from 'antd';
import './index.less';
const { RangePicker } = DatePicker;
const FORMATS = { const FORMATS = {
day: 'YYYY-MM-DD', day: 'YYYY-MM-DD',
week: 'YYYY-wo', week: 'YYYY-wo',
month: 'YYYY-MM', month: 'YYYY-MM',
quarter: 'YYYY-第Q季度',
year: 'YYYY', year: 'YYYY',
}; };
const STANTFORMAT = 'YYYY-MM-DD 00:00:00'; const STANTFORMAT = 'YYYY-MM-DD 00:00:00';
const ENDFORMAT = 'YYYY-MM-DD 23:59:59'; const ENDFORMAT = 'YYYY-MM-DD 23:59:59';
const DatePickerCustom = (props) => { const DatePickerCustom = (props) => {
const { getPrefixCls } = useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls('datepicker-custom');
// eslint-disable-next-line no-nested-ternary
const modes = props.picker ? (props.picker !== 'date' ? props.picker : 'day') : 'day'; const modes = props.picker ? (props.picker !== 'date' ? props.picker : 'day') : 'day';
const selectedDate = props.value ? props.value : new Date(); const selectedDate = props.value ? props.value : new Date();
const onChange = (date, dateString) => { const onChange = (date, dateString) => {
...@@ -31,6 +38,10 @@ const DatePickerCustom = (props) => { ...@@ -31,6 +38,10 @@ const DatePickerCustom = (props) => {
startTime = moment(dateTime).startOf(modes); startTime = moment(dateTime).startOf(modes);
endTime = moment(dateTime).endOf(modes); endTime = moment(dateTime).endOf(modes);
break; break;
case 'quarter':
startTime = moment(dateTime).startOf(modes);
endTime = moment(dateTime).endOf(modes);
break;
case 'year': case 'year':
startTime = moment(dateTime).startOf(modes); startTime = moment(dateTime).startOf(modes);
endTime = moment(dateTime).endOf(modes); endTime = moment(dateTime).endOf(modes);
...@@ -50,8 +61,10 @@ const DatePickerCustom = (props) => { ...@@ -50,8 +61,10 @@ const DatePickerCustom = (props) => {
switch (modes) { switch (modes) {
case 'day': case 'day':
name = value.format(FORMATS[modes]); name = value.format(FORMATS[modes]);
// eslint-disable-next-line no-use-before-define
if (name === getTime(0, 'days', FORMATS[modes])) { if (name === getTime(0, 'days', FORMATS[modes])) {
name = '今天'; name = '今天';
// eslint-disable-next-line no-use-before-define
} else if (name === getTime(1, 'days', FORMATS[modes])) { } else if (name === getTime(1, 'days', FORMATS[modes])) {
name = '昨天'; name = '昨天';
} }
...@@ -62,22 +75,37 @@ const DatePickerCustom = (props) => { ...@@ -62,22 +75,37 @@ const DatePickerCustom = (props) => {
// eslint-disable-next-line no-use-before-define // eslint-disable-next-line no-use-before-define
if (value.format('YYYY-wo') === getTime(0, 'week', FORMATS[modes])) { if (value.format('YYYY-wo') === getTime(0, 'week', FORMATS[modes])) {
name = '本周'; name = '本周';
// eslint-disable-next-line no-use-before-define
} else if (value.format('YYYY-wo') === getTime(1, 'week', FORMATS[modes])) { } else if (value.format('YYYY-wo') === getTime(1, 'week', FORMATS[modes])) {
name = '上周'; name = '上周';
} }
break; break;
case 'month': case 'month':
name = value.format(FORMATS[modes]); name = value.format(FORMATS[modes]);
// eslint-disable-next-line no-use-before-define
if (name === getTime(0, 'month', FORMATS[modes])) { if (name === getTime(0, 'month', FORMATS[modes])) {
name = '本月'; name = '本月';
// eslint-disable-next-line no-use-before-define
} else if (name === getTime(1, 'month', FORMATS[modes])) { } else if (name === getTime(1, 'month', FORMATS[modes])) {
name = '上月'; name = '上月';
} }
break; break;
case 'quarter':
name = value.format(FORMATS[modes]);
// eslint-disable-next-line no-use-before-define
if (name === getTime(0, 'month', FORMATS[modes])) {
name = '本季度';
// eslint-disable-next-line no-use-before-define
} else if (name === getTime(3, 'month', FORMATS[modes])) {
name = '上季度';
}
break;
case 'year': case 'year':
name = value.format(FORMATS[modes]); name = value.format(FORMATS[modes]);
// eslint-disable-next-line no-use-before-define
if (name === getTime(0, 'year', FORMATS[modes])) { if (name === getTime(0, 'year', FORMATS[modes])) {
name = '今年'; name = '今年';
// eslint-disable-next-line no-use-before-define
} else if (name === getTime(1, 'year', FORMATS[modes])) { } else if (name === getTime(1, 'year', FORMATS[modes])) {
name = '去年'; name = '去年';
} }
...@@ -91,25 +119,28 @@ const DatePickerCustom = (props) => { ...@@ -91,25 +119,28 @@ const DatePickerCustom = (props) => {
return moment(new Date()).subtract(num, type).format(format); return moment(new Date()).subtract(num, type).format(format);
}; };
const getMonthWeek = (value) => { const getMonthWeek = (value) => {
const a = value.format('YYYY'), const a = value.format('YYYY');
b = value.format('MM'), const b = value.format('MM');
c = value.format('DD'); const c = value.format('DD');
let date = new Date(a, parseInt(b) - 1, c), // eslint-disable-next-line radix
w = date.getDay(), const date = new Date(a, parseInt(b) - 1, c);
d = date.getDate(); let w = date.getDay();
if (w == 0) { const d = date.getDate();
if (w === 0) {
w = 7; w = 7;
} }
let config = { const config = {
getMonth: moment(date).format('MM'), getMonth: moment(date).format('MM'),
getYear: date.getFullYear(), getYear: date.getFullYear(),
getWeek: Math.ceil((d + 6 - w) / 7), getWeek: Math.ceil((d + 6 - w) / 7),
}; };
return '第' + config.getWeek + '周(' + config.getYear + '/' + config.getMonth + ')'; return `第${config.getWeek}周(${config.getYear}/${config.getMonth})`;
}; };
return ( return (
<DatePicker <DatePicker
{...props} {...props}
className={modes === 'quarter' ? classNames(`${prefixCls}-quarter-Box`) : ''}
dropdownClassName={modes === 'quarter' ? classNames(`${prefixCls}-quarter`) : ''}
defaultValue={selectedDate ? moment(selectedDate) : ''} defaultValue={selectedDate ? moment(selectedDate) : ''}
format={customFormat} format={customFormat}
onChange={onChange} onChange={onChange}
...@@ -117,4 +148,13 @@ const DatePickerCustom = (props) => { ...@@ -117,4 +148,13 @@ const DatePickerCustom = (props) => {
); );
}; };
const TimePickerCustom = (props) => {
return <TimePicker {...props} />;
};
const RangePickerCustom = (props) => {
return <RangePicker {...props} />;
};
export { TimePickerCustom, RangePickerCustom };
export default DatePickerCustom; export default DatePickerCustom;
@root-entry-name: 'default';
@import '~antd/es/style/themes/index.less';
@datepicker-custom-prefix-cls: ~'@{ant-prefix}-datepicker-custom';
.@{datepicker-custom-prefix-cls}-quarter-box {
width: 230px;
}
.@{datepicker-custom-prefix-cls}-quarter {
// :global {
.ant-picker-year-panel,
.ant-picker-quarter-panel {
width: 230px;
}
// 修改选中的年份、季度背景颜⾊
.ant-picker-cell-selected {
.ant-picker-cell-inner {
background: #1890ff;
}
}
// 使⽤CSS改变季度选择器的内容
.ant-picker-quarter-panel {
.ant-picker-content {
// 使季度选择器可以换⾏成两排
tr {
display: flex;
flex-wrap: wrap;
}
// 控制按钮外层宽度,使器溢出换⾏
td {
display: flex;
align-items: center;
justify-content: center;
width: 50%;
height: 50px;
padding: 20px;
}
}
// 使before伪元素和按钮背景颜⾊⼀致
.ant-picker-cell-selected {
&::before {
color: #fff;
background: #1890ff;
}
}
// 控制伪元素所占宽度
.ant-picker-cell {
&::before {
right: auto;
left: auto;
display: flex;
align-items: center;
justify-content: center;
width: 60%;
}
}
// 隐藏季度选择器的按钮,⽤伪元素代替
.ant-picker-cell-inner {
display: none;
}
// 根据title更换相应伪元素的content,使其代替原本的按钮
.ant-picker-cell[title$='-Q1'] {
&::before {
content: '第一季度';
}
}
.ant-picker-cell[title$='-Q2'] {
&::before {
content: '第二季度';
}
}
.ant-picker-cell[title$='-Q3'] {
&::before {
content: '第三季度';
}
}
.ant-picker-cell[title$='-Q4'] {
&::before {
content: '第四季度';
}
}
}
// }
}
...@@ -9,7 +9,7 @@ group: ...@@ -9,7 +9,7 @@ group:
# PandaExportExcel Excel 表格导出 # PandaExportExcel Excel 表格导出
<code src="./demos/Base.tsx"> <code src="./demos/base.tsx">
## API ## API
......
...@@ -2,6 +2,21 @@ ...@@ -2,6 +2,21 @@
All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.5](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/parseform@1.3.3...parseform@1.3.5) (2022-11-23)
### Bug Fixes
- 修改 ([aa52f31](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/aa52f3107232b839b233de6ebf050c10ecae06c2))
- 修改 ([9820334](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/98203342467b500426828f3f71ebf5ed4f055a2e))
- 修改组态查看组件 ([66c76de](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/66c76dee8e0a2528b7f5eec4da94e7397e023706))
## [1.3.4](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/parseform@1.3.3...parseform@1.3.4) (2022-11-23)
### Bug Fixes
- 修改 ([9820334](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/98203342467b500426828f3f71ebf5ed4f055a2e))
- 修改组态查看组件 ([66c76de](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/66c76dee8e0a2528b7f5eec4da94e7397e023706))
## [1.3.3](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/parseform@1.3.2...parseform@1.3.3) (2022-05-05) ## [1.3.3](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/parseform@1.3.2...parseform@1.3.3) (2022-05-05)
### Bug Fixes ### Bug Fixes
......
{ {
"name": "parseform", "name": "parseform",
"version": "1.3.3", "version": "1.3.5",
"description": "> TODO: description", "description": "> TODO: description",
"author": "lijiwen <961370825@qq.com>", "author": "lijiwen <961370825@qq.com>",
"homepage": "", "homepage": "",
...@@ -26,6 +26,6 @@ ...@@ -26,6 +26,6 @@
"dependencies": { "dependencies": {
"@babel/runtime": "^7.17.9", "@babel/runtime": "^7.17.9",
"form-render": "^0.9.12", "form-render": "^0.9.12",
"parseForm": "^0.0.8" "parseForm": "1.0.0"
} }
} }
...@@ -2,6 +2,19 @@ ...@@ -2,6 +2,19 @@
All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [1.3.9](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/realtimeinfo@1.3.7...@wisdom-components/realtimeinfo@1.3.9) (2022-11-23)
### Bug Fixes
- 修改 ([aa52f31](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/aa52f3107232b839b233de6ebf050c10ecae06c2))
- 修改 ([9820334](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/98203342467b500426828f3f71ebf5ed4f055a2e))
## [1.3.8](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/realtimeinfo@1.3.7...@wisdom-components/realtimeinfo@1.3.8) (2022-11-23)
### Bug Fixes
- 修改 ([9820334](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/98203342467b500426828f3f71ebf5ed4f055a2e))
## [1.3.7](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/realtimeinfo@1.3.6...@wisdom-components/realtimeinfo@1.3.7) (2022-06-02) ## [1.3.7](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/realtimeinfo@1.3.6...@wisdom-components/realtimeinfo@1.3.7) (2022-06-02)
### Bug Fixes ### Bug Fixes
......
{ {
"name": "@wisdom-components/realtimeinfo", "name": "@wisdom-components/realtimeinfo",
"version": "1.3.7", "version": "1.3.9",
"description": "> TODO: description", "description": "> TODO: description",
"author": "tuqian <webtuqian@163.com>", "author": "tuqian <webtuqian@163.com>",
"homepage": "", "homepage": "",
......
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import Empty from '@wisdom-components/Empty'; import Empty from '@wisdom-components/empty';
import RealTimeInfo from '../index'; import RealTimeInfo from '../index';
import request from 'umi-request'; import request from 'umi-request';
......
# Change Log
All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [0.2.6](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/richtext@0.2.5...@wisdom-components/richtext@0.2.6) (2022-06-27)
### Bug Fixes
- 修改 ([0f126c9](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/0f126c905fd979137f3594750d43f3fbe247254e))
## [0.2.5](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/richtext@0.2.4...@wisdom-components/richtext@0.2.5) (2022-06-27)
### Bug Fixes
- 修改 ([0350c1b](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/0350c1b40923045128bdcae5a2ccfb4d80e5ccd8))
## [0.2.4](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/richtext@0.2.3...@wisdom-components/richtext@0.2.4) (2022-06-27)
### Bug Fixes
- 修改 ([5e77ceb](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/5e77ceb9ab1ebebbc73df480767660be32f3bb19))
## [0.2.3](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/richtext@0.2.2...@wisdom-components/richtext@0.2.3) (2022-06-27)
### Bug Fixes
- 修改 ([9f98780](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/9f9878043356dc7dac2f7617c7c3614fe1d42d8f))
## [0.2.2](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/richtext@0.2.1...@wisdom-components/richtext@0.2.2) (2022-06-27)
### Bug Fixes
- 修改 ([3649ea4](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/3649ea488384ae1df0a5f58f7c6a92b7f67d069a))
## [0.2.1](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/compare/@wisdom-components/richtext@0.2.0...@wisdom-components/richtext@0.2.1) (2022-06-27)
### Bug Fixes
- test ([19831b1](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/19831b16fdbf189dc660e9204af6db9fe4c54402))
# 0.2.0 (2022-06-27)
### Features
- 富文本打包修改 ([0bfd44f](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/0bfd44f62677219f03d6ec641e512a372f3968c2))
- 富文本组件 ([75cd6b7](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/75cd6b786dc5b163e38625c3c7b1ef25efc6d7d2))
# 0.1.0 (2022-06-27)
### Features
- 富文本组件 ([75cd6b7](https://g.civnet.cn:8443/ReactWeb5/wisdom-components/commits/75cd6b786dc5b163e38625c3c7b1ef25efc6d7d2))
# `@wisdom-components/richtext`
> TODO: description
## Usage
```
const RichText = require('@wisdom-components/richtext');
// TODO: DEMONSTRATE API
```
{
"name": "@wisdom-components/richtext",
"version": "0.2.6",
"description": "> TODO: description",
"author": "hongmye <1014185119@qq.com>",
"homepage": "",
"license": "ISC",
"sideEffects": [
"*.less"
],
"module": "es/index.js",
"main": "lib/index.js",
"files": [
"lib",
"es",
"dist"
],
"directories": {
"lib": "lib",
"es": "es",
"dist": "dist",
"test": "__tests__"
},
"publishConfig": {
"registry": "https://g.civnet.cn:4873/"
},
"repository": {
"type": "git",
"url": "https://g.civnet.cn:8443/ReactWeb5/wisdom-components.git"
},
"scripts": {
"test": "echo \"Error: run tests from root\" && exit 1"
},
"dependencies": {
"@babel/runtime": "^7.17.9",
"classnames": "^2.2.6"
}
}
---
title: RichText - 富文本编辑器
nav:
title: 基础组件
path: /components
group:
path: /
---
# RichText 富文本编辑器
## 代码演示
### 常规使用
<code src="./demos/demo.jsx">
### 合计
<!-- <code src="./demos/Summary.tsx"> -->
## API
api 参考 Antd Table 组件 https://www.wangeditor.com/v4/
/*
* @Title:富文本展示,可预览图片
* @Author: hongmye
* @Date: 2022-03-21 14:44:49
*/
/**
* 1.引入组件 import RichTextShow from '@/components/RichText/RichTextShow';
* 示例:<RichTextShow content={this.state.content} onClickImg={src => {}} />;
*
* 2.传递方法 onClickImg 点击图片回调(不需可不传)
*
* 3.传值接收 content 富文本内容
* fileList 附件列表
*
*
*/
import { Image } from 'antd';
import { useEffect, useState } from 'react';
import FileListItem from './fileListItem';
import styles from './index.less';
function RichTextShow(props) {
const [imgVisible, setImgVisible] = useState(false);
const [imgPreviewSrc, setImgPreviewSrc] = useState('');
const [fileList, setFileList] = useState([]);
const onPreview = (e) => {
e.stopPropagation();
const src = e?.target?.src || null;
if (!src) return;
setImgPreviewSrc(src);
setImgVisible(true);
props.onClickImg && props.onClickImg(src, e.target);
};
useEffect(() => {
setFileList(props.fileList);
}, [props.fileList]);
useEffect(() => {}, [props.content]);
return (
<div style={{ ...props.style }}>
<div
className={styles.RichTextShow}
onClick={onPreview}
dangerouslySetInnerHTML={{ __html: props.content || '' }}
/>
{fileList && fileList.length > 0 && (
<div className={styles.RichTextFileList}>
<FileListItem
list={fileList}
onDel={(val) => {
onDelFile(val);
}}
onPreview={(val) => {
if (!val) return;
setImgPreviewSrc(val.path);
setImgVisible(true);
}}
/>
</div>
)}
<Image
width={200}
style={{ display: 'none' }}
src={imgPreviewSrc}
preview={{
visible: imgVisible,
src: imgPreviewSrc,
onVisibleChange: (value) => {
setImgVisible(value);
if (!value) setImgPreviewSrc('');
},
}}
/>
</div>
);
}
export default RichTextShow;
/*
* @Title:
* @Author: hongmye
* @Date: 2022-06-23 16:03:16
*/
// @ts-ignore
import Empty from '@wisdom-components/empty';
import { useEffect, useState } from 'react';
// import BasicTable from '../index';
import request from 'umi-request';
const Demo = () => {
const [columns, setColumns] = useState([]);
const [dataSource, setDataSource] = useState([]);
useEffect(() => {
fetchData();
}, []);
const fetchData = (params = {}) => {
request(`${baseUrl}/AcrossTable/GetEquipmentDataReport`, {
method: 'get',
params: {},
}).then(function (response) {
const data = response.data;
let column = data.map((item, index) => {
return {
title: `${item.DName + item.DType}(${item.Unit})`,
dataIndex: `name${index}`,
key: `name${index}`,
};
});
column.unshift({
title: '时间',
dataIndex: 'time',
key: 'time',
});
let dataSource = data[0].NameDate.map((item, index) => ({ key: index, time: item.Time }));
data.forEach((item, index) => {
item.NameDate.forEach((child) => {
dataSource.forEach((v) => {
if (child.Time === v.time) v[`name${index}`] = child.Value;
});
});
});
setColumns(column);
setDataSource(dataSource);
});
};
// @ts-ignore
return (
<div style={{ height: '800px' }}>
{/* {!!dataSource.length && (
<BasicTable
dataSource={dataSource}
columns={columns}
bordered={false}
pagination={{ pageSize: 20, size: 'default' }}
/>
)} */}
{!dataSource.length && <Empty description={'暂无数据'} />}
</div>
);
};
export default Demo;
const baseUrl = 'https://www.fastmock.site/mock/162c15dca15c4dba9ba51e0a0b76929b/api';
/*
* @Title: 富文本编辑器demo
* @Author: hongmye
* @Date: 2022-03-07 14:44:32
*/
import React from 'react';
import { Button } from 'antd';
import RichText from '../index';
import RichTextShow from '../RichTextShow';
// import { projectManageService } from '@/api';
import styles from './demo.less';
class RichTextDemo extends React.Component {
constructor(props) {
super(props);
this.myRichText = React.createRef();
this.state = {
personList: [
{ userId: 568, userName: '徐乐' },
{ userId: 569, userName: '余苏苏' },
{ userId: 572, userName: '周宏民' },
],
content: '',
fileList: [],
};
}
getData = async () => {
// const res = await projectManageService.GetWorkHourUserList({ projectId: 19 });
// this.setState({
// // personList: res.data || [],
// });
// const arr = [
// {
// name: '工时管理_工时日报 (1).xlsx',
// type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
// size: 8192,
// path:
// '/PandaWorkFlow/WorkFlow/AccountManage/DownloadFiles?filePath=b0422fdb-6c63-4b34-8021-b54102236bcb/工时管理_工时日报/(1).xlsx',
// },
// {
// name: '浊度.png',
// type: 'image/png',
// size: 6789,
// path:
// '/PandaWorkFlow/WorkFlow/AccountManage/DownloadFiles?filePath=fd00ce06-52c0-410a-bd30-8aed9131a616/浊度.png',
// },
// ];
// // this.setState({ fileList: arr });
// this.myRichText.current && this.myRichText.current.setHtml('');
};
componentDidMount = () => {
this.getData();
};
componentDidUpdate = (propNev, stateNev) => { };
componentWillUnmount() {
this.setState = () => { };
}
render() {
return (
<div className={styles.RichTextDemo}>
<div className={styles.RichTextDemoContainer}>
<RichText
// content={this.state.content}
personList={this.state.personList}
onChange={val => {
this.setState({ content: val });
}}
onChangeFile={arr => {
this.setState({ fileList: arr });
}}
fileList={this.state.fileList}
projectId={19}
ref={this.myRichText}
/>
</div>
{/* <div className={styles.contentBox}>{this.state.content}</div> */}
<div className={styles.contentBox}>
<RichTextShow content={this.state.content} onClickImg={src => { }} fileList={this.state.fileList} />
</div>
<div className={styles.contentBox}>{this.state.content}</div>
</div>
);
}
}
export default RichTextDemo;
.RichTextDemoContainer {
// height: 400px;
// padding: 0px 100px;
background-color: #fff;
}
.contentBox {
// height: 400px;
margin-top: 10px;
padding: 20px;
background-color: #fff;
}
.RichTextDemo {
height: 100%;
overflow-y: scroll;
}
\ No newline at end of file
/*
* @Title:
* @Author: hongmye
* @Date: 2022-03-21 14:44:49
*/
import React, { useState, useEffect, useRef, useImperativeHandle, forwardRef } from 'react';
import { FileTwoTone, DeleteOutlined, FileImageTwoTone, DownloadOutlined, PictureOutlined } from '@ant-design/icons';
import { Button } from 'antd';
import iconFile from './icon_file.png';
function fileListItem(props) {
const [fileList, setFileList] = useState([]);
const imgType = ['image/png', 'image/jpg', 'image/jpeg'];
const onPreview = item => {
props.onPreview(item);
};
const onDownLoad = item => {
const a = document.createElement('a');
a.setAttribute('download', item.name);
a.setAttribute('href', item.path);
document.documentElement.appendChild(a);
a.target = '_black';
a.click();
};
useEffect(() => {
setFileList(props.list || []);
}, [props.list]);
return (
<>
{fileList.map((item, index) => {
return (
<div key={index} className={'panda-civ-work-upload-list panda-civ-work-upload-list-picture'}>
<div className={'panda-civ-work-upload-list-picture-container'}>
<div className={'panda-civ-work-upload-list-item'}>
<div className={'panda-civ-work-upload-list-item-info'}>
<span className={'panda-civ-work-upload-span'}>
<div
className={
'panda-civ-work-upload-list-item-thumbnail panda-civ-work-upload-list-item-file'
}
>
{/* {imgType.includes(item.type) ? <FileImageTwoTone /> : <FileTwoTone />} */}
<img src={iconFile} />
</div>
<span
className={'panda-civ-work-upload-list-item-name'}
title={item.name}
style={{ cursor: 'pointer' }}
>
{item.name}
</span>
<span className={'panda-civ-work-upload-list-item-card-actions picture'}>
{imgType.includes(item.type) && (
<Button
title="预览"
type="text"
onClick={e => {
e && e.stopPropagation();
onPreview(item);
}}
style={{ padding: '4px 8px' }}
>
<PictureOutlined />
</Button>
)}
<Button
title="下载"
type="text"
onClick={e => {
e && e.stopPropagation();
onDownLoad(item);
}}
style={{ padding: '4px 8px' }}
>
<DownloadOutlined />
</Button>
{props.type === 'edit' && (
<Button
title="删除文件"
type="text"
onClick={e => {
e && e.stopPropagation();
props.onDel(item);
}}
style={{ padding: '4px 8px' }}
>
<DeleteOutlined />
</Button>
)}
</span>
</span>
</div>
</div>
</div>
</div>
);
})}
</>
);
}
export default fileListItem;
This diff is collapsed.
@import '~antd/es/style/themes/default.less';
// @import '~antd/es/image/style/index.less';
.RichText {
width: 100%;
height: auto;
min-height: 200px;
position: relative;
display: flex;
flex-direction: column;
border: 1px solid #d9d9d9;
border-radius: 2px;
.loadingWrap {
width: 100%;
height: 100%;
position: absolute;
display: flex;
align-items: center;
justify-content: center;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0.8);
}
.selectBox {
position: absolute;
top: 0;
left: 0;
background: #fff;
max-height: 250px;
overflow-y: scroll;
display: none;
}
.selectList{
border: 1px solid #efefef;
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.16), 0 0;
}
.selectList .selectItem:hover {
background: #1685FF;
color: #fff;
cursor: pointer;
}
.selectList .selectActiveItem {
background: #1685FF;
color: #fff;
}
.selectItem {
padding: 5px 10px;
}
ol li {
list-style: decimal !important;
}
ul li {
list-style: disc !important;
}
}
.RichTextFileList {
padding: 20px;
:global {
.@{ant-prefix}-upload-list-item {
height: 44px;
padding: 8px 16px;
.@{ant-prefix}-upload-list-item-thumbnail,
.@{ant-prefix}-upload-list-item-file {
width: 20px;
height: 22px;
>img {
width: 100%;
height: 100%;
}
}
.@{ant-prefix}-upload-list-item-name {
line-height: normal;
}
}
}
}
.RichTextContainer {
background-color: #fff;
color: #000000d9;
position: relative;
overflow-y: scroll;
flex: 1;
pre {
white-space: pre-wrap;
word-wrap: break-word;
}
}
.RichTextToolbar {
border-bottom: 1px solid #d9d9d9;
// height: 0;
// overflow: hidden;
}
.RichTextShow img {
cursor: pointer;
}
.RichTextShow span[data-type='person'] {
font-weight: bold;
color: #44acb6 !important;
}
:global {
#RichTextContainer span[data-type='person'] {
font-weight: bold;
color: #44acb6 !important;
}
.w-e-menu[data-title="图片"] {
display: none;
}
.RichText-image {
position: relative;
display: inline-block;
}
#RichTextContainer .RichText-image-img {
max-width: calc(100% - 20px);
display: inline-block;
width: auto;
height: auto;
}
.RichText-image-mask {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
background: rgba(0, 0, 0, 0.5);
cursor: pointer;
opacity: 0;
transition: opacity 0.3s;
padding: 0;
margin: 0;
box-sizing: border-box;
}
.RichText-image-mask-info {
padding: 0;
margin: 0;
box-sizing: border-box;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
cursor: pointer;
color: #fff;
font-size: 20px;
}
.RichText-image-mask-info .anticon {
margin-inline-end: 4px;
}
.anticon svg {
display: inline-block;
}
.RichText-image-mask:hover {
opacity: 1;
}
.r-t-add-file {
color: #999;
font-family: 'w-e-icon' !important;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
padding: 0;
margin: 0;
box-sizing: border-box;
}
.r-t-add-file:before {
content: "\e9cb";
}
.@{ant-prefix}-image-error {
display: block;
}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment