diff --git a/docs/api/layer/layer.zh.md b/docs/api/layer/layer.zh.md index 4b2af44899..78ca4aa56d 100644 --- a/docs/api/layer/layer.zh.md +++ b/docs/api/layer/layer.zh.md @@ -532,6 +532,18 @@ layer.select(false); layer.setSelect(id); ``` +### getLegendItems + +获取图例配置 + +#### 参数 + +- name 获取的图例类型 `color|size` + +```ts +layer.getLegendItems('color'); +``` + ## 鼠标事件 鼠标事件回调参数 target diff --git a/gatsby-config.js b/gatsby-config.js index 218ec551ba..0ec9d6b854 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -39,6 +39,66 @@ module.exports = { } } ], + ecosystems: [ + { + name: { + zh: 'L7 React组件', + en: 'L7React L7 For React', + }, + url: 'http://antv.vision/L7-react/', + }, + { + name: { + zh: 'L7 地理围栏绘制组件库', + en: 'L7Draw', + }, + url: 'http://antv.vision/L7-draw/', + }, + { + name: { + zh: 'L7 行政区划可视化库', + en: 'L7Boundary', + }, + url: 'http://antv.vision/L7-boundary/', + }, + { + name: { + zh: '地理可视分开发框架', + en: 'Dipper', + }, + url: 'http://antv.vision/Dipper', + }, + ], + Dipper: [ + { + name: { + zh: 'L7 React组件', + en: 'L7React L7 For React', + }, + url: 'http://antv.vision/L7-react/', + }, + { + name: { + zh: 'L7Draw 地理围栏绘制组件库', + en: 'L7Draw', + }, + url: 'http://antv.vision/L7-draw/', + }, + { + name: { + zh: 'L7Plot', + en: 'L7Plot', + }, + url: 'http://antv.vision/L7-draw/', + }, + { + name: { + zh: 'L7Boundary 行政区划可视化库', + en: 'L7Boundary', + }, + url: 'http://antv.vision/L7-boundary/', + }, + ], docs: [ { slug: 'api/l7', diff --git a/package.json b/package.json index 0990165218..25a997cf09 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,10 @@ "url": "https://github.com/antvis/L7" }, "devDependencies": { - "@antv/dipper": "^0.0.5", - "@antv/dipper-widgets": "^0.0.5", + "@antv/dipper": "0.0.6", + "@antv/dipper-widgets": "0.0.6", "@antv/g2": "^3.5.9", + "@antv/g2plot": "^2.3.40", "@antv/gatsby-theme-antv": "^1.1.1", "@antv/l7-district": "^2.3.9", "@antv/l7-draw": "^2.3.40", @@ -89,6 +90,7 @@ "jest-styled-components": "^6.2.1", "lerna": "^3.16.4", "lint-staged": "^9.2.4", + "mockjs": "^1.1.0", "npm-run-all": "^4.1.5", "popmotion": "^9.4.2", "postcss": "^7.0.18", diff --git a/site/components/Dipper/index.tsx b/site/components/Dipper/index.tsx new file mode 100644 index 0000000000..9496845a91 --- /dev/null +++ b/site/components/Dipper/index.tsx @@ -0,0 +1,36 @@ +// eslint-disable-next-line no-unused-vars +import React from 'react'; +import '../../css/dipper.css'; + +interface DipperProps { + dipper: { + title: string; + image: string; + link: string + }[] +} + +export function Dipper(props: DipperProps) { + const { dipper } = props; + + const jumoDemo = (url: string) => { + window.open(url, '_blank'); + }; + + return ( +
+
Dipper 地理分析应用开发框架
+
Dipper 是基于 L7 地理分析应用开发框架,用于快速构建和开发地理分析应用。用户通过组件化、模块化低代码的方式配置地图分析、指挥类应用。
+
+ {dipper.map(item => { + return ( +
+ + {item.title} +
+ ); + })} +
+
+ ); +} diff --git a/site/components/DipperMap/index.tsx b/site/components/DipperMap/index.tsx new file mode 100644 index 0000000000..6ca385247c --- /dev/null +++ b/site/components/DipperMap/index.tsx @@ -0,0 +1,43 @@ +// eslint-disable-next-line no-unused-vars +import { Carousel } from 'antd'; +import React from 'react'; +import '../../css/dippermap.css'; + +interface DipperMapProps { + dippermap: { + desc: string; + img: string; + alt: string + }[] +} + +export function DipperMap(props: DipperMapProps) { + const { dippermap } = props; + + const jumpDipperMap = (url: string) => { + window.open(url, '_blank'); + }; + + return ( +
+
Dipper Map 地理可视化分析工具
+
DipperMap 基于L7 地图可视分析工具,用户自由上传地理数据进行可视化化配置。
+
+ + {dippermap.map(item => { + return ( +
+

{item.desc}

+ {item.alt} +
+ ); + })} +
+
+
+ ); +} diff --git a/site/components/analysis/components/Bar/index.tsx b/site/components/analysis/components/Bar/index.tsx new file mode 100644 index 0000000000..96e57e7860 --- /dev/null +++ b/site/components/analysis/components/Bar/index.tsx @@ -0,0 +1,43 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Bar } from '@antv/g2plot'; + +export interface ChatData { + data: object[]; + legend?: boolean; + loading?: boolean; +} + +export function BarCahrt({ data }: ChatData) { + const id = useRef(); + const [barplot, setBarplot] = useState(); + useEffect(() => { + if (!barplot && id.current) { + const bar = new Bar(id.current, { + // @ts-ignore + data: data.sort((a, b) => b.xField - a.xField), + autoFit: true, + xField: 'yField', + yField: 'xField', + xAxis: false, + label: { + position: 'left', + style: { + fill: '#fff', + }, + }, + legend: { + position: 'top-left', + }, + }); + + bar.render(); + setBarplot(bar); + } else { + barplot.update({ + data, + }); + } + }, [id.current, data]); + + return
; +} diff --git a/site/components/analysis/components/Line/index.tsx b/site/components/analysis/components/Line/index.tsx new file mode 100644 index 0000000000..f03969bb13 --- /dev/null +++ b/site/components/analysis/components/Line/index.tsx @@ -0,0 +1,36 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Line } from '@antv/g2plot'; +import { ChatData } from '../Bar'; +import { Spin } from 'antd'; + +export function LineCahrt({ data, loading }: ChatData) { + const id = useRef(); + const [lineplot, setLinePlot] = useState(); + + useEffect(() => { + if (!lineplot && id.current && data) { + const lineplot = new Line(id.current, { + data, + autoFit: true, + xField: 'xField', + yField: 'yField', + seriesField: 'series', + legend: { + position: 'top-left', + }, + }); + lineplot.render(); + setLinePlot(lineplot); + } else { + lineplot.update({ + data, + }); + } + }, [id.current, data]); + + return ( + +
+ + ); +} diff --git a/site/components/analysis/components/Pie/index.tsx b/site/components/analysis/components/Pie/index.tsx new file mode 100644 index 0000000000..0738922d0f --- /dev/null +++ b/site/components/analysis/components/Pie/index.tsx @@ -0,0 +1,44 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Pie } from '@antv/g2plot'; +import { ChatData } from '../Bar'; +import { Spin } from 'antd'; + +export function PieChart({ data, legend, loading }: ChatData) { + const id = useRef(); + const [pieplot, setPiePlot] = useState(); + + useEffect(() => { + if (!pieplot && id.current && data) { + const pie = new Pie(id.current, { + data, + autoFit: true, + angleField: 'xField', + colorField: 'yField', + radius: 0.7, + label: { + type: 'spider', + labelHeight: 28, + content: '{name}\n{percentage}', + }, + legend: legend + ? { + position: 'top-left', + } + : false, + }); + + pie.render(); + setPiePlot(pie); + } else { + pieplot.update({ + data, + }); + } + }, [id.current, data]); + + return ( + +
+ + ); +} diff --git a/site/components/analysis/components/SingleLine/index.tsx b/site/components/analysis/components/SingleLine/index.tsx new file mode 100644 index 0000000000..f0513b1319 --- /dev/null +++ b/site/components/analysis/components/SingleLine/index.tsx @@ -0,0 +1,28 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Line } from '@antv/g2plot'; +import { ChatData } from '../Bar'; + +export function SingleLineCahrt({ data }: ChatData) { + const id = useRef(); + const [lineplot, setLinePlot] = useState(); + + + useEffect(() => { + if (!lineplot && id.current && data) { + const area = new Line(id.current, { + data, + autoFit: true, + xField: 'xField', + yField: 'yField', + }); + area.render(); + setLinePlot(area); + }else{ + lineplot.update({ + data + }) + } + }, [id.current,data]); + + return
; +} diff --git a/site/components/analysis/components/StackArea/index.tsx b/site/components/analysis/components/StackArea/index.tsx new file mode 100644 index 0000000000..97ffaf2ce1 --- /dev/null +++ b/site/components/analysis/components/StackArea/index.tsx @@ -0,0 +1,42 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Area } from '@antv/g2plot'; +import { ChatData } from '../Bar'; + +export function StackAreaCahrt({ data }: ChatData) { + const id = useRef(); + const [pieplot, setAreaPlot] = useState(); + const [list,setData] = useState([]) + + useEffect(()=>{ + fetch('https://gw.alipayobjects.com/os/bmw-prod/b21e7336-0b3e-486c-9070-612ede49284e.json') + .then((res) => res.json()) + .then((data) => { + setData(data); + }); + },[]) + + + + useEffect(() => { + if (!pieplot && id.current && list) { + const area = new Area(id.current, { + data:list, + autoFit: true, + xField: 'date', + yField: 'value', + seriesField: 'country', + legend:{ + position:'top-left' + } + }); + area.render(); + setAreaPlot(area); + }else{ + pieplot.update({ + data:list + }) + } + }, [id.current,data]); + + return
; +} diff --git a/site/components/rumbling/configs/config.ts b/site/components/analysis/configs/config.ts similarity index 70% rename from site/components/rumbling/configs/config.ts rename to site/components/analysis/configs/config.ts index 7624c934aa..78a6c16e0c 100644 --- a/site/components/rumbling/configs/config.ts +++ b/site/components/analysis/configs/config.ts @@ -4,30 +4,20 @@ export const config: Partial = { viewData: { global: { filterData: [], - sceneCode: 'iot_terminal_dominant', areaCode: '330100', view: 'task', }, widgets: { citySelect: { options: CityList, - value: [330000, 330100], + value: ['330000', '330100'], }, }, }, headerbar: { display: true, - logo: { - display: true, - value: - 'https://gw.alipayobjects.com/mdn/rms_855bab/afts/img/A*ObVJT4IxmlkAAAAAAAAAAAAAARQnAQ', - style: { - height: '24px', - width: '24px', - }, - }, title: { - value: '区代指挥中心', + value: '数据分析', display: true, }, children: [ @@ -41,21 +31,6 @@ export const config: Partial = { action: 'queryArea', }, }, - { - display: true, - options: [ - { - label: '热区分析', - value: 'hotspot', - }, - { - label: '任务管理', - value: 'task', - }, - ], - position: 'center', - type: 'navibar', - }, { display: false, position: 'right', @@ -69,24 +44,37 @@ export const config: Partial = { }, panel: { display: true, - enableToggle: true, - defaultTitle: '所有网格', - opened: true, - width: 360, + options: { + enableToggle: true, + defaultTitle: '所有网格', + opened: true, + width: 426, + }, position: 'right', children: [ { - type: 'siderbartabcontent', + display: true, + type: 'meshName', + title: '网格名称', + }, + { + display: true, + type: 'meshchart', + title: '所有网格数据', + }, + { + display: false, + type: 'panelTabContent', title: '所有网格', children: [ { display: true, type: 'mesh_indicator', - title: '数据查看', + title: '业务数据', }, { type: 'total_data_panel', - title: '地图面板', + title: '人员数据', }, ], }, @@ -106,9 +94,27 @@ export const config: Partial = { { display: true, position: 'topleft', + type: 'filter', + title: '筛选', + }, + { + display: true, + position: 'bottomright', + type: 'location', + title: '定位', + }, + { + display: true, + position: 'bottomright', type: 'mapStyle', title: '地图样式', }, + { + display: true, + position: 'topleft', + type: 'searchPlaces', + title: '地区搜索', + }, ], defaultcontrols: [ { @@ -136,7 +142,7 @@ export const config: Partial = { }, fill: { field: 'unit_price', - color: SingleSequentialColorScale.Blue, + color: ['#A9D3FF', '#82B1FF', '#6294FF', '#457BFF', '#2962FF'], bandNum: 5, scale: 'quantile', unknownName: '无类型', diff --git a/site/components/analysis/configs/mock.ts b/site/components/analysis/configs/mock.ts new file mode 100644 index 0000000000..12c10f37b3 --- /dev/null +++ b/site/components/analysis/configs/mock.ts @@ -0,0 +1,267 @@ +import Mock from 'mockjs'; + +// 单折线图 +export const singleLineChart = () => { + const data = Mock.mock({ + 'list|9': [ + { + // 生成长度在 100~1000 之间的小写字母 + yField: '@integer(0,5000)', + }, + ], + }); + return data.list + .sort((a, b) => a.yField - b.yField) + .map((item, index) => { + return { + xField: `${index + 1}月`, + ...item, + }; + }); +}; + +// 条形图 +export const barChart = () => { + let xField = ['餐饮', '影院', '百货购物中心', '国内旅游', '医疗']; + const data = Mock.mock({ + 'list|5': [ + { + // 生成长度在 100~1000 之间的小写字母 + yField: '@integer(0,5000)', + }, + ], + }); + return data.list + .sort((a, b) => b.yField - a.yField) + .map((item, index) => { + return { + xField: xField[index], + ...item, + }; + }); +}; + +// 多维折线图 +export const multidimensionalChart = () => { + const series = ['铺设失败', '铺设中', '铺设成功', '虚假铺设']; + const xField = new Array(12).fill('').map((item, index) => { + return `${2 * index + 2}:00`; + }); + + return series + .map((a, k) => { + return xField.map((b, index) => { + return { + xField: b, + series: a, + yField: Number( + ((index + 1) * 10 + 20 * Math.random() + k * 20).toFixed(), + ), + }; + }); + }) + .flat(); +}; + +// 作业单数 +export const operation = () => { + const data = Mock.mock({ + 'list|15': [ + { + name: '@cname', + order_count: '@integer(0,100)', + staff_no: '@integer(100000,1000000)', + }, + ], + }); + return data.list; +}; + +// 行业市场份额 +export const marketShare = () => { + const data = Mock.mock({ + 'list|3': [ + { + // 生成长度在 100~1000 之间的小写字母 + xField: '@integer(0,100)', + }, + ], + }); + const yField = ['街电', '怪兽', '小电']; + return data.list + .sort((a, b) => a.yField - b.yField) + .map((item, index) => { + return { + yField: yField[index], + ...item, + }; + }); +}; + +// 各品牌营收 +export const brandRevenue = () => { + const series = ['街电', '来电', '怪兽', '美团', '小电']; + const xField = new Array(11).fill('').map((item, index) => { + return `${2009 + index}`; + }); + + return series + .map((a, k) => { + return xField.map((b, index) => { + return { + xField: b, + series: a, + yField: Number( + ((index + 1) * 10 + 30 * Math.random() + k * 20).toFixed(), + ), + }; + }); + }) + .flat(); +}; + +export function randomData(data: T): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(data); + }, 500); + }); +} + +// 生成范围内的随机数 +export const randomNumBoth = (min: number, max: number) => { + const Range = max - min; + const Rand = Math.random(); + const num = min + Math.round(Rand * Range); + return num; +} + +export const brandOption = [ + { label: '全部类型', value: '1' }, + { label: '街电', value: '2' }, + { label: '怪兽', value: '3' }, + { label: '小电', value: '4' }, +]; + +export const CityList = [ + { + value: '330000', + areaLevel: 'province', + label: '浙江省', + children: [ + { + value: '330100', + areaLevel: 'city', + label: '杭州市', + children: [], + }, + ], + }, + { + value: '110000', + areaLevel: 'province', + label: '北京市', + children: [ + { + value: '110000', + areaLevel: 'city', + label: '北京市', + children: [], + }, + ], + }, + { + value: '120000', + areaLevel: 'province', + label: '天津市', + children: [ + { + value: '120000', + areaLevel: 'city', + label: '天津市', + children: [], + }, + ], + }, + { + value: '310000', + areaLevel: 'province', + label: '上海市', + children: [ + { + value: '310000', + areaLevel: 'province', + label: '上海市', + children: [], + }, + ], + }, + { + value: '440000', + areaLevel: 'province', + label: '广东省', + children: [ + { + value: '440100', + areaLevel: 'city', + label: '广州市', + children: [], + }, + { + value: '440300', + areaLevel: 'city', + label: '深圳市', + children: [], + }, + { + value: '440400', + areaLevel: 'city', + label: '珠海市', + children: [], + }, + { + value: '440600', + areaLevel: 'city', + label: '佛山市', + children: [], + }, + { + value: '441300', + areaLevel: 'city', + label: '惠州市', + children: [], + }, + { + value: '441900', + areaLevel: 'city', + label: '东莞市', + children: [], + }, + { + value: '442000', + areaLevel: 'city', + label: '中山市', + children: [], + }, + ], + }, + { + value: '130000', + areaLevel: 'province', + label: '河北省', + children: [ + { + value: '130100', + areaLevel: 'city', + label: '石家庄市', + children: [], + }, + { + value: '131000', + areaLevel: 'city', + label: '廊坊市', + children: [], + }, + ], + }, +]; diff --git a/site/components/analysis/index.tsx b/site/components/analysis/index.tsx new file mode 100644 index 0000000000..7d75f24b9c --- /dev/null +++ b/site/components/analysis/index.tsx @@ -0,0 +1,27 @@ +import { initWidgets } from './widgets'; +import React, { useEffect, useState } from 'react'; +import { config } from './configs/config'; +import { DipperContainer, IConfig } from '@antv/dipper'; +import 'antd/dist/antd.css' +interface IInitData { + areaVOList: any[]; + sceneCode: string; + areaCode: string; + filterData: any[]; +} + +export default function RumbMap() { + const [mapConfig, setMapConfig] = useState>(); + // 初始化相关数据 + + useEffect(() => { + initWidgets(); + setMapConfig(config); + }, []); + + return ( +
+ cfg={mapConfig!} /> +
+ ); +} diff --git a/site/components/analysis/widgets/Filter.tsx b/site/components/analysis/widgets/Filter.tsx new file mode 100644 index 0000000000..77aa663151 --- /dev/null +++ b/site/components/analysis/widgets/Filter.tsx @@ -0,0 +1,42 @@ +import { Select } from 'antd'; +import React from 'react'; +import { useConfigService } from '@antv/dipper'; +import { brandOption } from '../configs/mock'; + +const { Option } = Select; + +export const Filter = () => { + const { setWidgetsValue } = useConfigService(); + + const onBrandChange = (e: any) => { + setWidgetsValue('brand', e); + }; + + return ( +
+ + +
+ ); +}; diff --git a/site/components/analysis/widgets/GridLayer.tsx b/site/components/analysis/widgets/GridLayer.tsx new file mode 100644 index 0000000000..94f560867f --- /dev/null +++ b/site/components/analysis/widgets/GridLayer.tsx @@ -0,0 +1,140 @@ +import { + useSceneService, + useConfigService, + LayerGroupEventEnum, + useLayerService, +} from '@antv/dipper'; +import React, { useEffect, useMemo, useState } from 'react'; +import { GridLayerGroup } from '@antv/dipper'; +import { randomNumBoth } from '../configs/mock'; +const formatLegend = (data: any[]) => { + return data.map((item) => { + if (Array.isArray(item.value)) { + return { + ...item, + value: item.value.map((v) => v.toFixed(2)), + }; + } else { + return { + ...item, + value: item.value.toFixed(2), + }; + } + }); +}; +export function GridLayer() { + const { layerService } = useLayerService(); + const { sceneService } = useSceneService(); + const { globalConfig, updateLegend, getWidgetsValue } = useConfigService(); + const { layers } = globalConfig; + const [gridLayer, setGridLayer] = useState(); + const cityValue = getWidgetsValue('citySelect'); + const brandValue = getWidgetsValue('brand'); + const [geoData, setGeoData] = useState(); + + const layerProps = useMemo(() => { + return layers.find((item: any) => item.type === 'gridLayer'); + }, [layers]); + + const updateLayerLegend = (items: any[]) => { + updateLegend('gridLayerLegend', { + type: 'classifyColor', + display: true, + position: 'bottomleft', + options: { + title: '充电宝投放数量', + unkownName: layerProps.options.unkownName, + items: items.map((item) => { + return { + color: item.color, + value: item.value.map((v) => { + return (v / 10000).toFixed(2); + }), + }; + }), + }, + }); + }; + + // 根据筛选器条件请求数据 + useEffect(() => { + // 可以根据业务需求配置接口 + fetch( + `https://gw.alipayobjects.com/os/antvdemo/assets/dipper-city/${cityValue[1]}.json`, + ) + .then((res) => res.json()) + .then((data) => { + const geoDataList = + data && + data.features?.map((item) => { + return { + ...item, + properties: { + ...item.properties, + brand_type: randomNumBoth(1, 4).toString(), // 充电宝品牌 + }, + }; + }); + + // 品牌 过滤 + if (brandValue && geoDataList) { + // @ts-ignore + const data = + brandValue === '1' + ? geoDataList + : geoDataList.filter( + (item) => item.properties.brand_type === brandValue, + ); + if (data.length) { + // @ts-ignore + setGeoData({ type: 'FeatureCollection', features: data }); + } + } else { + // @ts-ignore + setGeoData({ type: 'FeatureCollection', features: geoDataList }); + } + }); + // 切换城市 高德地图方法 + sceneService.getScene().map?.setCity(cityValue[1]); + }, [JSON.stringify(cityValue), brandValue]); + + useEffect(() => { + if (!geoData) { + return; + } + if (gridLayer) { + gridLayer.setData(geoData); + return; + } + const layer = new GridLayerGroup({ + name: 'grid', + data: geoData, + options: layerProps.options, + }); + layerService.addLayer(layer); + + layer.on(LayerGroupEventEnum.DATAUPDATE, () => { + layer.getLegendItem().map((item) => { + if (Array.isArray(item.value)) { + return { + ...item, + value: item.value.map((v) => v.toFixed(2)), + }; + } else { + return { + ...item, + value: item.value.toFixed(2), + }; + } + }); + updateLayerLegend(formatLegend(layer.getLegendItem())); + }); + + // 更新图例 + updateLayerLegend(formatLegend(layer.getLegendItem())); + + setGridLayer(layer); + }, [geoData]); + + return <>; +} diff --git a/site/components/analysis/widgets/MeshChart/index.tsx b/site/components/analysis/widgets/MeshChart/index.tsx new file mode 100644 index 0000000000..8443615146 --- /dev/null +++ b/site/components/analysis/widgets/MeshChart/index.tsx @@ -0,0 +1,34 @@ +import React, { useEffect, useState } from 'react'; +import { useLayerGroup } from '@antv/dipper'; +import { brandRevenue, marketShare } from '../../configs/mock'; +import { PieChart } from '../../components/Pie'; +import { LineCahrt } from '../../components/Line'; + +export function MeshChart() { + const { selectFeatures } = useLayerGroup('grid'); + const [pieData, setPieData] = useState([]); + const [lineData, setLineData] = useState([]); + const [loding, setLoding] = useState(false); + + useEffect(() => { + setLoding(true); + setTimeout(() => { + setLoding(false); + setPieData(marketShare()); + setLineData(brandRevenue()); + }, 300); + }, [JSON.stringify(selectFeatures)]); + + return ( +
+
+

行业市场份额

+ +
+
+

各品牌营收

+ +
+
+ ); +} diff --git a/site/components/analysis/widgets/MeshIndicator.tsx b/site/components/analysis/widgets/MeshIndicator.tsx new file mode 100644 index 0000000000..ced8182214 --- /dev/null +++ b/site/components/analysis/widgets/MeshIndicator.tsx @@ -0,0 +1,33 @@ +import React, { useState, useEffect } from 'react'; +import { useLayerGroup } from '@antv/dipper'; +import { SingleLineCahrt } from '../components/SingleLine'; +import { singleLineChart, barChart } from '../configs/mock'; +import { BarCahrt } from '../components/Bar'; + +export function MeshIndicator() { + const { selectFeatures } = useLayerGroup('grid'); + + // lineChart + const [lineData, setLineData] = useState([]); + + const [barData, setBarData] = useState([]); + + // lineChart + useEffect(() => { + setLineData(singleLineChart()); + setBarData(barChart()); + }, [JSON.stringify(selectFeatures)]); + + return ( +
+
+
交易笔数
+ +
+
+
各场景覆盖数
+ +
+
+ ); +} diff --git a/site/components/analysis/widgets/MeshName/index.module.css b/site/components/analysis/widgets/MeshName/index.module.css new file mode 100644 index 0000000000..a03ab39e9d --- /dev/null +++ b/site/components/analysis/widgets/MeshName/index.module.css @@ -0,0 +1,13 @@ +.meahname { + padding: 20px; +} +.closeicon { + padding: 0 8px; +} +.edit { + display: flex; + align-items: center; +} +.edit span:hover { + color: #1890ff; +} diff --git a/site/components/analysis/widgets/MeshName/index.tsx b/site/components/analysis/widgets/MeshName/index.tsx new file mode 100644 index 0000000000..0f03f1a034 --- /dev/null +++ b/site/components/analysis/widgets/MeshName/index.tsx @@ -0,0 +1,106 @@ +import React, { + useRef, + useState, + useMemo, + useCallback, + useEffect, +} from 'react'; +import { CheckOutlined, CloseOutlined, EditOutlined } from '@ant-design/icons'; +import styles from './index.module.css' +import { Input } from 'antd'; +import { useLayerGroup, useConfigService } from '@antv/dipper'; +import _ from 'loadsh'; + +export function MeshName() { + const { selectFeatures, updateProperties } = useLayerGroup('grid'); + const [edit, setEdit] = useState(false); + const ref = useRef(); + const { setConfig } = useConfigService(); + + /** + * get meshname + * type []string + */ + const meshName = useMemo(() => { + if (!selectFeatures.length) return []; + return selectFeatures.map((item) => { + // @ts-ignore + return item.feature.properties.name; + }); + }, [JSON.stringify(selectFeatures)]); + + // 修改 网格名称 + const editMeshName = useCallback(() => { + // @ts-ignore + const value = ref.current.state.value; + selectFeatures.forEach((item) => { + const properties = { + ...item.feature.properties, + name: value, + }; + updateProperties(item.feature, properties); + }); + setEdit(false); + }, [JSON.stringify(selectFeatures)]); + + // select more meshname 编辑 网格名称 + const EditMeshName = () => { + return ( + <> + {!edit ? ( +
setEdit(!edit)}> + {meshName} + +
+ ) : ( +
+ + + setEdit(false)} /> +
+ )} + + ); + }; + + // show 多个网格名称 + const ShowMeshNames = () => { + return ( +
+ {meshName.length >= 2 && + meshName.map((s) => { + return + {s}、 + ; + })} +
+ ); + }; + + useEffect(() => { + if (selectFeatures.length) { + // TODO 报错 + setConfig(`panel.children.1.display`, false); + setConfig(`panel.children.2.display`, true); + // setConfig(`panel.children.${findIdMeshchart}.display`, false) + } else { + setConfig(`panel.children.1.display`, true); + setConfig(`panel.children.2.display`, false); + } + }, [JSON.stringify(selectFeatures)]); + + return ( + <> + {meshName && meshName.length ? ( +
+ {meshName.length === 1 ? : } +
+ ) : ( +

所有网格数据概览

+ )} + + ); +} diff --git a/site/components/analysis/widgets/TotalPanel/index.module.css b/site/components/analysis/widgets/TotalPanel/index.module.css new file mode 100644 index 0000000000..b3f2430e6c --- /dev/null +++ b/site/components/analysis/widgets/TotalPanel/index.module.css @@ -0,0 +1,37 @@ +.teamcontainer { + margin: 10px 0; + display: flex; + align-items: center; + justify-content: space-between; +} +.orderlist { + display: flex; + align-items: center; + justify-content: space-between; + height: 48px; + width: 378px; + background: #fafafa; + border-radius: 2px; + padding: 0 5px; +} +.orderlist .leftpart { + display: flex; + align-items: center; +} +.orderlist .leftpart > div { + padding-right: 15px; +} +.orderlist .leftpart .ordericon { + width: 16px; + height: 16px; + margin-right: 10px; +} +.sort:hover { + color: #1e73f8; +} +.orderCon :global .ant-list-split .ant-list-item { + border: none !important; +} +.orderCon :global .ant-list-item { + padding: 5px 0 !important; +} diff --git a/site/components/analysis/widgets/TotalPanel/index.tsx b/site/components/analysis/widgets/TotalPanel/index.tsx new file mode 100644 index 0000000000..8c0953f95c --- /dev/null +++ b/site/components/analysis/widgets/TotalPanel/index.tsx @@ -0,0 +1,116 @@ +import React, { useState, useEffect } from 'react'; +import { useLayerGroup } from '@antv/dipper' +import { Button, List } from 'antd'; +import { multidimensionalChart, operation } from '../../configs/mock'; +import styles from './index.module.css' +import { LineCahrt } from '../../components/Line'; + +enum Sort { + Up, + Dowm, +} + +const No1 = + 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*grCBQ4izMjcAAAAAAAAAAAAAARQnAQ'; +const No2 = + 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*r0DyQIluJ8QAAAAAAAAAAAAAARQnAQ'; +const No3 = + 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*5R92QrzHW7YAAAAAAAAAAAAAARQnAQ'; + +export function TotalPanel() { + const { selectFeatures = [] } = useLayerGroup('grid'); + + const [lineData, setLineData] = useState([]); + const [orderData, setOrderData] = useState([]); + const [ordersort, setOrderSort] = useState(1); + const [loading, setLoading] = useState(false); + + // lineChart + useEffect(() => { + setLoading(true) + setTimeout(()=>{ + setLoading(false) + setLineData(multidimensionalChart()); + },300) + }, [JSON.stringify(selectFeatures)]); + + useEffect(() => { + if (ordersort === undefined) { + return setOrderData(operation()); + } + const sortData = operation(); + if (ordersort === 0) { + return setOrderData( + sortData.sort((a, b) => a.order_count - b.order_count), + ); + } + if (ordersort === 1) { + return setOrderData( + sortData.sort((a, b) => b.order_count - a.order_count), + ); + } + }, [selectFeatures, ordersort]); + + // 排序 + const sorts = (type: Sort) => { + setOrderSort(type); + }; + + // orderData index 与 icon 映射 + const iconOrder = { 1: No1, 2: No2, 3: No3 }; + + return ( +
+
+

铺设进程

+ +
+
+
+
团队榜单
+
+ + +
+
+ {orderData && ( + ( + +
+
+ {index <= 2 ? ( + + ) : ( +
{index + 1}
+ )} + + {item.name}({item.staff_no}) + +
+
作业成功{item.order_count}单
+
+
+ )} + /> + )} +
+
+ ); +} diff --git a/site/components/analysis/widgets/index.ts b/site/components/analysis/widgets/index.ts new file mode 100644 index 0000000000..6e220dcc52 --- /dev/null +++ b/site/components/analysis/widgets/index.ts @@ -0,0 +1,34 @@ +import { registerWidget } from '@antv/dipper-core'; +import { + CitySelect, + NavBar, + ClassifyColor, + DiscreteColor, + Draw, + MapStyle, + SearchPlace, + Location, +} from '@antv/dipper-widgets'; +import { GridLayer } from './GridLayer'; +import { MeshIndicator } from './MeshIndicator'; +import { MeshName } from './MeshName'; +import { Filter } from './Filter'; +import { TotalPanel } from './TotalPanel/index'; +import { MeshChart } from './MeshChart'; + +export function initWidgets() { + registerWidget('citySelect', CitySelect); + registerWidget('navibar', NavBar); + registerWidget('gridLayer', GridLayer); + registerWidget('classifyColor', ClassifyColor); + registerWidget('discreteColor', DiscreteColor); + registerWidget('mapStyle', MapStyle); + registerWidget('searchPlaces', SearchPlace); + registerWidget('location', Location); + registerWidget('filter', Filter); + registerWidget('mesh_indicator', MeshIndicator); + registerWidget('total_data_panel', TotalPanel); + registerWidget('meshchart', MeshChart); + registerWidget('draw', Draw); + registerWidget('meshName',MeshName) +} diff --git a/site/components/rumbling/configs/mock.ts b/site/components/rumbling/configs/mock.ts deleted file mode 100644 index 584b3b38cd..0000000000 --- a/site/components/rumbling/configs/mock.ts +++ /dev/null @@ -1,532 +0,0 @@ -export const geojson = [ - { - type: 'Feature', - properties: { - label: 'A类区域', - value: 'A', - featureId: '2021102300040027', - id: '2021102300040027', - name: '哈哈6666', - groupId: '2021102300073562', - canvasId: '2021102300077947', - creator: '285869', - modifier: 'WB904416', - gmtCreate: '2021-10-23T13:23:53.000+00:00', - gmtModified: '2021-10-29T08:43:06.000+00:00', - status: 1, - bizId: 'ALGO13301000000030038b', - source: 'INIT', - extInfo: { - area_centroid: '[120.200270,30.137812]', - }, - }, - geometry: { - type: 'Polygon', - coordinates: [ - [ - [120.147844, 30.143857], - [120.146688, 30.144529], - [120.145292, 30.145769], - [120.14333, 30.146841], - [120.138229, 30.153274], - [120.133322, 30.160392], - [120.132625, 30.161615], - [120.135188, 30.16281], - [120.136067, 30.163429], - [120.137014, 30.164436], - [120.138875, 30.167409], - [120.139576, 30.168271], - [120.140893, 30.169368], - [120.141752, 30.169944], - [120.144082, 30.170827], - [120.147209, 30.171816], - [120.151231, 30.172756], - [120.154113, 30.173337], - [120.155476, 30.173477], - [120.158666, 30.173408], - [120.158813, 30.173182], - [120.167716, 30.173249], - [120.167809, 30.173079], - [120.167644, 30.172555], - [120.167663, 30.172204], - [120.168217, 30.171148], - [120.168583, 30.170715], - [120.168799, 30.169991], - [120.16937, 30.169203], - [120.168394, 30.168113], - [120.167832, 30.167112], - [120.170001, 30.162286], - [120.170393, 30.161163], - [120.170857, 30.160363], - [120.171268, 30.159909], - [120.171843, 30.159472], - [120.172585, 30.159084], - [120.173472, 30.158806], - [120.176516, 30.158457], - [120.178244, 30.158018], - [120.181234, 30.156641], - [120.182546, 30.156143], - [120.187335, 30.155265], - [120.188246, 30.155308], - [120.188949, 30.155505], - [120.189517, 30.155768], - [120.190041, 30.156122], - [120.191852, 30.157747], - [120.192457, 30.158198], - [120.199627, 30.161976], - [120.200393, 30.161113], - [120.201372, 30.160261], - [120.204072, 30.158385], - [120.204474, 30.157992], - [120.205018, 30.15764], - [120.205398, 30.157546], - [120.205887, 30.157658], - [120.205706, 30.15851], - [120.206192, 30.158863], - [120.206058, 30.159513], - [120.206121, 30.159901], - [120.207273, 30.160486], - [120.208006, 30.160419], - [120.208488, 30.159493], - [120.208835, 30.158228], - [120.208544, 30.157534], - [120.206494, 30.157128], - [120.207878, 30.156136], - [120.208276, 30.156082], - [120.208298, 30.156518], - [120.209071, 30.157141], - [120.210222, 30.156577], - [120.210388, 30.157044], - [120.210978, 30.157462], - [120.212571, 30.158131], - [120.212937, 30.158078], - [120.213941, 30.157481], - [120.214887, 30.159206], - [120.214888, 30.160837], - [120.215479, 30.161676], - [120.215645, 30.162161], - [120.215948, 30.162305], - [120.218933, 30.162964], - [120.21947, 30.162984], - [120.221036, 30.16208], - [120.221542, 30.161941], - [120.221799, 30.162783], - [120.222203, 30.163521], - [120.222931, 30.164169], - [120.225012, 30.165453], - [120.225443, 30.165901], - [120.226118, 30.16827], - [120.226124, 30.168557], - [120.225875, 30.168755], - [120.226207, 30.170185], - [120.226446, 30.170469], - [120.226639, 30.170573], - [120.227512, 30.170626], - [120.227522, 30.171242], - [120.227796, 30.171909], - [120.229737, 30.172137], - [120.229916, 30.171461], - [120.23, 30.170618], - [120.230569, 30.170018], - [120.233933, 30.169673], - [120.23455, 30.165985], - [120.234458, 30.164828], - [120.234558, 30.162136], - [120.234676, 30.16115], - [120.235118, 30.159612], - [120.235576, 30.158653], - [120.235617, 30.15825], - [120.236053, 30.157277], - [120.235382, 30.157034], - [120.235301, 30.156572], - [120.23496, 30.156239], - [120.234249, 30.155793], - [120.233696, 30.155684], - [120.2332, 30.15573], - [120.232496, 30.155586], - [120.23286, 30.154907], - [120.233495, 30.154176], - [120.232856, 30.153878], - [120.232683, 30.153433], - [120.232879, 30.153278], - [120.232872, 30.152843], - [120.232724, 30.152397], - [120.23234, 30.151877], - [120.231848, 30.151555], - [120.231595, 30.151273], - [120.231185, 30.150624], - [120.230557, 30.150187], - [120.230053, 30.149345], - [120.229281, 30.148778], - [120.228917, 30.148747], - [120.228421, 30.14842], - [120.228184, 30.147479], - [120.226923, 30.147425], - [120.226418, 30.147328], - [120.225486, 30.147388], - [120.226496, 30.146217], - [120.225966, 30.145733], - [120.225583, 30.145521], - [120.225428, 30.14502], - [120.224312, 30.14501], - [120.223858, 30.144788], - [120.223652, 30.144476], - [120.223478, 30.144345], - [120.222825, 30.14418], - [120.222569, 30.14428], - [120.221885, 30.144124], - [120.221396, 30.144273], - [120.220971, 30.1447], - [120.220603, 30.144724], - [120.220295, 30.144623], - [120.220024, 30.144701], - [120.219842, 30.144619], - [120.219654, 30.144693], - [120.219384, 30.144654], - [120.218498, 30.144158], - [120.217793, 30.143521], - [120.217119, 30.143362], - [120.216758, 30.14301], - [120.216674, 30.14272], - [120.216732, 30.142301], - [120.217668, 30.141623], - [120.218151, 30.141431], - [120.220282, 30.139534], - [120.220356, 30.140206], - [120.220619, 30.140315], - [120.220731, 30.140486], - [120.221293, 30.140608], - [120.221736, 30.140936], - [120.221342, 30.141563], - [120.22151, 30.141869], - [120.220996, 30.142466], - [120.22197, 30.142837], - [120.223564, 30.142785], - [120.223847, 30.142422], - [120.223877, 30.142059], - [120.223806, 30.141797], - [120.221855, 30.139726], - [120.2231, 30.140085], - [120.223641, 30.140564], - [120.223948, 30.141129], - [120.223997, 30.141173], - [120.224257, 30.141696], - [120.224258, 30.142105], - [120.224381, 30.142548], - [120.224535, 30.142716], - [120.224726, 30.143188], - [120.2255, 30.143728], - [120.226119, 30.144357], - [120.226434, 30.14455], - [120.228071, 30.144609], - [120.229719, 30.144786], - [120.229908, 30.14485], - [120.23018, 30.145286], - [120.230407, 30.145484], - [120.231237, 30.145853], - [120.231382, 30.146076], - [120.231631, 30.146207], - [120.232288, 30.146322], - [120.233052, 30.146667], - [120.23368, 30.14734], - [120.233786, 30.147891], - [120.234623, 30.14832], - [120.234839, 30.148646], - [120.235314, 30.149087], - [120.23548, 30.149626], - [120.235721, 30.149938], - [120.236457, 30.150391], - [120.23716, 30.150539], - [120.237485, 30.150801], - [120.23803, 30.151477], - [120.239139, 30.152535], - [120.23946, 30.153088], - [120.240229, 30.153121], - [120.240626, 30.152351], - [120.241359, 30.151459], - [120.242314, 30.150725], - [120.245302, 30.148847], - [120.24628, 30.147889], - [120.247034, 30.146693], - [120.247423, 30.145397], - [120.247992, 30.145405], - [120.248012, 30.143993], - [120.247725, 30.142724], - [120.247166, 30.142646], - [120.242305, 30.130879], - [120.241721, 30.130596], - [120.240334, 30.12946], - [120.239997, 30.129042], - [120.238317, 30.125574], - [120.237006, 30.123431], - [120.236783, 30.122886], - [120.235868, 30.122206], - [120.236571, 30.122049], - [120.23665, 30.121468], - [120.235894, 30.119696], - [120.235675, 30.118672], - [120.235701, 30.117587], - [120.235629, 30.11654], - [120.235379, 30.116023], - [120.233483, 30.116034], - [120.233123, 30.116188], - [120.232895, 30.116075], - [120.231727, 30.115965], - [120.230487, 30.116072], - [120.230015, 30.116313], - [120.229969, 30.115245], - [120.229787, 30.11438], - [120.229945, 30.113327], - [120.232144, 30.112345], - [120.233516, 30.111985], - [120.235989, 30.111814], - [120.234895, 30.107582], - [120.234778, 30.106555], - [120.234895, 30.104915], - [120.230596, 30.103151], - [120.2278, 30.101876], - [120.226383, 30.101599], - [120.222325, 30.1023], - [120.2147, 30.103149], - [120.212667, 30.103445], - [120.21219, 30.10365], - [120.211945, 30.103932], - [120.210495, 30.107288], - [120.209991, 30.108123], - [120.209384, 30.108529], - [120.208824, 30.10864], - [120.208085, 30.108556], - [120.205857, 30.107717], - [120.205393, 30.107652], - [120.204861, 30.107693], - [120.201864, 30.109287], - [120.20089, 30.109712], - [120.199973, 30.109881], - [120.193121, 30.109323], - [120.191151, 30.109647], - [120.190646, 30.109835], - [120.190888, 30.111217], - [120.190796, 30.111259], - [120.190086, 30.109884], - [120.189525, 30.109667], - [120.18587, 30.107744], - [120.185064, 30.109015], - [120.183326, 30.113489], - [120.18151, 30.11587], - [120.180172, 30.11726], - [120.177758, 30.119219], - [120.174527, 30.121509], - [120.173028, 30.122505], - [120.172232, 30.122899], - [120.171456, 30.123117], - [120.170975, 30.12361], - [120.170378, 30.12466], - [120.166094, 30.128398], - [120.165454, 30.129692], - [120.164526, 30.130852], - [120.163489, 30.131706], - [120.162161, 30.132556], - [120.160762, 30.133219], - [120.158745, 30.134854], - [120.156354, 30.137038], - [120.154387, 30.138586], - [120.152292, 30.139893], - [120.150055, 30.14083], - [120.149208, 30.142005], - [120.148552, 30.143085], - [120.147844, 30.143857], - ], - ], - }, - }, - { - type: 'Feature', - properties: { - label: 'B类区域', - value: 'B', - featureId: '2021102300040027', - id: '2021102300040027', - name: '于争光', - groupId: '2021102300073562', - canvasId: '2021102300077947', - creator: '285869', - modifier: 'WB904416', - gmtCreate: '2021-10-23T13:23:53.000+00:00', - gmtModified: '2021-10-29T08:43:06.000+00:00', - status: 1, - bizId: 'ALGO13301000000030038b', - source: 'INIT', - extInfo: { - area_centroid: '[120.200270,30.137812]', - }, - }, - geometry: { - type: 'Polygon', - coordinates: [ - [ - [120.1636505126953, 30.24631485403797], - [120.17704010009766, 30.22970466206658], - [120.19214630126953, 30.243942141326617], - [120.1636505126953, 30.24631485403797], - ], - ], - }, - }, - { - type: 'Feature', - properties: { - label: 'C类区域', - value: 'C', - featureId: '2021102300040027', - id: '2021102300040027', - name: 'ecnevnevnec', - groupId: '2021102300073562', - canvasId: '2021102300077947', - creator: '285869', - modifier: 'WB904416', - gmtCreate: '2021-10-23T13:23:53.000+00:00', - gmtModified: '2021-10-29T08:43:06.000+00:00', - status: 1, - bizId: 'ALGO13301000000030038b', - source: 'INIT', - extInfo: { - area_centroid: '[120.200270,30.137812]', - }, - }, - geometry: { - type: 'Polygon', - coordinates: [ - [ - [120.09017944335938, 30.224958377428475], - [120.08949279785156, 30.18994745521063], - [120.14751434326172, 30.189353942421295], - [120.14854431152342, 30.22466172703242], - [120.09017944335938, 30.224958377428475], - ], - ], - }, - }, -]; - -export const CityList = [ - { - value: '330000', - areaLevel: 'province', - label: '浙江省', - children: [ - { - value: '330100', - areaLevel: 'city', - label: '杭州市', - children: [], - }, - ], - }, - { - value: '110000', - areaLevel: 'province', - label: '北京市', - children: [ - { - value: '110000', - areaLevel: 'city', - label: '北京市', - children: [], - }, - ], - }, - { - value: '120000', - areaLevel: 'province', - label: '天津市', - children: [ - { - value: '120000', - areaLevel: 'city', - label: '天津市', - children: [], - }, - ], - }, - { - value: '310000', - areaLevel: 'province', - label: '上海市', - children: [ - { - value: '310000', - areaLevel: 'province', - label: '上海市', - children: [], - }, - ], - }, - { - value: '440000', - areaLevel: 'province', - label: '广东省', - children: [ - { - value: '440100', - areaLevel: 'city', - label: '广州市', - children: [], - }, - { - value: '440300', - areaLevel: 'city', - label: '深圳市', - children: [], - }, - { - value: '440400', - areaLevel: 'city', - label: '珠海市', - children: [], - }, - { - value: '440600', - areaLevel: 'city', - label: '佛山市', - children: [], - }, - { - value: '441300', - areaLevel: 'city', - label: '惠州市', - children: [], - }, - { - value: '441900', - areaLevel: 'city', - label: '东莞市', - children: [], - }, - { - value: '442000', - areaLevel: 'city', - label: '中山市', - children: [], - }, - ], - }, - { - value: '130000', - areaLevel: 'province', - label: '河北省', - children: [ - { - value: '130100', - areaLevel: 'city', - label: '石家庄市', - children: [], - }, - { - value: '131000', - areaLevel: 'city', - label: '廊坊市', - children: [], - }, - ], - }, -]; diff --git a/site/components/rumbling/widgets/index.ts b/site/components/rumbling/widgets/index.ts deleted file mode 100644 index a11dfaa89f..0000000000 --- a/site/components/rumbling/widgets/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { registerWidget } from '@antv/dipper-core'; -import { - CitySelect, - SiderBar, - NavBar, - ClassifyColor, - DiscreteColor, -} from '@antv/dipper-widgets'; -import { GridLayer } from './GridLayer'; -import { MapStyle } from '@antv/dipper-widgets'; - -export function initWidgets() { - registerWidget('citySelect', CitySelect); - registerWidget('siderbartabcontent', SiderBar); - registerWidget('navibar', NavBar); - registerWidget('gridLayer', GridLayer); - registerWidget('classifyColor', ClassifyColor); - registerWidget('discreteColor', DiscreteColor); - registerWidget('mapStyle', MapStyle); -} diff --git a/site/components/task/components/Bar/index.tsx b/site/components/task/components/Bar/index.tsx new file mode 100644 index 0000000000..be274f46b8 --- /dev/null +++ b/site/components/task/components/Bar/index.tsx @@ -0,0 +1,37 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Bar } from '@antv/g2plot'; + +export interface ChatData { + data: object[]; +} + +export function BarChart({ data }: ChatData) { + const id = useRef(); + const [barplot, setBarplot] = useState(); + useEffect(() => { + if (!barplot && id.current) { + const bar = new Bar(id.current, { + // @ts-ignore + data: data.sort((a, b) => b.xField - a.xField), + autoFit: true, + xField: 'xField', + yField: 'yField', + xAxis: false, + label: { + position: 'left', + style: { + fill: '#fff', + }, + }, + legend: { + position: 'top-left', + }, + }); + + bar.render(); + setBarplot(bar); + } + }, []); + + return
; +} diff --git a/site/components/task/components/Line/index.tsx b/site/components/task/components/Line/index.tsx new file mode 100644 index 0000000000..0b41073ace --- /dev/null +++ b/site/components/task/components/Line/index.tsx @@ -0,0 +1,42 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Line } from '@antv/g2plot'; +import { ChatData } from '../Bar'; + +export function LineChart({ data }: ChatData) { + const id = useRef(); + const [lineplot, setLinePlot] = useState(); + const [list, setData] = useState([]); + + useEffect(() => { + fetch( + 'https://gw.alipayobjects.com/os/bmw-prod/b21e7336-0b3e-486c-9070-612ede49284e.json', + ) + .then((res) => res.json()) + .then((data) => { + setData(data); + }); + }, []); + + useEffect(() => { + if (!lineplot && id.current && list) { + const area = new Line(id.current, { + data: list, + autoFit: true, + xField: 'date', + yField: 'value', + seriesField: 'country', + legend: { + position: 'top-left', + }, + }); + area.render(); + setLinePlot(area); + } else { + lineplot.update({ + data: list, + }); + } + }, [id.current, list]); + + return
; +} diff --git a/site/components/task/components/Pie/index.tsx b/site/components/task/components/Pie/index.tsx new file mode 100644 index 0000000000..d7c8d0250a --- /dev/null +++ b/site/components/task/components/Pie/index.tsx @@ -0,0 +1,33 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Pie } from '@antv/g2plot'; +import { ChatData } from '../Bar'; + +export function PieChart({ data }: ChatData) { + const id = useRef(); + const [pieplot, setPiePlot] = useState(); + + useEffect(() => { + if (!pieplot && id.current && data) { + const bar = new Pie(id.current, { + data, + autoFit: true, + angleField: 'xField', + colorField: 'yField', + radius: 0.7, + label: { + type: 'spider', + labelHeight: 28, + content: '{name}\n{percentage}', + }, + legend: { + position: 'top-left', + }, + }); + + bar.render(); + setPiePlot(bar); + } + }, [id.current, data]); + + return
; +} diff --git a/site/components/task/components/StackArea/index.tsx b/site/components/task/components/StackArea/index.tsx new file mode 100644 index 0000000000..4339f6f315 --- /dev/null +++ b/site/components/task/components/StackArea/index.tsx @@ -0,0 +1,42 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Area } from '@antv/g2plot'; +import { ChatData } from '../Bar'; + +export function StackAreaChart({ data }: ChatData) { + const id = useRef(); + const [pieplot, setAreaPlot] = useState(); + const [list, setData] = useState([]); + + useEffect(() => { + fetch( + 'https://gw.alipayobjects.com/os/bmw-prod/b21e7336-0b3e-486c-9070-612ede49284e.json', + ) + .then((res) => res.json()) + .then((data) => { + setData(data); + }); + }, []); + + useEffect(() => { + if (!pieplot && id.current && list) { + const area = new Area(id.current, { + data: list, + autoFit: true, + xField: 'date', + yField: 'value', + seriesField: 'country', + legend: { + position: 'top-left', + }, + }); + area.render(); + setAreaPlot(area); + } else { + pieplot.update({ + data: list, + }); + } + }, [id.current, data]); + + return
; +} diff --git a/site/components/task/configs/config.ts b/site/components/task/configs/config.ts new file mode 100644 index 0000000000..0c3fd1c320 --- /dev/null +++ b/site/components/task/configs/config.ts @@ -0,0 +1,168 @@ +import { IConfig, SingleSequentialColorScale } from '@antv/dipper'; +import { CityList } from './mock'; +export const config: Partial = { + viewData: { + global: { + filterData: [], + areaCode: '110000', + view: 'task', + }, + widgets: { + citySelect: { + options: CityList, + value: ['110000', '110000'], + }, + }, + }, + headerbar: { + display: true, + title: { + value: 'XX 管理地图地图', + display: true, + }, + children: [ + { + display: true, + position: 'left', + title: '选择城市', + type: 'citySelect', + event: { + actionType: 'map', + action: 'queryArea', + }, + }, + ], + }, + panel: { + display: true, + + position: 'right', + options: { + enableToggle: true, + defaultTitle: '所有网格', + opened: true, + width: 426, + }, + children: [ + { + display: true, + type: 'meshName', + title: '网格名称', + }, + { + display: true, + type: 'activityTask', + title: '活动任务', + }, + ], + }, + toolbar: { + display: true, + children: [ + { + display: true, + position: 'left', + title: '全部活动', + type: 'activity', + }, + { + display: true, + position: 'left', + title: '全部状态', + type: 'status', + }, + { + display: true, + position: 'left', + title: '地图展示', + type: 'mapExhibit', + }, + { + display: true, + position: 'left', + title: '人员搜索', + type: 'searchPerson', + }, + { + display: true, + position: 'right', + title: '保存', + type: 'save', + }, + { + display: true, + position: 'right', + type: 'publishbar', + title: '发布', + event: { + actionType: 'map', + action: 'publish', + }, + }, + ], + }, + map: { + zoom: 10, + center: [120.153576, 30.287459], + pitch: 0, + style: 'normal', + }, + controls: [ + { + display: true, + position: 'bottomright', + type: 'mapStyle', + title: '地图样式', + }, + { + display: true, + position: 'rightcenter', + type: 'meshTools', + title: '网格工具', + }, + { + display: true, + position: 'bottomright', + type: 'location', + title: '定位', + }, + ], + defaultcontrols: [ + { + type: 'zoom', + position: 'bottomright', + display: true, + }, + { + type: 'scale', + position: 'bottomleft', + display: true, + }, + ], + popup: { + enable: false, + }, + layers: [ + { + type: 'gridLayer', + options: { + label: { + field: 'name', + size: 12, + color: '#000', + }, + + fill: { + field: 'unit_price', + color: ['#CFE1B9', '#B0C298', '#90A276', '#718355'], + unknownName: '无类型', + scale: { + type: 'cat', + domain: ['C', 'B', 'A'], + }, + }, + }, + }, + ], + legends: [], +}; diff --git a/site/components/task/configs/mock.ts b/site/components/task/configs/mock.ts new file mode 100644 index 0000000000..f91578ebcf --- /dev/null +++ b/site/components/task/configs/mock.ts @@ -0,0 +1,199 @@ +import Mock from 'mockjs'; + +export const chartList = Mock.mock({ + // 生成长度在 0~32 之间的小写字母 + success: '@string("lower", 0, 32)', + // 生成长度在 0~32 之间的小写字母 + errorMessage: '@string("lower", 0, 32)', + data: { + 'list|4-7': [ + { + // 生成长度在 100~1000 之间的小写字母 + xField: '@integer(100,1000)', + // 生成长度在 3~5 之间的中文 + yField: '@ctitle(3, 5)', + }, + ], + }, +}); + +export const personOption = () => { + const data = Mock.mock({ + 'list|10': [ + { + label: '@cname', + staffNo: '@integer(100000,1000000)', + value: '@integer(100000,1000000)' + }, + ], + }) + return data.list +} + +export const selectActivityItem = [ + { + label: '双十一赢金币', + value: '双十一赢金币', + icon: 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*JYNuSaNAga8AAAAAAAAAAAAAARQnAQ' + }, + { + label: '充电桩铺设', + value: '充电桩铺设', + icon: 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*eay2Q7nXeG4AAAAAAAAAAAAAARQnAQ' + }, + { + label: '1块钱升级月卡', + value: '1块钱升级月卡', + icon: 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*nA0vQbl_hGMAAAAAAAAAAAAAARQnAQ' + }, + { + label: '免费充电1小时', + value: '免费充电1小时', + icon: 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*snkKRYonMgEAAAAAAAAAAAAAARQnAQ' + }, +] + +export function randomData(data: T): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(data); + }, 500); + }); +} + +export const ActivityOption = [ + { label: '全部活动', value: '全部活动' }, + { label: '双十一赢金币', value: '双十一赢金币' }, + { label: '充电桩铺设', value: '充电桩铺设' }, + { label: '1块钱升级月卡', value: '1块钱升级月卡' }, + { label: '免费充电1小时', value: '免费充电1小时' } +] + +export const StatusOption = [ + { label: '全部状态', value: '全部状态' }, + { label: '未拓展', value: '未拓展' }, + { label: '已拓展', value: '已拓展' }, +] + +export const CityList = [ + { + value: '330000', + areaLevel: 'province', + label: '浙江省', + children: [ + { + value: '330100', + areaLevel: 'city', + label: '杭州市', + children: [], + }, + ], + }, + { + value: '110000', + areaLevel: 'province', + label: '北京市', + children: [ + { + value: '110000', + areaLevel: 'city', + label: '北京市', + children: [], + }, + ], + }, + { + value: '120000', + areaLevel: 'province', + label: '天津市', + children: [ + { + value: '120000', + areaLevel: 'city', + label: '天津市', + children: [], + }, + ], + }, + { + value: '310000', + areaLevel: 'province', + label: '上海市', + children: [ + { + value: '310000', + areaLevel: 'province', + label: '上海市', + children: [], + }, + ], + }, + { + value: '440000', + areaLevel: 'province', + label: '广东省', + children: [ + { + value: '440100', + areaLevel: 'city', + label: '广州市', + children: [], + }, + { + value: '440300', + areaLevel: 'city', + label: '深圳市', + children: [], + }, + { + value: '440400', + areaLevel: 'city', + label: '珠海市', + children: [], + }, + { + value: '440600', + areaLevel: 'city', + label: '佛山市', + children: [], + }, + { + value: '441300', + areaLevel: 'city', + label: '惠州市', + children: [], + }, + { + value: '441900', + areaLevel: 'city', + label: '东莞市', + children: [], + }, + { + value: '442000', + areaLevel: 'city', + label: '中山市', + children: [], + }, + ], + }, + { + value: '130000', + areaLevel: 'province', + label: '河北省', + children: [ + { + value: '130100', + areaLevel: 'city', + label: '石家庄市', + children: [], + }, + { + value: '131000', + areaLevel: 'city', + label: '廊坊市', + children: [], + }, + ], + }, +]; diff --git a/site/components/rumbling/index.tsx b/site/components/task/index.tsx similarity index 86% rename from site/components/rumbling/index.tsx rename to site/components/task/index.tsx index 2727bac06b..a3f5c06962 100644 --- a/site/components/rumbling/index.tsx +++ b/site/components/task/index.tsx @@ -2,6 +2,7 @@ import { initWidgets } from './widgets'; import React, { useEffect, useMemo, useState } from 'react'; import { config } from './configs/config'; import { DipperContainer, IConfig } from '@antv/dipper'; +import 'antd/dist/antd.css' interface IInitData { areaVOList: any[]; @@ -21,7 +22,7 @@ export default function RumbMap() { }, []); return ( -
+
cfg={mapConfig!} />
); diff --git a/site/components/task/widgets/Activity.tsx b/site/components/task/widgets/Activity.tsx new file mode 100644 index 0000000000..35964b621a --- /dev/null +++ b/site/components/task/widgets/Activity.tsx @@ -0,0 +1,25 @@ +import { Select } from 'antd'; +import React, { useState,useEffect } from 'react'; +import { ActivityOption } from '../configs/mock'; + +const { Option } = Select + +export function Activity() { + + const [active,setActive] = useState() + + useEffect(()=>{ + setActive(ActivityOption[0].value) + },[]) + + return( + + ) +} diff --git a/site/components/task/widgets/ActivityTask/index.module.css b/site/components/task/widgets/ActivityTask/index.module.css new file mode 100644 index 0000000000..6b4818609b --- /dev/null +++ b/site/components/task/widgets/ActivityTask/index.module.css @@ -0,0 +1,54 @@ +.selectactivity { + padding: 0 0 20px 20px ; +} +.selectactivity .select { + display: flex; + align-items: center; + flex-wrap: wrap; +} +.selectactivity .select .selectitem { + display: flex; + align-items: center; + width: 183px; + height: 64px; + margin: 0 15px 15px 0; + position: relative; + padding-left: 15px; +} +.selectactivity .select .selectitem .icon { + width: 40px; + height: 40px; + margin-right: 10px; +} +.selectactivity .select .selectitem .selecticon { + width: 21px; + height: 21px; + position: absolute; + right: 6px; + top: 6px; +} +.empty { + display: flex; + flex-direction: column; + align-items: center; + height: calc(674px - 80px); + justify-content: center; +} +.empty img { + width: 216px; + height: 132px; + margin-left: 100px; +} +.empty span { + color: rgba(0, 0, 0, 0.55); + margin-top: 20px; +} +.submit { + position: absolute; + bottom: 0; + right: 0; +} +.task { + height: calc(674px - 130px); + position: relative; +} diff --git a/site/components/task/widgets/ActivityTask/index.tsx b/site/components/task/widgets/ActivityTask/index.tsx new file mode 100644 index 0000000000..94955be8f8 --- /dev/null +++ b/site/components/task/widgets/ActivityTask/index.tsx @@ -0,0 +1,91 @@ +import React, { useState, useMemo } from 'react' +import { useLayerGroup } from '@antv/dipper' +import { Alert, Button, Select } from 'antd' +import { personOption, selectActivityItem } from '../../configs/mock' +import style from './index.module.css' + +const { Option } = Select + +export function ActivityTask() { + const selecticon = 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*kyI9T7Lrej4AAAAAAAAAAAAAARQnAQ' + const emptyicon = 'https://gw.alipayobjects.com/mdn/rms_58ab56/afts/img/A*H9dxSp69pi0AAAAAAAAAAAAAARQnAQ' + const { selectFeatures = [] } = useLayerGroup('grid') + const [current, setCurrent] = useState(selectActivityItem[0]?.value) + + const selectItem = (item) => { + setCurrent(item) + } + + const alertMsg = useMemo(() => { + if (selectFeatures.length === 2) { + return '勾选多个网格中,批量分配后将一起更新数据' + } + if (selectFeatures.length >= 3) { + return '你当前多选网格中包含已分配网格,无法批量分配,建议选择单个网格、或选择多个未分配网格的批量操作' + } + return ''; + }, [JSON.stringify(selectFeatures)]); + + const HasSelectFeature = () => { + return ( +
+
+ {selectFeatures.length >= 2 && } +
+
+

选择活动

+
+ {selectActivityItem && selectActivityItem.map((item) => { + return ( +
selectItem(item.value)} + style={{ + border: current === item.value ? '1px solid #1E73F8' : '1px solid rgba(0,0,0,0.15)', + }} + className={style.selectitem}> + + {item.label} + {current === item.value && } +
+ ) + })} +
+
+
+

分配人员

+ +
+
+ + +
+
+ ) + } + + const Empty = () => { + return ( +
+ + 暂无数据 +
+ ) + } + + return ( +
+ {!selectFeatures.length ? : } +
+ ) +} diff --git a/site/components/rumbling/widgets/GridLayer.tsx b/site/components/task/widgets/GridLayer.tsx similarity index 71% rename from site/components/rumbling/widgets/GridLayer.tsx rename to site/components/task/widgets/GridLayer.tsx index 138a2a6b67..0ee5096345 100644 --- a/site/components/rumbling/widgets/GridLayer.tsx +++ b/site/components/task/widgets/GridLayer.tsx @@ -34,15 +34,43 @@ export function GridLayer() { return layers.find((item: any) => item.type === 'gridLayer'); }, [layers]); + const testData = { + title: '图例', + items: [ + { + colors: ['#fef0d9', '#fdcc8a', '#fc8d59', '#e34a33', '#b30000'], + title: '已分配', + }, + { + colors: ['#f1eef6', '#bdc9e1', '#74a9cf', '#2b8cbe', '#045a8d'], + title: '未分配', + }, + ], + }; + const updateLayerLegend = (items: any[]) => { updateLegend('gridLayerLegend', { - type: 'discreteColor', + type: 'multiClassifyColor', display: true, position: 'bottomleft', options: { - targetName: '区域类型', + title: '网格', unkownName: layerProps.options.unkownName, - items, + items: [ + { + colors: ['#BEC3BD', '#A1A6A0', '#828681', '#646763'], + title: '已分配', + }, + { + colors: ['#CFE1B9', '#B0C298', '#90A276', '#718355'], + title: '未分配', + }, + ], + values: items.map((item) => { + return item.value.map((v) => { + return (v / 10000).toFixed(2); + }); + }), }, }); }; @@ -70,10 +98,18 @@ export function GridLayer() { return; } + const color = ['#CFE1B9','#B0C298','#90A276','#718355'] + const layer = new GridLayerGroup({ name: 'grid', - geodata: geoData, - options: layerProps.options, + data: geoData, + options: { + ...layerProps.options, + fill:{ + ...layerProps.options.fill, + color + } + }, }); layerService.addLayer(layer); diff --git a/site/components/task/widgets/MapExhibit/index.module.css b/site/components/task/widgets/MapExhibit/index.module.css new file mode 100644 index 0000000000..ac0a3cda7f --- /dev/null +++ b/site/components/task/widgets/MapExhibit/index.module.css @@ -0,0 +1,19 @@ +.exhibititem { + display: flex; + align-items: center; + justify-content: space-between; +} +.exhibititem :global .ant-switch-checked { + background-color: #1E73F8; +} +.dropdown { + border-left: 1px solid #f3f3f3; + border-right: 1px solid #f3f3f3; + padding: 0 10px; + height: 32px; + line-height: 32px; +} +.dropicon { + padding-left: 8px; + color: rgba(0, 0, 0, 0.25); +} diff --git a/site/components/task/widgets/MapExhibit/index.tsx b/site/components/task/widgets/MapExhibit/index.tsx new file mode 100644 index 0000000000..04b974271c --- /dev/null +++ b/site/components/task/widgets/MapExhibit/index.tsx @@ -0,0 +1,29 @@ +import { DownOutlined } from "@ant-design/icons"; +import { Dropdown, Menu, Switch } from "antd"; +import React from "react"; +import style from './index.module.css' + +export function MapExhibit() { + const onChange = (e) => { + // TODO 根据业务实现 + console.log(e) + } + const menu = ( + + +
+
地图放大展示分配人员
+ +
+
+
+ ); + + return ( + +
+ 地图展示 +
+
+ ) +} diff --git a/site/components/task/widgets/MeshName/index.module.css b/site/components/task/widgets/MeshName/index.module.css new file mode 100644 index 0000000000..a03ab39e9d --- /dev/null +++ b/site/components/task/widgets/MeshName/index.module.css @@ -0,0 +1,13 @@ +.meahname { + padding: 20px; +} +.closeicon { + padding: 0 8px; +} +.edit { + display: flex; + align-items: center; +} +.edit span:hover { + color: #1890ff; +} diff --git a/site/components/task/widgets/MeshName/index.tsx b/site/components/task/widgets/MeshName/index.tsx new file mode 100644 index 0000000000..0672803712 --- /dev/null +++ b/site/components/task/widgets/MeshName/index.tsx @@ -0,0 +1,83 @@ +import React, { useRef, useState, useMemo, useCallback } from 'react'; +import { CheckOutlined, CloseOutlined, EditOutlined } from '@ant-design/icons'; +import styles from './index.module.css' +import { Input } from 'antd'; +import { useLayerGroup } from '@antv/dipper'; + +export function MeshName() { + const { selectFeatures, updateProperties } = useLayerGroup('grid'); + const [edit, setEdit] = useState(false); + const ref = useRef(); + + /** + * get meshname + * type []string + */ + const meshName = useMemo(() => { + if (!selectFeatures.length) return []; + return selectFeatures.map((item) => { + // @ts-ignore + return item.feature.properties.name; + }); + }, [JSON.stringify(selectFeatures)]); + + // 修改 网格名称 + const editMeshName = useCallback(() => { + // @ts-ignore + const value = ref.current.state.value; + selectFeatures.forEach((item) => { + const properties = { + ...item.feature.properties, + name: value, + }; + updateProperties(item.feature, properties); + }); + setEdit(false); + }, [JSON.stringify(selectFeatures)]); + + // select more meshname 编辑 网格名称 + const EditMeshName = () => { + return ( + <> + {!edit ? ( +
setEdit(!edit)}> + {meshName} + +
+ ) : ( +
+ + + setEdit(false)} /> +
+ )} + + ); + }; + + // show 多个网格名称 + const ShowMeshNames = () => { + return ( +
+ {meshName.length >= 2 && meshName.map((s) => { + return ( + {s}, + ) + })} +
+ ); + }; + + return ( + <> + {meshName && meshName.length ? ( +
+ {meshName.length === 1 ? : } +
+ ) : null} + + ); +} diff --git a/site/components/task/widgets/MeshTools/SvgElement.tsx b/site/components/task/widgets/MeshTools/SvgElement.tsx new file mode 100644 index 0000000000..e1a2b3551b --- /dev/null +++ b/site/components/task/widgets/MeshTools/SvgElement.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +export function MeshSplitSvg() { + return ( +
+ + + +
+ ); +} + +export function MeshMergeSvg() { + return ( +
+ + 自动合并 + + + + + + + + + +
+ ); +} diff --git a/site/components/task/widgets/MeshTools/index.module.css b/site/components/task/widgets/MeshTools/index.module.css new file mode 100644 index 0000000000..c378ada7cb --- /dev/null +++ b/site/components/task/widgets/MeshTools/index.module.css @@ -0,0 +1,10 @@ +.meshTools{ + width: 32px; + height: 160px; + background: #fff; + border-radius: 2px; + display: flex; + flex-direction: column; + justify-content: space-between; + padding:15px 5px; +} diff --git a/site/components/task/widgets/MeshTools/index.tsx b/site/components/task/widgets/MeshTools/index.tsx new file mode 100644 index 0000000000..fe0ec54f47 --- /dev/null +++ b/site/components/task/widgets/MeshTools/index.tsx @@ -0,0 +1,82 @@ +import React, { useMemo, useState, useRef } from 'react'; +import styles from './index.module.css' +import { MeshSplitSvg, MeshMergeSvg } from './SvgElement'; +import { useLayerGroup } from '@antv/dipper' +import { Input, message, Modal, Popconfirm, Tooltip } from 'antd'; + + +export function MeshTools() { + const { selectFeatures = [] } = useLayerGroup('grid') + const [visible, setVisible] = useState(false) + const refs = useRef() + + const disable = { cursor: 'pointer', opacity: 1 } + const noDisable = { cursor: 'not-allowed', opacity: 0.25 } + + const cssPropsSplit = useMemo(() => { + if (selectFeatures.length === 1) return disable; + return noDisable; + }, [JSON.stringify(selectFeatures)]); + + const cssPropsMerge = useMemo(() => { + if (selectFeatures.length >= 2) { + return disable + } + return noDisable; + }, [JSON.stringify(selectFeatures)]); + + const splitMesh = () => { + // TODO 根据业务实现 + } + + const mergrMesh = () => { + // @ts-ignore + const value = refs.current.state.value + if (!value) { + return message.error('请输入要合并后的名称') + } + // TODO 根据业务实现 + setVisible(false) + } + + return ( +
+ + +
+ +
网格拆分
+
+
+ +
+ + = 2 ? '选择多个网格,可以合并' : null}> +
setVisible(true)}> + +
网格合并
+
+
+ + setVisible(false)} + > +

合并后的新网格名称

+ +
+ +
+ ) +} diff --git a/site/components/task/widgets/Save.tsx b/site/components/task/widgets/Save.tsx new file mode 100644 index 0000000000..cfaffaef62 --- /dev/null +++ b/site/components/task/widgets/Save.tsx @@ -0,0 +1,11 @@ +import { SaveOutlined } from '@ant-design/icons'; +import { Button } from 'antd'; +import React from 'react'; + +export function Save() { + return ( + + ); +} diff --git a/site/components/task/widgets/SearchPerson.tsx b/site/components/task/widgets/SearchPerson.tsx new file mode 100644 index 0000000000..5919b03c50 --- /dev/null +++ b/site/components/task/widgets/SearchPerson.tsx @@ -0,0 +1,60 @@ +import React, { useState, useEffect } from "react"; +import { Dropdown, Input, Menu, Select } from 'antd'; +import { SearchOutlined } from "@ant-design/icons"; +import { personOption } from "../configs/mock"; + +const { Search } = Input +const { Option } = Select + +// 此功能 仅做展示,以实际业务为准 +export function SearchPerson() { + + const [persons, setPersons] = useState([]) + const [visible, setVisible] = useState(false) + + const onSearch = (e) => { + const value = e.target.value + setTimeout(() => { + if (value) { + setPersons(personOption()) + setVisible(true) + } else { + setPersons([]) + setVisible(false) + } + + }, 300) + } + + // 人员搜索 + const onSelect = (value) =>{ + // TODO 根据业务实现 + } + + const menu = ( + + + {persons && persons.map((item) => { + return ( +
onSelect(item.value)} + style={{ paddingBottom: '5px' }} + >{item.label}
+ ) + })} +
+
+ ); + + return ( +
+ + } + onChange={onSearch} + /> + +
+ ) +} diff --git a/site/components/task/widgets/Send.tsx b/site/components/task/widgets/Send.tsx new file mode 100644 index 0000000000..8375aff6de --- /dev/null +++ b/site/components/task/widgets/Send.tsx @@ -0,0 +1,9 @@ +import { SendOutlined } from '@ant-design/icons'; +import { Button } from 'antd'; +import React from 'react'; + +export function Send() { + return( + + ) +} diff --git a/site/components/task/widgets/Status.tsx b/site/components/task/widgets/Status.tsx new file mode 100644 index 0000000000..f43d784f66 --- /dev/null +++ b/site/components/task/widgets/Status.tsx @@ -0,0 +1,25 @@ +import { Select } from 'antd'; +import React,{ useState,useEffect } from 'react'; +import { StatusOption } from '../configs/mock'; + +const { Option } = Select + +export function Status() { + + const [status,setStatus] = useState() + + useEffect(()=>{ + setStatus(StatusOption[0].value) + },[]) + + return( + + ) +} diff --git a/site/components/task/widgets/index.ts b/site/components/task/widgets/index.ts new file mode 100644 index 0000000000..4a21def18e --- /dev/null +++ b/site/components/task/widgets/index.ts @@ -0,0 +1,33 @@ +import { registerWidget } from '@antv/dipper-core'; +import { + CitySelect, + ClassifyColor, + DiscreteColor, +} from '@antv/dipper-widgets'; +import { Activity } from './Activity'; +import { ActivityTask } from './ActivityTask'; +import { GridLayer } from './GridLayer'; +import { MeshName } from './MeshName/index'; +import { Save } from './Save'; +import { SearchPerson } from './SearchPerson'; +import { Send } from './Send'; +import { Status } from './Status'; +import { MeshTools } from './MeshTools'; +import { MapExhibit } from './MapExhibit/index'; + +export function initWidgets() { + registerWidget('citySelect', CitySelect); + registerWidget('gridLayer', GridLayer); + registerWidget('classifyColor', ClassifyColor); + registerWidget('discreteColor', DiscreteColor); + registerWidget('meshName', MeshName); + registerWidget('meshTools',MeshTools) + + registerWidget('save', Save); + registerWidget('publishbar', Send); + registerWidget('activity', Activity); + registerWidget('status',Status); + registerWidget('mapExhibit', MapExhibit); + registerWidget('searchPerson',SearchPerson) + registerWidget('activityTask',ActivityTask) +} diff --git a/site/css/dipper.css b/site/css/dipper.css new file mode 100644 index 0000000000..c1b807fd3d --- /dev/null +++ b/site/css/dipper.css @@ -0,0 +1,58 @@ +.dippercontainer { + display: flex; + align-items: center; + flex-direction: column; + height: 538px; + justify-content: center; +} + +.title { + font-size: 30px; + font-family: 'PingFangSC-Semibold'; +} + +.subtitle { + font-size: 16px; + color: #697B8C; + font-family: 'PingFangSC-Regular'; + padding-top: 20px; +} + +.dipperdemo { + display: flex; +} + +.dipperitem { + display: flex; + flex-direction: column; + align-items: center; + min-width: 400px; + max-width: 600px; + margin:40px 20px; +} + +.dipperimg { + border-radius: 50%; + box-shadow: inset 0 0 16px 4px rgba(115, 108, 255, 0.44); + background-color: rgba(#746CFF, 0.24); + height: 180px; + width: 180px; + padding: 40px; +} + +.dipperitem:hover .dipperimg{ + padding: 32px; + border: 8px solid rgba(115, 108, 255, 0.08); + box-shadow: inset 0 0 16px 4px rgba(115, 108, 255, 0.44); +} + +.dippertitle { + font-size: 24px; + font-family: 'PingFangSC-Semibold'; + color: #0D1A26; + padding-top: 40px; +} + +.dipperitem:hover .dippertitle { + color: #873BF4; +} diff --git a/site/css/dippermap.css b/site/css/dippermap.css new file mode 100644 index 0000000000..dc6a2b634e --- /dev/null +++ b/site/css/dippermap.css @@ -0,0 +1,33 @@ +.dippermapcontainer{ + /* height: 656px; */ + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding-top: 68px; +} + +.title { + font-size: 30px; + font-family: 'PingFangSC-Semibold'; +} + +.subtitle { + font-size: 16px; + color: #697B8C; + font-family: 'PingFangSC-Regular'; + padding-top: 20px; +} +.carousel{ + width: 80%; + padding-top: 36px; +} +.carousel img{ + width: 100%; + height: 520px; + object-fit: cover; +} +.ant-carousel-vertical .slick-dots-right{ + right: -40px !important; + top: 100px; +} diff --git a/site/locale.json b/site/locale.json index abcafcebaf..14bcffb150 100644 --- a/site/locale.json +++ b/site/locale.json @@ -16,5 +16,8 @@ "深版精彩案例": "Dark Theme", "感谢信赖":"WE ARE TRUSTED BY", "新版发布" : "New Version", - "一个个真实的地理数据可视化案例,将复杂的地理数据,通过简单,易用的API接口,让用户达到开箱即用的效果。" : "We have summarized a series of story design templates from lots of real geospatial data visualization cases, so that users can use them directly." + "一个个真实的地理数据可视化案例,将复杂的地理数据,通过简单,易用的API接口,让用户达到开箱即用的效果。" : "We have summarized a series of story design templates from lots of real geospatial data visualization cases, so that users can use them directly.", + "指挥监控场景": "Command monitoring scene", + "指挥分配场景": "Command distribution scenario", + "可视化配置场景": "Visual configuration scenario" } diff --git a/site/pages/apps/home.tsx b/site/pages/apps/home.tsx deleted file mode 100644 index 0cff196ba5..0000000000 --- a/site/pages/apps/home.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; - -const Page: React.FC & { noLayout: boolean } = () =>

地图

; - -Page.noLayout = true; - -export default Page; \ No newline at end of file diff --git a/site/pages/index.zh.tsx b/site/pages/index.zh.tsx index 88a079e901..8dacae92fa 100644 --- a/site/pages/index.zh.tsx +++ b/site/pages/index.zh.tsx @@ -6,75 +6,15 @@ import Features from '@antv/gatsby-theme-antv/site/components/Features'; import SEO from '@antv/gatsby-theme-antv/site/components/Seo'; import React from 'react'; import { useTranslation } from 'react-i18next'; +import { useConfig } from './useConfig'; +import { Dipper } from '../components/Dipper'; +import { DipperMap } from '../components/DipperMap'; import '../css/home.css'; const IndexPage = () => { const { t, i18n } = useTranslation(); + const { L7Case, L7Features,notifications,companies, ecosystems} = useConfig(); - const features = [ - { - icon: - 'https://gw.alipayobjects.com/zos/basement_prod/ca2168d1-ae50-4929-8738-c6df62231de3.svg', - title: t('架构灵活且自由'), - description: t('支持地图底图,渲染引擎,图层自由定制、扩展,组合'), - }, - { - icon: - 'https://gw.alipayobjects.com/zos/basement_prod/0ccf4dcb-1bac-4f4e-8d8d-f1031c77c9c8.svg', - title: t('业务专业且通用'), - description: t( - '以图形符号学地理设计体系理论基础,易用、易理解、专业、专注', - ), - }, - { - icon: - 'https://gw.alipayobjects.com/zos/basement_prod/fd232581-14b3-45ec-a85c-fb349c51b376.svg', - title: t('视觉酷炫且动感'), - description: t('支持海量数据,2D、3D,动态,可交互,高性能渲染'), - }, - ]; - const companies = [ - { - name: '阿里云', - img: - 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*V_xMRIvw2iwAAAAAAAAAAABkARQnAQ', - }, - { - name: '支付宝', - img: - 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*lYDrRZvcvD4AAAAAAAAAAABkARQnAQ', - }, - { - name: '天猫', - img: - 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*BQrxRK6oemMAAAAAAAAAAABkARQnAQ', - }, - { - name: '淘宝网', - img: - 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*1l8-TqUr7UcAAAAAAAAAAABkARQnAQ', - }, - { - name: '网商银行', - img: - 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*ZAKFQJ5Bz4MAAAAAAAAAAABkARQnAQ', - }, - { - name: '盒马', - img: - 'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*ePJMQZCb8vkAAAAAAAAAAABkARQnAQ', - }, - { - name: 'yunos', - img: - 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*_js7SaNosUwAAAAAAAAAAABkARQnAQ', - }, - { - name: '菜鸟', - img: - 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*TgV-RZDODJIAAAAAAAAAAABkARQnAQ', - }, - ]; const bannerButtons = [ { text: t('图表示例'), @@ -87,43 +27,55 @@ const IndexPage = () => { }, ]; - const notifications = [ + + const dipper = [ { - type: t('推荐'), - title: t('如何制作不一样的疫情世界地图-酷炫、动感的地理可视化'), - date: '2020.03.12', - link: 'https://www.yuque.com/antv/blog/wigku2', + title: t('配置化'), + image: 'https://gw.alipayobjects.com/zos/bmw-prod/a8d32053-ef9d-485e-ae13-2b49535e6f4f.svg', + link: `/${i18n.language}/view` }, { - type: t('新版发布'), - title: t('L7 2.1 正式版'), - date: '2020.03.12', - link: ' https://www.yuque.com/antv/blog/ows55v', + title: t('组件化'), + image: 'https://gw.alipayobjects.com/zos/bmw-prod/4235cc53-ef5f-4a47-a33c-1623df19e4b7.svg', + link: `/${i18n.language}/task` }, + { + title: t('自由定制'), + image: 'https://gw.alipayobjects.com/zos/bmw-prod/29cbd68c-86ac-440c-a38d-792dbd8aea61.svg', + link: 'https://dippermap.alipay.com' + } ]; - const cases = [ + const dippermap = [ { - logo: - 'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*gjBmT56SDgsAAAAAAAAAAABkARQnAQ', - title: t('浅版精彩案例'), - description: t( - '一个个真实的地理数据可视化案例,将复杂的地理数据,通过简单,易用的API接口,让用户达到开箱即用的效果。', - ), - link: `/${i18n.language}/examples/gallery/basic`, - image: - 'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*h1vhT6eSVPkAAAAAAAAAAABkARQnAQ', + img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*6S8hQJAUB2oAAAAAAAAAAAAAARQnAQ', + alt: 'heat', + desc: '3D热力图', }, { - logo: - 'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*gjBmT56SDgsAAAAAAAAAAABkARQnAQ', - title: t('深版精彩案例'), - description: t( - '一个个真实的地理数据可视化案例,将复杂的地理数据,通过简单,易用的API接口,让用户达到开箱即用的效果。', - ), - link: `/${i18n.language}/examples/gallery/basic`, - image: - 'https://gw.alipayobjects.com/mdn/antv_site/afts/img/A*-gtxQbUPoGQAAAAAAAAAAABkARQnAQ', + img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*R8juSLJc86wAAAAAAAAAAAAAARQnAQ', + alt: '3DARC', + desc: '3D曲线', + }, + { + img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*MDmtT6lRS6EAAAAAAAAAAAAAARQnAQ', + alt: 'trip', + desc: '路径图', + }, + { + img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*lRdLQotjkKsAAAAAAAAAAAAAARQnAQ', + alt: 'point', + desc: '3D柱图', + }, + { + img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*W_DMQ5DVmIsAAAAAAAAAAAAAARQnAQ', + alt: 'polygon', + desc: '中国3D地图', + }, + { + img: 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*InJXT6G-l6UAAAAAAAAAAAAAARQnAQ', + alt: 'hex', + desc: '六边形图', }, ]; @@ -140,16 +92,19 @@ const IndexPage = () => { } title={t('L7 空间数据可视分析')} description={t( - '蚂蚁金服 AntV 数据可视化团队推出的基于 WebGL 的开源大规模地理空间数据可视分析开发框架。', + '蚂蚁金服 AntV 数据可视化团队推出的基于 WebGL 的开源大规模地理空间数据可视分析引擎。', )} buttons={bannerButtons} notifications={notifications} className="banner" githubStarLink="https://github.com/antvis/L7/stargazers" /> - - + + + + + ); }; diff --git a/site/pages/map.en.tsx b/site/pages/map.en.tsx deleted file mode 100644 index 72af948dfc..0000000000 --- a/site/pages/map.en.tsx +++ /dev/null @@ -1,2 +0,0 @@ -import Index from './map.zh'; -export default Index; diff --git a/site/pages/map.zh.tsx b/site/pages/map.zh.tsx index 6396d0754a..d12c056c84 100644 --- a/site/pages/map.zh.tsx +++ b/site/pages/map.zh.tsx @@ -1,6 +1,6 @@ import React from 'react'; import Loadable from "@loadable/component" -const Map = Loadable(() => import("../components/rumbling")) +const Map = Loadable(() => import("../components/analysis")) const Page: React.FC & { noLayout: boolean } = () => ; Page.noLayout = true; diff --git a/site/pages/task.en.tsx b/site/pages/task.en.tsx new file mode 100644 index 0000000000..e5d8e0bba6 --- /dev/null +++ b/site/pages/task.en.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import Loadable from "@loadable/component" +const Map = Loadable(() => import("../components/task")) +const Page: React.FC & { noLayout: boolean } = () => ; + +Page.noLayout = true; + +export default Page; \ No newline at end of file diff --git a/site/pages/task.zh.tsx b/site/pages/task.zh.tsx new file mode 100644 index 0000000000..f02b6a107e --- /dev/null +++ b/site/pages/task.zh.tsx @@ -0,0 +1,2 @@ +import Index from './task.en'; +export default Index; diff --git a/site/pages/useConfig.ts b/site/pages/useConfig.ts new file mode 100644 index 0000000000..5c3ecc2dbd --- /dev/null +++ b/site/pages/useConfig.ts @@ -0,0 +1,159 @@ +import { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; + +export const useConfig = () => { + const { t, i18n } = useTranslation(); + + // 通知 + const notifications = useMemo(() => { + return [{ + type: t('推荐'), + title: t('如何制作不一样的疫情世界地图-酷炫、动感的地理可视化'), + date: '2020.03.12', + link: 'https://www.yuque.com/antv/blog/wigku2', + }, + { + type: t('新版发布'), + title: t('L7 2.1 正式版'), + date: '2020.03.12', + link: ' https://www.yuque.com/antv/blog/ows55v', + }, + ]; + }, []); + + // L7 特性 + const L7Features = useMemo(() => { + return [ + { + icon: + 'https://gw.alipayobjects.com/zos/basement_prod/ca2168d1-ae50-4929-8738-c6df62231de3.svg', + title: t('架构灵活且自由'), + description: t('支持地图底图,渲染引擎,图层自由定制、扩展,组合'), + }, + { + icon: + 'https://gw.alipayobjects.com/zos/basement_prod/0ccf4dcb-1bac-4f4e-8d8d-f1031c77c9c8.svg', + title: t('业务专业且通用'), + description: t( + '以图形符号学地理设计体系理论基础,易用、易理解、专业、专注', + ), + }, + { + icon: + 'https://gw.alipayobjects.com/zos/basement_prod/fd232581-14b3-45ec-a85c-fb349c51b376.svg', + title: t('视觉酷炫且动感'), + description: t('支持海量数据,2D、3D,动态,可交互,高性能渲染'), + }, + ]; + + }, []) + + + const L7Case = useMemo(() => { + return [ + { + logo: + 'https://antv-2018.alipay.com/assets/image/icon/l7.svg', + title: t('指挥分配场景'), + description: t( + '区域化网格化数据管理指挥分配场景', + ), + link: `/${i18n.language}/task`, + image: + 'https://gw.alipayobjects.com/mdn/rms_08cc33/afts/img/A*CLJESKDO1g4AAAAAAAAAAAAAARQnAQ', + }, + { + logo: + 'https://antv-2018.alipay.com/assets/image/icon/l7.svg', + title: t('地图数据分析'), + description: t( + '区域化网格化数据分析场景', + ), + link: `/${i18n.language}/view`, + image: + 'https://gw.alipayobjects.com/mdn/rms_08cc33/afts/img/A*jb4tS7BiNo4AAAAAAAAAAAAAARQnAQ', + }, + { + logo: + 'https://gw.alipayobjects.com/zos/bmw-prod/222865fc-15e9-44b9-b726-444e1512d937.ico', + title: t('地理分析工具'), + description: t( + '地图可视化配置分析类场景', + ), + link: `/${i18n.language}/examples/gallery/basic`, + image: + 'https://gw.alipayobjects.com/mdn/rms_e7e1c6/afts/img/A*MPWKQqh54vwAAAAAAAAAAAAAARQnAQ', + }, + ] + + }, []) + const companies = useMemo(() => [{ + name: '阿里云', + img: + 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*V_xMRIvw2iwAAAAAAAAAAABkARQnAQ', + }, + { + name: '支付宝', + img: + 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*lYDrRZvcvD4AAAAAAAAAAABkARQnAQ', + }, + { + name: '天猫', + img: + 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*BQrxRK6oemMAAAAAAAAAAABkARQnAQ', + }, + { + name: '淘宝网', + img: + 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*1l8-TqUr7UcAAAAAAAAAAABkARQnAQ', + }, + { + name: '网商银行', + img: + 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*ZAKFQJ5Bz4MAAAAAAAAAAABkARQnAQ', + }, + { + name: '盒马', + img: + 'https://gw.alipayobjects.com/mdn/rms_f8c6a0/afts/img/A*ePJMQZCb8vkAAAAAAAAAAABkARQnAQ', + }, + { + name: 'yunos', + img: + 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*_js7SaNosUwAAAAAAAAAAABkARQnAQ', + }, + { + name: '菜鸟', + img: + 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*TgV-RZDODJIAAAAAAAAAAABkARQnAQ', + } + ], []); + + const ecosystems = useMemo(() => [{ + name: '阿里云', + img: + 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*V_xMRIvw2iwAAAAAAAAAAABkARQnAQ', + }, + { + name: '支付宝', + img: + 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*lYDrRZvcvD4AAAAAAAAAAABkARQnAQ', + }, + { + name: '天猫', + img: + 'https://gw.alipayobjects.com/mdn/rms_2274c3/afts/img/A*BQrxRK6oemMAAAAAAAAAAABkARQnAQ', + } + ], []); + + return { + ecosystems, + L7Features, + notifications, + companies, + L7Case, + } +} + + + diff --git a/site/pages/view.en.tsx b/site/pages/view.en.tsx new file mode 100644 index 0000000000..300b038621 --- /dev/null +++ b/site/pages/view.en.tsx @@ -0,0 +1,2 @@ +import Index from './view.zh'; +export default Index; diff --git a/site/pages/view.zh.tsx b/site/pages/view.zh.tsx new file mode 100644 index 0000000000..d12c056c84 --- /dev/null +++ b/site/pages/view.zh.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import Loadable from "@loadable/component" +const Map = Loadable(() => import("../components/analysis")) +const Page: React.FC & { noLayout: boolean } = () => ; + +Page.noLayout = true; + +export default Page; \ No newline at end of file