Commit e4002b20 by zhaochengxiang

资产运营

parent db73475b
...@@ -386,4 +386,28 @@ export function* listDistributeAbleUsersByName(payload) { ...@@ -386,4 +386,28 @@ export function* listDistributeAbleUsersByName(payload) {
export function* getMetadataColumns(payload) { export function* getMetadataColumns(payload) {
return yield call(metadataService.getMetadataColumns, payload) return yield call(metadataService.getMetadataColumns, payload)
}
export function* operationOverview() {
return yield call(service.operationOverview)
}
export function* getOperationSupportDataAssetStatisticsObject() {
return yield call(service.getOperationSupportDataAssetStatisticsObject)
}
export function* getOperationSupportResourceStatisticsObject() {
return yield call(service.getOperationSupportResourceStatisticsObject)
}
export function* operationCountByStatisticsObject(payload) {
return yield call(service.operationCountByStatisticsObject, payload)
}
export function* getOperationPopularDataAssetRanking() {
return yield call(service.getOperationPopularDataAssetRanking)
}
export function* getOperationLatestDataAssetRanking() {
return yield call(service.getOperationLatestDataAssetRanking)
} }
\ No newline at end of file
...@@ -374,4 +374,28 @@ export function getPreviewRangeByDirId(payload) { ...@@ -374,4 +374,28 @@ export function getPreviewRangeByDirId(payload) {
export function listDistributeAbleUsersByName(payload) { export function listDistributeAbleUsersByName(payload) {
return GetJSON("/dataassetmanager/userApi/listDistributeAbleUsersByName", payload) return GetJSON("/dataassetmanager/userApi/listDistributeAbleUsersByName", payload)
} }
\ No newline at end of file
export function operationOverview() {
return GetJSON("/dataassetmanager/operationApi/statisticalOverview")
}
export function getOperationSupportDataAssetStatisticsObject() {
return GetJSON("/dataassetmanager/operationApi/listSupportDataAssetStatisticsObject")
}
export function getOperationSupportResourceStatisticsObject() {
return GetJSON("/dataassetmanager/operationApi/listSupportResourceStatisticsObject")
}
export function operationCountByStatisticsObject(payload) {
return PostJSON("/dataassetmanager/operationApi/countByStatisticsObject", payload)
}
export function getOperationPopularDataAssetRanking() {
return GetJSON("/dataassetmanager/operationApi/getPopularDataAssetRanking")
}
export function getOperationLatestDataAssetRanking() {
return GetJSON("/dataassetmanager/operationApi/getLatestDataAssetRanking")
}
\ No newline at end of file
import React from 'react' import React from 'react'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import ResizeObserver from 'rc-resize-observer' import ResizeObserver from 'rc-resize-observer'
import { Row, Col, Card, Space, Divider, Badge, Select, DatePicker } from 'antd' import { Row, Col, Card, Space, Divider, Badge, Select, DatePicker, Spin, Tabs } from 'antd'
import produce from 'immer'
import Table from '../../../util/Component/Table' import Table from '../../../util/Component/Table'
import { dispatch } from '../../../model' import { dispatch } from '../../../model'
import './index.less' import './index.less'
const mockStatisticInfo = [ const overviewInformations = [
{ title: '内部资源', value: 12112 }, { title: '内部资源', key: 'innerResourceCount'},
{ title: '外部资源', value: 5609 }, { title: '外部资源', key: 'outerResourceCount'},
{ title: '已发布资产', value: 7174 }, { title: '已发布资产', key: 'publishedDataAssetCount'},
{ title: '未发布资产', value: 1309 }, { title: '未发布资产', key: 'unPublishedDataAssetCount'},
{ title: '梳理任务', value: 122 }, { title: '梳理任务', key: 'taskCount'},
] ]
const FC = (props) => { const FC = (props) => {
return ( return (
<div className='asset-operation p-3'> <div className='asset-operation'>
<Summary data={mockStatisticInfo} /> <Overview />
<div className='my-3'> <div className='my-3' style={{ overflow: 'hidden' }}>
<Row gutter={10}> <Row gutter={10}>
<Col span={12}> <Col span={12}>
<ResourceStatistic /> <Statistic type='resource' />
</Col> </Col>
<Col span={12}> <Col span={12}>
<AssetStatistic /> <Statistic />
</Col> </Col>
</Row> </Row>
</div> </div>
<div className='my-3'> <div style={{ overflow: 'hidden' }}>
<Row gutter={10}> <Row gutter={10}>
<Col span={12}> <Col span={12}>
<AssetBrowseRank /> <PopularAssetRank />
</Col> </Col>
<Col span={12}> <Col span={12}>
<AssetNewest /> <LatestAssetRank />
</Col> </Col>
</Row> </Row>
</div> </div>
...@@ -53,118 +54,209 @@ export const Header = ({ title }) => ( ...@@ -53,118 +54,209 @@ export const Header = ({ title }) => (
</Space> </Space>
) )
const Summary = ({ data }) => { const Overview = () => {
const [loading, setLoading] = React.useState(false)
const [data, setData] = React.useState()
const [contentWidth, setContentWidth] = React.useState() const [contentWidth, setContentWidth] = React.useState()
React.useEffect(() => {
getOverview()
}, [])
const colWidth = React.useMemo(() => { const colWidth = React.useMemo(() => {
const len = (data??[]).length const len = (overviewInformations??[]).length
if (contentWidth && len>0) { if (contentWidth && len>0) {
const len = (data??[]).length
return (contentWidth - (len-1)*10)/len return (contentWidth - (len-1)*10)/len
} }
return 0 return 0
}, [contentWidth, data]) }, [contentWidth])
const getOverview = () => {
setLoading(true)
dispatch({
type: 'assetmanage.operationOverview',
callback: data => {
setLoading(false)
setData(data)
},
error: () => {
setLoading(false)
}
})
}
return ( return (
<Card size='small'> <Spin spinning={loading}>
<Header title='资产数据概览' /> <Card size='small'>
<ResizeObserver <Header title='资产数据概览' />
onResize={({ width }) => { <ResizeObserver
setContentWidth(width) onResize={({ width }) => {
}} setContentWidth(width)
> }}
<div className='flex' style={{ justifyContent: 'space-between', alignItems: 'center' }}> >
{ <div className='flex' style={{ justifyContent: 'space-between', alignItems: 'center' }}>
data?.map((item, index) => { {
return ( (overviewInformations??[]).map((item, index) => {
<div key={index} style={{ width: colWidth }}> return (
<Card> <div key={item.key} style={{ width: colWidth }}>
<div <Card>
className='flex' <div
style={{ className='flex'
justifyContent: 'space-between', style={{
alignItems: 'center' justifyContent: 'space-between',
}} alignItems: 'center'
> }}
<span style={{ color: 'rgba(0, 0, 0, 0.45)' }}>{item.title}</span> >
<span style={{ color: 'rgba(0, 0, 0, 0.85)', fontSize: 24 }}>{item.value||0}</span> <span style={{ color: 'rgba(0, 0, 0, 0.45)' }}>{item.title}</span>
</div> <span style={{ color: 'rgba(0, 0, 0, 0.85)', fontSize: 24 }}>{data?.[item.key]}</span>
</Card> </div>
</div> </Card>
); </div>
}) );
} })
</div> }
</ResizeObserver> </div>
</Card> </ResizeObserver>
</Card>
</Spin>
) )
} }
const ResourceStatistic = () => { const Statistic = ({ type = 'dataAsset' }) => {
const mockOptions = [ const [loading, setLoading] = React.useState(false)
'按资源状态', const [loadingStatisticsObject, setLoadingStatisticsObject] = React.useState(false)
] const [statisticsObject, setStatisticsObject] = React.useState()
const [currentStatisticObject, setCurrentStatisticObject] = React.useState()
const [startTime, setStartTime] = React.useState()
const [endTime, setEndTime] = React.useState()
const [operationType, setOperationType] = React.useState()
const [data, setData] = React.useState()
React.useEffect(() => {
getStatisticsObject()
}, [])
React.useEffect(() => {
if (currentStatisticObject
&& (
(currentStatisticObject.groupByOperateTypes??[]).length===0
|| ((currentStatisticObject.groupByOperateTypes??[]).length>0&&operationType)
)
) {
getCount()
}
}, [currentStatisticObject, operationType, startTime, endTime])
const getStatisticsObject = () => {
setLoadingStatisticsObject(true)
dispatch({
type: (type==='dataAsset')?'assetmanage.getOperationSupportDataAssetStatisticsObject':'assetmanage.getOperationSupportResourceStatisticsObject',
callback: data => {
setLoadingStatisticsObject(false)
setStatisticsObject(data)
if ((data??[]).length > 0) {
const newCurrentStatisticObject = data[0]
setCurrentStatisticObject(newCurrentStatisticObject)
if ((newCurrentStatisticObject?.groupByOperateTypes??[]).length > 0) {
setOperationType(newCurrentStatisticObject?.groupByOperateTypes[0].type)
} else {
setOperationType()
}
}
},
error: () => {
setLoadingStatisticsObject(false)
}
})
}
const getCount = () => {
const newCurrentStatisticObject = produce(currentStatisticObject, (draft) => {
draft.beingTime = startTime
draft.endTime = endTime
for (let item of (draft.groupByOperateTypes??[])) {
item.selected = (item.type===operationType)
}
})
setLoading(true)
dispatch({
type: 'assetmanage.operationCountByStatisticsObject',
payload: {
data: newCurrentStatisticObject
},
callback: data => {
setLoading(false)
setData(data)
},
error: () => {
setLoading(false)
}
})
}
return ( return (
<Card size='small'> <Card size='small'>
<Header title='数据资源统计' /> <Header title={type==='dataAsset'?'数据资产统计':'数据资源统计'} />
<div className='flex mb-3' style={{ justifyContent: 'space-between', alignItems: 'center' }}> <div className='flex' style={{ justifyContent: 'space-between', alignItems: 'center' }}>
<Select <Select
loading={loadingStatisticsObject}
onChange={(value) => { onChange={(value) => {
const index = (statisticsObject??[]).findIndex(item => item.statisticsById===value)
if (index !== -1) {
const newCurrentStatisticObject = statisticsObject[index]
setCurrentStatisticObject(newCurrentStatisticObject)
if ((newCurrentStatisticObject?.groupByOperateTypes??[]).length > 0) {
setOperationType(newCurrentStatisticObject?.groupByOperateTypes[0].type)
} else {
setOperationType()
}
}
}} }}
value={currentStatisticObject?.statisticsById}
style={{ width: 140 }} style={{ width: 140 }}
> >
{ {
(mockOptions??[]).map((item, index) => <Select.Option key={index} value={item}>{item}</Select.Option>) (statisticsObject??[]).map((item, index) => <Select.Option key={item.statisticsById} value={item.statisticsById}>{item.statisticsByName}</Select.Option>)
} }
</Select> </Select>
<DatePicker.RangePicker <DatePicker.RangePicker
format="YYYY-MM-DD" format="YYYY-MM-DD"
onChange={(values) => { onChange={(values) => {
// setArgsAndPage({ startTime: (values??[]).length>0?values[0].valueOf():'', endTime: (values??[]).length>1?values[1].valueOf():'' }) setStartTime((values??[]).length>0?values[0].valueOf():'')
setEndTime((values??[]).length>1?values[1].valueOf():'')
}} }}
style={{ width: 240 }} style={{ width: 240 }}
/> />
</div> </div>
<StackedLine /> <div className='mb-3' style={{ height: 38 }}>
</Card> {
) (currentStatisticObject?.groupByOperateTypes??[]).length > 0 && <Tabs
} size='small'
activeKey={operationType}
const AssetStatistic = () => { onChange={(val) => {
const mockOptions = [ setOperationType(val)
'按资源状态',
]
return (
<Card size='small'>
<Header title='数据资产统计' />
<div className='flex mb-3' style={{ justifyContent: 'space-between', alignItems: 'center' }}>
<Select
onChange={(value) => {
}} }}
style={{ width: 140 }}
> >
{ {
(mockOptions??[]).map((item, index) => <Select.Option key={index} value={item}>{item}</Select.Option>) (currentStatisticObject?.groupByOperateTypes??[]).map((item, index) => {
return <Tabs.TabPane tab={item.name} key={item.type}></Tabs.TabPane>
})
} }
</Select> </Tabs>
<DatePicker.RangePicker }
format="YYYY-MM-DD"
onChange={(values) => {
// setArgsAndPage({ startTime: (values??[]).length>0?values[0].valueOf():'', endTime: (values??[]).length>1?values[1].valueOf():'' })
}}
style={{ width: 240 }}
/>
</div> </div>
<StackedLine /> <Spin spinning={loading}>
<StackedLine data={data} />
</Spin>
</Card> </Card>
) )
} }
const AssetBrowseRank = () => { const PopularAssetRank = () => {
const [loading, setLoading] = React.useState(false) const [loading, setLoading] = React.useState(false)
const [data, setData] = React.useState() const [data, setData] = React.useState()
const cols = [ const cols = [
...@@ -188,7 +280,7 @@ const AssetBrowseRank = () => { ...@@ -188,7 +280,7 @@ const AssetBrowseRank = () => {
}, },
{ {
title: '英文名', title: '英文名',
dataIndex: 'name', dataIndex: 'enName',
ellipsis: true, ellipsis: true,
}, },
{ {
...@@ -198,7 +290,7 @@ const AssetBrowseRank = () => { ...@@ -198,7 +290,7 @@ const AssetBrowseRank = () => {
}, },
{ {
title: '浏览次数', title: '浏览次数',
dataIndex: 'count', dataIndex: 'visitCount',
ellipsis: true, ellipsis: true,
}, },
] ]
...@@ -209,12 +301,16 @@ const AssetBrowseRank = () => { ...@@ -209,12 +301,16 @@ const AssetBrowseRank = () => {
const getRanks = () => { const getRanks = () => {
setLoading(true) setLoading(true)
setTimeout(() => { dispatch({
setLoading(false) type: 'assetmanage.getOperationPopularDataAssetRanking',
setData(Array.from({ length: 10 }).map((_, i) => ({ callback: data => {
setLoading(false)
}))) setData(data)
}, 1000) },
error: () => {
setLoading(false)
}
})
} }
return ( return (
...@@ -231,7 +327,7 @@ const AssetBrowseRank = () => { ...@@ -231,7 +327,7 @@ const AssetBrowseRank = () => {
) )
} }
const AssetNewest = () => { const LatestAssetRank = () => {
const [loading, setLoading] = React.useState(false) const [loading, setLoading] = React.useState(false)
const [data, setData] = React.useState() const [data, setData] = React.useState()
const cols = [ const cols = [
...@@ -255,7 +351,7 @@ const AssetNewest = () => { ...@@ -255,7 +351,7 @@ const AssetNewest = () => {
}, },
{ {
title: '英文名', title: '英文名',
dataIndex: 'name', dataIndex: 'enName',
ellipsis: true, ellipsis: true,
}, },
{ {
...@@ -265,7 +361,7 @@ const AssetNewest = () => { ...@@ -265,7 +361,7 @@ const AssetNewest = () => {
}, },
{ {
title: '发布时间', title: '发布时间',
dataIndex: 'time', dataIndex: 'createTime',
ellipsis: true, ellipsis: true,
}, },
] ]
...@@ -276,12 +372,16 @@ const AssetNewest = () => { ...@@ -276,12 +372,16 @@ const AssetNewest = () => {
const getRanks = () => { const getRanks = () => {
setLoading(true) setLoading(true)
setTimeout(() => { dispatch({
setLoading(false) type: 'assetmanage.getOperationLatestDataAssetRanking',
setData(Array.from({ length: 10 }).map((_, i) => ({ callback: data => {
setLoading(false)
}))) setData(data)
}, 1000) },
error: () => {
setLoading(false)
}
})
} }
return ( return (
...@@ -311,13 +411,23 @@ const StackedLine = ({ data }) => { ...@@ -311,13 +411,23 @@ const StackedLine = ({ data }) => {
}, [data]) }, [data])
const setOption = () => { const setOption = () => {
let serieNames = []
if ((data??[]).length === 0) {
echartsRef.current?.clear()
return
}
if ((data??[]).length > 0) {
serieNames = Object.keys(data[0]).filter(item => item !== 'date')
}
let option = { let option = {
tooltip: { tooltip: {
trigger: 'axis' trigger: 'axis'
}, },
legend: { legend: {
bottom: 0, bottom: 0,
data: ['Email', 'Union Ads', 'Video Ads', 'Direct', 'Search Engine'] data: serieNames
}, },
grid: { grid: {
left: '3%', left: '3%',
...@@ -328,44 +438,20 @@ const StackedLine = ({ data }) => { ...@@ -328,44 +438,20 @@ const StackedLine = ({ data }) => {
}, },
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: true,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] data: (data??[]).map(item => item.date)
}, },
yAxis: { yAxis: {
type: 'value' type: 'value'
}, },
series: [ series: (serieNames??[]).map(name => {
{ return ({
name: 'Email', name,
type: 'line', type: 'line',
stack: 'Total', stack: 'Total',
data: [120, 132, 101, 134, 90, 230, 210] data: (data??[]).map(item => item[`${name}`])
}, })
{ })
name: 'Union Ads',
type: 'line',
stack: 'Total',
data: [220, 182, 191, 234, 290, 330, 310]
},
{
name: 'Video Ads',
type: 'line',
stack: 'Total',
data: [150, 232, 201, 154, 190, 330, 410]
},
{
name: 'Direct',
type: 'line',
stack: 'Total',
data: [320, 332, 301, 334, 390, 330, 320]
},
{
name: 'Search Engine',
type: 'line',
stack: 'Total',
data: [820, 932, 901, 934, 1290, 1330, 1320]
}
]
} }
echartsRef.current?.setOption(option) echartsRef.current?.setOption(option)
} }
......
.asset-operation { .asset-operation {
height: 100%; height: 100%;
// background-color: white;
overflow: auto; overflow: auto;
.yy-tabs-nav::before {
border: none;
}
.yy-tabs-nav-wrap {
justify-content: flex-end;
}
} }
\ No newline at end of file
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