0.0.2.0
完成看板前端开发
This commit is contained in:
parent
811bcb0727
commit
08b7db297b
@ -86,7 +86,9 @@ CREATE TABLE `retry_task_log`
|
|||||||
`error_message` text NOT NULL COMMENT '异常信息',
|
`error_message` text NOT NULL COMMENT '异常信息',
|
||||||
PRIMARY KEY (`id`),
|
PRIMARY KEY (`id`),
|
||||||
KEY `idx_group_name` (`group_name`),
|
KEY `idx_group_name` (`group_name`),
|
||||||
KEY `idx_scene_name` (`scene_name`)
|
KEY `idx_scene_name` (`scene_name`),
|
||||||
|
KEY `idx_retry_status` (`retry_status`),
|
||||||
|
KEY `idx_biz_id` (`biz_id`),
|
||||||
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='重试日志表'
|
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='重试日志表'
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ import java.util.Objects;
|
|||||||
/**
|
/**
|
||||||
* RestTemplate 拦截器
|
* RestTemplate 拦截器
|
||||||
*
|
*
|
||||||
* @author: shuguang.zhang
|
* @author: www.byteblogs.com
|
||||||
* @date : 2022-04-17 15:22
|
* @date : 2022-04-17 15:22
|
||||||
*/
|
*/
|
||||||
public class ExampleClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
|
public class ExampleClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
package com.example.demo;
|
package com.example.demo;
|
||||||
|
|
||||||
import com.x.retry.client.core.client.request.BeatHttpRequestHandler;
|
|
||||||
import com.x.retry.client.core.strategy.RetryMethod;
|
import com.x.retry.client.core.strategy.RetryMethod;
|
||||||
import com.x.retry.common.core.model.Result;
|
|
||||||
import com.x.retry.common.core.util.JsonUtil;
|
import com.x.retry.common.core.util.JsonUtil;
|
||||||
import com.x.retry.server.model.dto.ConfigDTO;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -38,4 +38,4 @@ logging:
|
|||||||
|
|
||||||
x-retry:
|
x-retry:
|
||||||
server:
|
server:
|
||||||
host: 192.168.100.3
|
host: 127.0.0.1
|
||||||
|
@ -89,7 +89,7 @@ public class ExistsTransactionalRetryServiceTest {
|
|||||||
.thenReturn(new Result(0, "5"))
|
.thenReturn(new Result(0, "5"))
|
||||||
;
|
;
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < 400; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
threadPoolExecutor.execute(() -> testExistsTransactionalRetryService.testSimpleInsert(UUID.randomUUID().toString()));
|
threadPoolExecutor.execute(() -> testExistsTransactionalRetryService.testSimpleInsert(UUID.randomUUID().toString()));
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design-vue/pro-layout": "^1.0.11",
|
"@ant-design-vue/pro-layout": "^1.0.11",
|
||||||
"@antv/data-set": "^0.10.2",
|
"@antv/data-set": "^0.10.2",
|
||||||
|
"@antv/g2": "^3.5.1",
|
||||||
"ant-design-vue": "^1.7.6",
|
"ant-design-vue": "^1.7.6",
|
||||||
"axios": ">=0.21.1",
|
"axios": ">=0.21.1",
|
||||||
"core-js": "^3.1.2",
|
"core-js": "^3.1.2",
|
||||||
|
@ -24,11 +24,54 @@ const api = {
|
|||||||
notifyConfigList: '/notify-config/list',
|
notifyConfigList: '/notify-config/list',
|
||||||
userPageList: '/user/page/list',
|
userPageList: '/user/page/list',
|
||||||
saveUser: '/user',
|
saveUser: '/user',
|
||||||
systemUserByUserName: '/user/username/user-info'
|
systemUserByUserName: '/user/username/user-info',
|
||||||
|
countTask: '/dashboard/task/count',
|
||||||
|
countDispatch: '/dashboard/dispatch/count',
|
||||||
|
countActivePod: '/dashboard/active-pod/count',
|
||||||
|
rankSceneQuantity: '/dashboard/scene/rank',
|
||||||
|
lineDispatchQuantity: '/dashboard/dispatch/line'
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default api
|
export default api
|
||||||
|
|
||||||
|
export function getLineDispatchQuantity (parameter) {
|
||||||
|
return request({
|
||||||
|
url: api.lineDispatchQuantity,
|
||||||
|
method: 'get',
|
||||||
|
params: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rankSceneQuantity (parameter) {
|
||||||
|
return request({
|
||||||
|
url: api.rankSceneQuantity,
|
||||||
|
method: 'get',
|
||||||
|
params: parameter
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function countActivePod () {
|
||||||
|
return request({
|
||||||
|
url: api.countActivePod,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function countTask () {
|
||||||
|
return request({
|
||||||
|
url: api.countTask,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function countDispatch () {
|
||||||
|
return request({
|
||||||
|
url: api.countDispatch,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export function getGroupConfigForPage (parameter) {
|
export function getGroupConfigForPage (parameter) {
|
||||||
return request({
|
return request({
|
||||||
url: api.groupConfigForPage,
|
url: api.groupConfigForPage,
|
||||||
|
78
frontend/src/components/Charts/Line.vue
Normal file
78
frontend/src/components/Charts/Line.vue
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div id="viewData"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import * as G2 from '@antv/g2'
|
||||||
|
import { getLineDispatchQuantity } from '@/api/manage'
|
||||||
|
const DataSet = require('@antv/data-set')
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'G2Line',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
viewRecords: [],
|
||||||
|
chart: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.getLineDispatchQuantity()
|
||||||
|
this.createView()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getLineDispatchQuantity () {
|
||||||
|
getLineDispatchQuantity().then(res => {
|
||||||
|
this.viewCharts(res.data)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
viewCharts (viewRecords, type = 'day') {
|
||||||
|
var ds = new DataSet()
|
||||||
|
console.log(this.lineDispatchQuantity)
|
||||||
|
var dv = ds.createView().source(viewRecords)
|
||||||
|
dv.transform({
|
||||||
|
type: 'fold',
|
||||||
|
fields: ['success', 'fail'], // 展开字段集
|
||||||
|
key: 'name',
|
||||||
|
value: 'viewTotal',
|
||||||
|
retains: [ 'total', 'createDt' ]
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(dv.rows)
|
||||||
|
this.chart.source(dv, {
|
||||||
|
date: {
|
||||||
|
type: 'cat'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.chart.axis('viewTotal', {
|
||||||
|
label: {
|
||||||
|
textStyle: {
|
||||||
|
fill: '#aaaaaa'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.chart.tooltip({
|
||||||
|
crosshairs: {
|
||||||
|
type: 'line'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.chart.line().position('createDt*viewTotal').color('name', ['#1890ff', '#c28c62']).shape('smooth')
|
||||||
|
this.chart.point().position('createDt*viewTotal').color('name', ['#1890ff', '#c28c62']).size(4).shape('circle').style({
|
||||||
|
stroke: '#fff',
|
||||||
|
lineWidth: 1
|
||||||
|
})
|
||||||
|
|
||||||
|
this.chart.render()
|
||||||
|
},
|
||||||
|
createView () {
|
||||||
|
this.chart = new G2.Chart({
|
||||||
|
container: 'viewData',
|
||||||
|
forceFit: true,
|
||||||
|
height: 410,
|
||||||
|
padding: [20, 90, 60, 50]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -10,6 +10,7 @@ import Radar from '@/components/Charts/Radar'
|
|||||||
import RankList from '@/components/Charts/RankList'
|
import RankList from '@/components/Charts/RankList'
|
||||||
import TransferBar from '@/components/Charts/TransferBar'
|
import TransferBar from '@/components/Charts/TransferBar'
|
||||||
import TagCloud from '@/components/Charts/TagCloud'
|
import TagCloud from '@/components/Charts/TagCloud'
|
||||||
|
import G2Line from '@/components/Charts/Line'
|
||||||
|
|
||||||
// pro components
|
// pro components
|
||||||
import AvatarList from '@/components/AvatarList'
|
import AvatarList from '@/components/AvatarList'
|
||||||
@ -51,6 +52,7 @@ export {
|
|||||||
TagSelect,
|
TagSelect,
|
||||||
StandardFormRow,
|
StandardFormRow,
|
||||||
ArticleListContent,
|
ArticleListContent,
|
||||||
|
G2Line,
|
||||||
|
|
||||||
Dialog
|
Dialog
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
export default {
|
export default {
|
||||||
navTheme: 'dark', // theme for nav menu
|
navTheme: 'dark', // theme for nav menu
|
||||||
primaryColor: '#1890ff', // '#F5222D', // primary color of ant design
|
primaryColor: '#1890ff', // '#F5222D', // primary color of ant design
|
||||||
layout: 'sidemenu', // nav menu position: `sidemenu` or `topmenu`
|
layout: 'topmenu', // nav menu position: `sidemenu` or `topmenu`
|
||||||
contentWidth: 'Fluid', // layout of content: `Fluid` or `Fixed`, only works when layout is topmenu
|
contentWidth: 'Fixed', // layout of content: `Fluid` or `Fixed`, only works when layout is topmenu
|
||||||
fixedHeader: false, // sticky header
|
fixedHeader: false, // sticky header
|
||||||
fixSiderbar: false, // sticky siderbar
|
fixSiderbar: false, // sticky siderbar
|
||||||
colorWeak: false,
|
colorWeak: false,
|
||||||
|
@ -14,34 +14,22 @@ export const asyncRouterMap = [
|
|||||||
|
|
||||||
component: BasicLayout,
|
component: BasicLayout,
|
||||||
meta: { title: 'menu.home' },
|
meta: { title: 'menu.home' },
|
||||||
redirect: '/basic-config-list',
|
redirect: '/dashboard/workplace',
|
||||||
children: [
|
children: [
|
||||||
// dashboard
|
// dashboard
|
||||||
{
|
{
|
||||||
path: '/dashboard',
|
path: '/dashboard',
|
||||||
name: 'dashboard',
|
name: 'dashboard',
|
||||||
hidden: true,
|
redirect: '/dashboard/analysis',
|
||||||
redirect: '/dashboard/workplace',
|
hideChildrenInMenu: true,
|
||||||
component: RouteView,
|
component: RouteView,
|
||||||
meta: { title: 'menu.dashboard', keepAlive: true, icon: bxAnaalyse, permission: ['dashboard'] },
|
meta: { title: 'menu.dashboard', keepAlive: true, icon: bxAnaalyse, permission: ['dashboard'] },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/dashboard/analysis/:pageNo([1-9]\\d*)?',
|
path: '/dashboard/analysis',
|
||||||
name: 'Analysis',
|
name: 'Analysis',
|
||||||
component: () => import('@/views/dashboard/Analysis'),
|
component: () => import('@/views/dashboard/Analysis'),
|
||||||
meta: { title: 'menu.dashboard.analysis', keepAlive: false, permission: ['dashboard'] }
|
meta: { title: 'menu.dashboard.analysis', keepAlive: true, permission: ['dashboard'] }
|
||||||
},
|
|
||||||
// 外部链接
|
|
||||||
{
|
|
||||||
path: 'https://www.baidu.com/',
|
|
||||||
name: 'Monitor',
|
|
||||||
meta: { title: 'menu.dashboard.monitor', target: '_blank' }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/dashboard/workplace',
|
|
||||||
name: 'Workplace',
|
|
||||||
component: () => import('@/views/dashboard/Workplace'),
|
|
||||||
meta: { title: 'menu.dashboard.workplace', keepAlive: true, permission: ['dashboard'] }
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
export default {
|
export default {
|
||||||
'dashboard.analysis.test': '工专路 {no} 号店',
|
'dashboard.analysis.test': '工专路 {no} 号店',
|
||||||
'dashboard.analysis.introduce': '指标说明',
|
'dashboard.analysis.introduce': '指标说明',
|
||||||
'dashboard.analysis.total-sales': '总销售额',
|
'dashboard.analysis.total-sales': '总任务量',
|
||||||
'dashboard.analysis.day-sales': '日均销售额¥',
|
'dashboard.analysis.day-sales': '日均任务',
|
||||||
'dashboard.analysis.visits': '访问量',
|
'dashboard.analysis.visits': '访问量',
|
||||||
'dashboard.analysis.visits-trend': '访问量趋势',
|
'dashboard.analysis.visits-trend': '访问量趋势',
|
||||||
'dashboard.analysis.visits-ranking': '门店访问量排名',
|
'dashboard.analysis.visits-ranking': '门店访问量排名',
|
||||||
@ -13,7 +13,7 @@ export default {
|
|||||||
'dashboard.analysis.conversion-rate': '转化率',
|
'dashboard.analysis.conversion-rate': '转化率',
|
||||||
'dashboard.analysis.operational-effect': '运营活动效果',
|
'dashboard.analysis.operational-effect': '运营活动效果',
|
||||||
'dashboard.analysis.sales-trend': '销售趋势',
|
'dashboard.analysis.sales-trend': '销售趋势',
|
||||||
'dashboard.analysis.sales-ranking': '门店销售额排名',
|
'dashboard.analysis.sales-ranking': '异常重试量排名',
|
||||||
'dashboard.analysis.all-year': '全年',
|
'dashboard.analysis.all-year': '全年',
|
||||||
'dashboard.analysis.all-month': '本月',
|
'dashboard.analysis.all-month': '本月',
|
||||||
'dashboard.analysis.all-week': '本周',
|
'dashboard.analysis.all-week': '本周',
|
||||||
@ -27,7 +27,7 @@ export default {
|
|||||||
'dashboard.analysis.channel.all': '全部渠道',
|
'dashboard.analysis.channel.all': '全部渠道',
|
||||||
'dashboard.analysis.channel.online': '线上',
|
'dashboard.analysis.channel.online': '线上',
|
||||||
'dashboard.analysis.channel.stores': '门店',
|
'dashboard.analysis.channel.stores': '门店',
|
||||||
'dashboard.analysis.sales': '销售额',
|
'dashboard.analysis.sales': '调度',
|
||||||
'dashboard.analysis.traffic': '客流量',
|
'dashboard.analysis.traffic': '客流量',
|
||||||
'dashboard.analysis.table.rank': '排名',
|
'dashboard.analysis.table.rank': '排名',
|
||||||
'dashboard.analysis.table.search-keyword': '搜索关键词',
|
'dashboard.analysis.table.search-keyword': '搜索关键词',
|
||||||
|
@ -1,64 +1,47 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<a-row :gutter="24">
|
<a-row :gutter="24">
|
||||||
<a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
|
<a-col :sm="24" :md="12" :xl="8" :style="{ marginBottom: '24px' }">
|
||||||
<chart-card :loading="loading" :title="$t('dashboard.analysis.total-sales')" total="¥126,560">
|
<chart-card :loading="loading" :title="$t('dashboard.analysis.total-sales')" :total="taskQuantity.total">
|
||||||
<a-tooltip :title="$t('dashboard.analysis.introduce')" slot="action">
|
<a-tooltip :title="$t('dashboard.analysis.introduce')" slot="action">
|
||||||
<a-icon type="info-circle-o" />
|
<a-icon type="info-circle-o" />
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div>
|
<div>
|
||||||
<trend flag="up" style="margin-right: 16px;">
|
<span slot="term">完成</span>
|
||||||
<span slot="term">{{ $t('dashboard.analysis.week') }}</span>
|
{{ taskQuantity.finish }}
|
||||||
12%
|
<a-divider type="vertical" />
|
||||||
</trend>
|
<span slot="term">运行中</span>
|
||||||
<trend flag="down">
|
{{ taskQuantity.running }}
|
||||||
<span slot="term">{{ $t('dashboard.analysis.day') }}</span>
|
<a-divider type="vertical" />
|
||||||
11%
|
<span slot="term">最大次数</span>
|
||||||
</trend>
|
{{ taskQuantity.maxRetryCount }}
|
||||||
</div>
|
</div>
|
||||||
<template slot="footer">{{ $t('dashboard.analysis.day-sales') }}<span>¥ 234.56</span></template>
|
|
||||||
</chart-card>
|
</chart-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
|
<a-col :sm="24" :md="12" :xl="8" :style="{ marginBottom: '24px' }">
|
||||||
<chart-card :loading="loading" :title="$t('dashboard.analysis.visits')" :total="8846 | NumberFormat">
|
<chart-card :loading="loading" title="总调度量" :total="dispatchQuantity.total">
|
||||||
<a-tooltip :title="$t('dashboard.analysis.introduce')" slot="action">
|
<a-tooltip :title="$t('dashboard.analysis.introduce')" slot="action">
|
||||||
<a-icon type="info-circle-o" />
|
<a-icon type="info-circle-o" />
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div>
|
<div>
|
||||||
<mini-area />
|
<a-tooltip title="成功率">
|
||||||
|
<a-progress stroke-linecap="square" :percent="dispatchQuantity.successPercent" />
|
||||||
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<template slot="footer">{{ $t('dashboard.analysis.day-visits') }}<span> {{ '1234' | NumberFormat }}</span></template>
|
|
||||||
</chart-card>
|
</chart-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
|
<a-col :sm="24" :md="12" :xl="8" :style="{ marginBottom: '24px' }">
|
||||||
<chart-card :loading="loading" :title="$t('dashboard.analysis.payments')" :total="6560 | NumberFormat">
|
<chart-card :loading="loading" title="总在线机器" :total="countActivePodQuantity.total">
|
||||||
<a-tooltip :title="$t('dashboard.analysis.introduce')" slot="action">
|
<a-tooltip :title="$t('dashboard.analysis.introduce')" slot="action">
|
||||||
<a-icon type="info-circle-o" />
|
<a-icon type="info-circle-o" />
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div>
|
<div>
|
||||||
<mini-bar />
|
<span slot="term">客户端</span>
|
||||||
|
{{ countActivePodQuantity.clientTotal }}
|
||||||
|
<a-divider type="vertical" />
|
||||||
|
<span slot="term">服务端</span>
|
||||||
|
{{ countActivePodQuantity.serverTotal }}
|
||||||
</div>
|
</div>
|
||||||
<template slot="footer">{{ $t('dashboard.analysis.conversion-rate') }} <span>60%</span></template>
|
|
||||||
</chart-card>
|
|
||||||
</a-col>
|
|
||||||
<a-col :sm="24" :md="12" :xl="6" :style="{ marginBottom: '24px' }">
|
|
||||||
<chart-card :loading="loading" :title="$t('dashboard.analysis.operational-effect')" total="78%">
|
|
||||||
<a-tooltip :title="$t('dashboard.analysis.introduce')" slot="action">
|
|
||||||
<a-icon type="info-circle-o" />
|
|
||||||
</a-tooltip>
|
|
||||||
<div>
|
|
||||||
<mini-progress color="rgb(19, 194, 194)" :target="80" :percentage="78" height="8px" />
|
|
||||||
</div>
|
|
||||||
<template slot="footer">
|
|
||||||
<trend flag="down" style="margin-right: 16px;">
|
|
||||||
<span slot="term">{{ $t('dashboard.analysis.week') }}</span>
|
|
||||||
12%
|
|
||||||
</trend>
|
|
||||||
<trend flag="up">
|
|
||||||
<span slot="term">{{ $t('dashboard.analysis.day') }}</span>
|
|
||||||
80%
|
|
||||||
</trend>
|
|
||||||
</template>
|
|
||||||
</chart-card>
|
</chart-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
@ -73,146 +56,31 @@
|
|||||||
<a>{{ $t('dashboard.analysis.all-month') }}</a>
|
<a>{{ $t('dashboard.analysis.all-month') }}</a>
|
||||||
<a>{{ $t('dashboard.analysis.all-year') }}</a>
|
<a>{{ $t('dashboard.analysis.all-year') }}</a>
|
||||||
</div>
|
</div>
|
||||||
<a-range-picker :style="{width: '256px'}" />
|
<div class="extra-item">
|
||||||
|
<a-range-picker :style="{width: '256px'}" />
|
||||||
|
</div>
|
||||||
|
<a-select placeholder="请输入组名称" @change="value => handleChange(value)" :style="{width: '256px'}">
|
||||||
|
<a-select-option v-for="item in groupNameList" :value="item" :key="item">{{ item }}</a-select-option>
|
||||||
|
</a-select>
|
||||||
</div>
|
</div>
|
||||||
<a-tab-pane loading="true" :tab="$t('dashboard.analysis.sales')" key="1">
|
<a-tab-pane loading="true" :tab="$t('dashboard.analysis.sales')" key="1">
|
||||||
<a-row>
|
<a-row>
|
||||||
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
|
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
|
||||||
<bar :data="barData" :title="$t('dashboard.analysis.sales-trend')" />
|
<g2-line/>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
|
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
|
||||||
<rank-list :title="$t('dashboard.analysis.sales-ranking')" :list="rankList"/>
|
<rank-list :title="$t('dashboard.analysis.sales-ranking')" :list="rankList"/>
|
||||||
</a-col>
|
</a-col>
|
||||||
</a-row>
|
</a-row>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane :tab="$t('dashboard.analysis.visits')" key="2">
|
|
||||||
<a-row>
|
|
||||||
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
|
|
||||||
<bar :data="barData2" :title="$t('dashboard.analysis.visits-trend')" />
|
|
||||||
</a-col>
|
|
||||||
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
|
|
||||||
<rank-list :title="$t('dashboard.analysis.visits-ranking')" :list="rankList"/>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</a-tab-pane>
|
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</div>
|
</div>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
<div class="antd-pro-pages-dashboard-analysis-twoColLayout" :class="!isMobile && 'desktop'">
|
|
||||||
<a-row :gutter="24" type="flex" :style="{ marginTop: '24px' }">
|
|
||||||
<a-col :xl="12" :lg="24" :md="24" :sm="24" :xs="24">
|
|
||||||
<a-card :loading="loading" :bordered="false" :title="$t('dashboard.analysis.online-top-search')" :style="{ height: '100%' }">
|
|
||||||
<a-dropdown :trigger="['click']" placement="bottomLeft" slot="extra">
|
|
||||||
<a class="ant-dropdown-link" href="#">
|
|
||||||
<a-icon type="ellipsis" />
|
|
||||||
</a>
|
|
||||||
<a-menu slot="overlay">
|
|
||||||
<a-menu-item>
|
|
||||||
<a href="javascript:;">{{ $t('dashboard.analysis.dropdown-option-one') }}</a>
|
|
||||||
</a-menu-item>
|
|
||||||
<a-menu-item>
|
|
||||||
<a href="javascript:;">{{ $t('dashboard.analysis.dropdown-option-two') }}</a>
|
|
||||||
</a-menu-item>
|
|
||||||
</a-menu>
|
|
||||||
</a-dropdown>
|
|
||||||
<a-row :gutter="68">
|
|
||||||
<a-col :xs="24" :sm="12" :style="{ marginBottom: ' 24px'}">
|
|
||||||
<number-info :total="12321" :sub-total="17.1">
|
|
||||||
<span slot="subtitle">
|
|
||||||
<span>{{ $t('dashboard.analysis.search-users') }}</span>
|
|
||||||
<a-tooltip :title="$t('dashboard.analysis.introduce')" slot="action">
|
|
||||||
<a-icon type="info-circle-o" :style="{ marginLeft: '8px' }" />
|
|
||||||
</a-tooltip>
|
|
||||||
</span>
|
|
||||||
</number-info>
|
|
||||||
<!-- miniChart -->
|
|
||||||
<div>
|
|
||||||
<mini-smooth-area :style="{ height: '45px' }" :dataSource="searchUserData" :scale="searchUserScale" />
|
|
||||||
</div>
|
|
||||||
</a-col>
|
|
||||||
<a-col :xs="24" :sm="12" :style="{ marginBottom: ' 24px'}">
|
|
||||||
<number-info :total="2.7" :sub-total="26.2" status="down">
|
|
||||||
<span slot="subtitle">
|
|
||||||
<span>{{ $t('dashboard.analysis.per-capita-search') }}</span>
|
|
||||||
<a-tooltip :title="$t('dashboard.analysis.introduce')" slot="action">
|
|
||||||
<a-icon type="info-circle-o" :style="{ marginLeft: '8px' }" />
|
|
||||||
</a-tooltip>
|
|
||||||
</span>
|
|
||||||
</number-info>
|
|
||||||
<!-- miniChart -->
|
|
||||||
<div>
|
|
||||||
<mini-smooth-area :style="{ height: '45px' }" :dataSource="searchUserData" :scale="searchUserScale" />
|
|
||||||
</div>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
<div class="ant-table-wrapper">
|
|
||||||
<a-table
|
|
||||||
row-key="index"
|
|
||||||
size="small"
|
|
||||||
:columns="searchTableColumns"
|
|
||||||
:dataSource="searchData"
|
|
||||||
:pagination="{ pageSize: 5 }"
|
|
||||||
>
|
|
||||||
<span slot="range" slot-scope="text, record">
|
|
||||||
<trend :flag="record.status === 0 ? 'up' : 'down'">
|
|
||||||
{{ text }}%
|
|
||||||
</trend>
|
|
||||||
</span>
|
|
||||||
</a-table>
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</a-col>
|
|
||||||
<a-col :xl="12" :lg="24" :md="24" :sm="24" :xs="24">
|
|
||||||
<a-card class="antd-pro-pages-dashboard-analysis-salesCard" :loading="loading" :bordered="false" :title="$t('dashboard.analysis.the-proportion-of-sales')" :style="{ height: '100%' }">
|
|
||||||
<div slot="extra" style="height: inherit;">
|
|
||||||
<!-- style="bottom: 12px;display: inline-block;" -->
|
|
||||||
<span class="dashboard-analysis-iconGroup">
|
|
||||||
<a-dropdown :trigger="['click']" placement="bottomLeft">
|
|
||||||
<a-icon type="ellipsis" class="ant-dropdown-link" />
|
|
||||||
<a-menu slot="overlay">
|
|
||||||
<a-menu-item>
|
|
||||||
<a href="javascript:;">{{ $t('dashboard.analysis.dropdown-option-one') }}</a>
|
|
||||||
</a-menu-item>
|
|
||||||
<a-menu-item>
|
|
||||||
<a href="javascript:;">{{ $t('dashboard.analysis.dropdown-option-two') }}</a>
|
|
||||||
</a-menu-item>
|
|
||||||
</a-menu>
|
|
||||||
</a-dropdown>
|
|
||||||
</span>
|
|
||||||
<div class="analysis-salesTypeRadio">
|
|
||||||
<a-radio-group defaultValue="a">
|
|
||||||
<a-radio-button value="a">{{ $t('dashboard.analysis.channel.all') }}</a-radio-button>
|
|
||||||
<a-radio-button value="b">{{ $t('dashboard.analysis.channel.online') }}</a-radio-button>
|
|
||||||
<a-radio-button value="c">{{ $t('dashboard.analysis.channel.stores') }}</a-radio-button>
|
|
||||||
</a-radio-group>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<h4>{{ $t('dashboard.analysis.sales') }}</h4>
|
|
||||||
<div>
|
|
||||||
<!-- style="width: calc(100% - 240px);" -->
|
|
||||||
<div>
|
|
||||||
<v-chart :force-fit="true" :height="405" :data="pieData" :scale="pieScale">
|
|
||||||
<v-tooltip :showTitle="false" dataKey="item*percent" />
|
|
||||||
<v-axis />
|
|
||||||
<!-- position="right" :offsetX="-140" -->
|
|
||||||
<v-legend dataKey="item"/>
|
|
||||||
<v-pie position="percent" color="item" :vStyle="pieStyle" />
|
|
||||||
<v-coord type="theta" :radius="0.75" :innerRadius="0.6" />
|
|
||||||
</v-chart>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</a-card>
|
|
||||||
</a-col>
|
|
||||||
</a-row>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import moment from 'moment'
|
// import moment from 'moment'
|
||||||
import {
|
import {
|
||||||
ChartCard,
|
ChartCard,
|
||||||
MiniArea,
|
MiniArea,
|
||||||
@ -220,88 +88,12 @@ import {
|
|||||||
MiniProgress,
|
MiniProgress,
|
||||||
RankList,
|
RankList,
|
||||||
Bar,
|
Bar,
|
||||||
Trend,
|
|
||||||
NumberInfo,
|
NumberInfo,
|
||||||
MiniSmoothArea
|
MiniSmoothArea,
|
||||||
|
G2Line
|
||||||
} from '@/components'
|
} from '@/components'
|
||||||
import { baseMixin } from '@/store/app-mixin'
|
import { baseMixin } from '@/store/app-mixin'
|
||||||
|
import { getAllGroupNameList, countTask, countDispatch, countActivePod, rankSceneQuantity } from '@/api/manage'
|
||||||
const barData = []
|
|
||||||
const barData2 = []
|
|
||||||
for (let i = 0; i < 12; i += 1) {
|
|
||||||
barData.push({
|
|
||||||
x: `${i + 1}月`,
|
|
||||||
y: Math.floor(Math.random() * 1000) + 200
|
|
||||||
})
|
|
||||||
barData2.push({
|
|
||||||
x: `${i + 1}月`,
|
|
||||||
y: Math.floor(Math.random() * 1000) + 200
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const rankList = []
|
|
||||||
for (let i = 0; i < 7; i++) {
|
|
||||||
rankList.push({
|
|
||||||
name: '白鹭岛 ' + (i + 1) + ' 号店',
|
|
||||||
total: 1234.56 - i * 100
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const searchUserData = []
|
|
||||||
for (let i = 0; i < 7; i++) {
|
|
||||||
searchUserData.push({
|
|
||||||
x: moment().add(i, 'days').format('YYYY-MM-DD'),
|
|
||||||
y: Math.ceil(Math.random() * 10)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const searchUserScale = [
|
|
||||||
{
|
|
||||||
dataKey: 'x',
|
|
||||||
alias: '时间'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataKey: 'y',
|
|
||||||
alias: '用户数',
|
|
||||||
min: 0,
|
|
||||||
max: 10
|
|
||||||
}]
|
|
||||||
|
|
||||||
const searchData = []
|
|
||||||
for (let i = 0; i < 50; i += 1) {
|
|
||||||
searchData.push({
|
|
||||||
index: i + 1,
|
|
||||||
keyword: `搜索关键词-${i}`,
|
|
||||||
count: Math.floor(Math.random() * 1000),
|
|
||||||
range: Math.floor(Math.random() * 100),
|
|
||||||
status: Math.floor((Math.random() * 10) % 2)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const DataSet = require('@antv/data-set')
|
|
||||||
|
|
||||||
const sourceData = [
|
|
||||||
{ item: '家用电器', count: 32.2 },
|
|
||||||
{ item: '食用酒水', count: 21 },
|
|
||||||
{ item: '个护健康', count: 17 },
|
|
||||||
{ item: '服饰箱包', count: 13 },
|
|
||||||
{ item: '母婴产品', count: 9 },
|
|
||||||
{ item: '其他', count: 7.8 }
|
|
||||||
]
|
|
||||||
|
|
||||||
const pieScale = [{
|
|
||||||
dataKey: 'percent',
|
|
||||||
min: 0,
|
|
||||||
formatter: '.0%'
|
|
||||||
}]
|
|
||||||
|
|
||||||
const dv = new DataSet.View().source(sourceData)
|
|
||||||
dv.transform({
|
|
||||||
type: 'percent',
|
|
||||||
field: 'count',
|
|
||||||
dimension: 'item',
|
|
||||||
as: 'percent'
|
|
||||||
})
|
|
||||||
const pieData = dv.rows
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'Analysis',
|
name: 'Analysis',
|
||||||
@ -313,27 +105,30 @@ export default {
|
|||||||
MiniProgress,
|
MiniProgress,
|
||||||
RankList,
|
RankList,
|
||||||
Bar,
|
Bar,
|
||||||
Trend,
|
|
||||||
NumberInfo,
|
NumberInfo,
|
||||||
MiniSmoothArea
|
MiniSmoothArea,
|
||||||
|
G2Line
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
loading: true,
|
loading: true,
|
||||||
rankList,
|
rankList: [],
|
||||||
|
groupNameList: [],
|
||||||
// 搜索用户数
|
taskQuantity: {
|
||||||
searchUserData,
|
total: 0,
|
||||||
searchUserScale,
|
running: 0,
|
||||||
searchData,
|
finish: 0,
|
||||||
|
maxRetryCount: 0
|
||||||
barData,
|
},
|
||||||
barData2,
|
dispatchQuantity: {
|
||||||
|
successPercent: '0',
|
||||||
//
|
total: 0
|
||||||
pieScale,
|
},
|
||||||
pieData,
|
countActivePodQuantity: {
|
||||||
sourceData,
|
clientTotal: 0,
|
||||||
|
serverTotal: 0,
|
||||||
|
total: 0
|
||||||
|
},
|
||||||
pieStyle: {
|
pieStyle: {
|
||||||
stroke: '#fff',
|
stroke: '#fff',
|
||||||
lineWidth: 1
|
lineWidth: 1
|
||||||
@ -341,32 +136,35 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
searchTableColumns () {
|
},
|
||||||
return [
|
methods: {
|
||||||
{
|
|
||||||
dataIndex: 'index',
|
|
||||||
title: this.$t('dashboard.analysis.table.rank'),
|
|
||||||
width: 90
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataIndex: 'keyword',
|
|
||||||
title: this.$t('dashboard.analysis.table.search-keyword')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataIndex: 'count',
|
|
||||||
title: this.$t('dashboard.analysis.table.users')
|
|
||||||
},
|
|
||||||
{
|
|
||||||
dataIndex: 'range',
|
|
||||||
title: this.$t('dashboard.analysis.table.weekly-range'),
|
|
||||||
align: 'right',
|
|
||||||
sorter: (a, b) => a.range - b.range,
|
|
||||||
scopedSlots: { customRender: 'range' }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
|
getAllGroupNameList().then(res => {
|
||||||
|
this.groupNameList = res.data
|
||||||
|
})
|
||||||
|
|
||||||
|
countTask().then(res => {
|
||||||
|
this.taskQuantity = res.data
|
||||||
|
})
|
||||||
|
|
||||||
|
countDispatch().then(res => {
|
||||||
|
this.dispatchQuantity = res.data
|
||||||
|
})
|
||||||
|
|
||||||
|
countActivePod().then(res => {
|
||||||
|
this.countActivePodQuantity = res.data
|
||||||
|
})
|
||||||
|
|
||||||
|
rankSceneQuantity().then(res => {
|
||||||
|
res.data.forEach(res => {
|
||||||
|
this.rankList.push({
|
||||||
|
name: res.groupName + '/' + res.sceneName,
|
||||||
|
total: res.total
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.loading = !this.loading
|
this.loading = !this.loading
|
||||||
}, 1000)
|
}, 1000)
|
||||||
|
@ -21,7 +21,7 @@ import java.util.Objects;
|
|||||||
/**
|
/**
|
||||||
* 请求头和响应头传递
|
* 请求头和响应头传递
|
||||||
*
|
*
|
||||||
* @author: shuguang.zhang
|
* @author: www.byteblogs.com
|
||||||
* @date : 2022-04-18 09:19
|
* @date : 2022-04-18 09:19
|
||||||
*/
|
*/
|
||||||
@Aspect
|
@Aspect
|
||||||
|
@ -5,7 +5,7 @@ import lombok.Data;
|
|||||||
/**
|
/**
|
||||||
* x-retry 请求头信息
|
* x-retry 请求头信息
|
||||||
*
|
*
|
||||||
* @author: shuguang.zhang
|
* @author: www.byteblogs.com
|
||||||
* @date : 2022-04-16 22:20
|
* @date : 2022-04-16 22:20
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
|
@ -2,6 +2,12 @@ package com.x.retry.server.persistence.mybatis.mapper;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.x.retry.server.persistence.mybatis.po.RetryTaskLog;
|
import com.x.retry.server.persistence.mybatis.po.RetryTaskLog;
|
||||||
|
import com.x.retry.server.web.model.response.ActivePodQuantityResponseVO;
|
||||||
|
import com.x.retry.server.web.model.response.DispatchQuantityResponseVO;
|
||||||
|
import com.x.retry.server.web.model.response.SceneQuantityRankResponseVO;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface RetryTaskLogMapper extends BaseMapper<RetryTaskLog> {
|
public interface RetryTaskLogMapper extends BaseMapper<RetryTaskLog> {
|
||||||
|
|
||||||
@ -9,4 +15,13 @@ public interface RetryTaskLogMapper extends BaseMapper<RetryTaskLog> {
|
|||||||
|
|
||||||
RetryTaskLog selectByPrimaryKey(Long id);
|
RetryTaskLog selectByPrimaryKey(Long id);
|
||||||
|
|
||||||
}
|
long countTaskTotal();
|
||||||
|
|
||||||
|
long countTaskByRetryStatus(@Param("retryStatus") Integer retryStatus);
|
||||||
|
|
||||||
|
List<SceneQuantityRankResponseVO> rankSceneQuantity(@Param("groupName") String groupName);
|
||||||
|
|
||||||
|
List<DispatchQuantityResponseVO> lineDispatchQuantity(@Param("groupName") String groupName,
|
||||||
|
@Param("retryStatus") Integer retryStatus);
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.x.retry.server.service;
|
||||||
|
|
||||||
|
import com.x.retry.server.web.model.response.ActivePodQuantityResponseVO;
|
||||||
|
import com.x.retry.server.web.model.response.DispatchQuantityResponseVO;
|
||||||
|
import com.x.retry.server.web.model.response.SceneQuantityRankResponseVO;
|
||||||
|
import com.x.retry.server.web.model.response.TaskQuantityResponseVO;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: www.byteblogs.com
|
||||||
|
* @date : 2022-04-22 20:19
|
||||||
|
*/
|
||||||
|
public interface DashBoardService {
|
||||||
|
|
||||||
|
TaskQuantityResponseVO countTask();
|
||||||
|
|
||||||
|
DispatchQuantityResponseVO countDispatch();
|
||||||
|
|
||||||
|
ActivePodQuantityResponseVO countActivePod();
|
||||||
|
|
||||||
|
List<SceneQuantityRankResponseVO> rankSceneQuantity(String groupName);
|
||||||
|
|
||||||
|
List<DispatchQuantityResponseVO> lineDispatchQuantity(String groupName);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
package com.x.retry.server.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.x.retry.common.core.enums.NodeTypeEnum;
|
||||||
|
import com.x.retry.common.core.enums.RetryStatusEnum;
|
||||||
|
import com.x.retry.server.persistence.mybatis.mapper.RetryTaskLogMapper;
|
||||||
|
import com.x.retry.server.persistence.mybatis.mapper.ServerNodeMapper;
|
||||||
|
import com.x.retry.server.persistence.mybatis.po.RetryTaskLog;
|
||||||
|
import com.x.retry.server.persistence.mybatis.po.ServerNode;
|
||||||
|
import com.x.retry.server.service.DashBoardService;
|
||||||
|
import com.x.retry.server.web.model.response.ActivePodQuantityResponseVO;
|
||||||
|
import com.x.retry.server.web.model.response.DispatchQuantityResponseVO;
|
||||||
|
import com.x.retry.server.web.model.response.SceneQuantityRankResponseVO;
|
||||||
|
import com.x.retry.server.web.model.response.TaskQuantityResponseVO;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: www.byteblogs.com
|
||||||
|
* @date : 2022-04-22 20:19
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class DashBoardServiceImpl implements DashBoardService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RetryTaskLogMapper retryTaskLogMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ServerNodeMapper serverNodeMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TaskQuantityResponseVO countTask() {
|
||||||
|
|
||||||
|
TaskQuantityResponseVO taskQuantityResponseVO = new TaskQuantityResponseVO();
|
||||||
|
taskQuantityResponseVO.setTotal(retryTaskLogMapper.countTaskTotal());
|
||||||
|
|
||||||
|
taskQuantityResponseVO.setFinish(retryTaskLogMapper.countTaskByRetryStatus(RetryStatusEnum.FINISH.getLevel()));
|
||||||
|
taskQuantityResponseVO.setMaxRetryCount(retryTaskLogMapper.countTaskByRetryStatus(RetryStatusEnum.MAX_RETRY_COUNT.getLevel()));
|
||||||
|
taskQuantityResponseVO.setRunning(taskQuantityResponseVO.getTotal() - taskQuantityResponseVO.getFinish() - taskQuantityResponseVO.getMaxRetryCount());
|
||||||
|
|
||||||
|
return taskQuantityResponseVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DispatchQuantityResponseVO countDispatch() {
|
||||||
|
DispatchQuantityResponseVO dispatchQuantityResponseVO = new DispatchQuantityResponseVO();
|
||||||
|
|
||||||
|
Long total = retryTaskLogMapper.selectCount(null);
|
||||||
|
dispatchQuantityResponseVO.setTotal(total);
|
||||||
|
|
||||||
|
if (total == 0) {
|
||||||
|
return dispatchQuantityResponseVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
Long success = retryTaskLogMapper.selectCount(new LambdaQueryWrapper<RetryTaskLog>()
|
||||||
|
.in(RetryTaskLog::getRetryStatus, RetryStatusEnum.MAX_RETRY_COUNT.getLevel(),
|
||||||
|
RetryStatusEnum.FINISH.getLevel()));
|
||||||
|
dispatchQuantityResponseVO.setSuccessPercent(BigDecimal.valueOf(success).divide(BigDecimal.valueOf(total), 2, RoundingMode.HALF_UP));
|
||||||
|
|
||||||
|
return dispatchQuantityResponseVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActivePodQuantityResponseVO countActivePod() {
|
||||||
|
|
||||||
|
ActivePodQuantityResponseVO activePodQuantityResponseVO = new ActivePodQuantityResponseVO();
|
||||||
|
activePodQuantityResponseVO.setTotal(serverNodeMapper.selectCount(null));
|
||||||
|
activePodQuantityResponseVO.setServerTotal(serverNodeMapper.selectCount(new LambdaQueryWrapper<ServerNode>().eq(ServerNode::getNodeType, NodeTypeEnum.SERVER.getType())));
|
||||||
|
activePodQuantityResponseVO.setClientTotal(serverNodeMapper.selectCount(new LambdaQueryWrapper<ServerNode>().eq(ServerNode::getNodeType, NodeTypeEnum.CLIENT.getType())));
|
||||||
|
|
||||||
|
return activePodQuantityResponseVO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SceneQuantityRankResponseVO> rankSceneQuantity(String groupName) {
|
||||||
|
return retryTaskLogMapper.rankSceneQuantity(groupName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<DispatchQuantityResponseVO> lineDispatchQuantity(String groupName) {
|
||||||
|
|
||||||
|
List<DispatchQuantityResponseVO> totalDispatchQuantityResponseList = retryTaskLogMapper.lineDispatchQuantity(groupName, null);
|
||||||
|
|
||||||
|
List<DispatchQuantityResponseVO> successDispatchQuantityResponseList = retryTaskLogMapper.lineDispatchQuantity(groupName, RetryStatusEnum.FINISH.getLevel());
|
||||||
|
Map<String, DispatchQuantityResponseVO> dispatchQuantityResponseVOMap = successDispatchQuantityResponseList.stream().collect(Collectors.toMap(DispatchQuantityResponseVO::getCreateDt, i -> i));
|
||||||
|
for (DispatchQuantityResponseVO dispatchQuantityResponseVO : totalDispatchQuantityResponseList) {
|
||||||
|
|
||||||
|
DispatchQuantityResponseVO quantityResponseVO = dispatchQuantityResponseVOMap.get(dispatchQuantityResponseVO.getCreateDt());
|
||||||
|
if (Objects.isNull(dispatchQuantityResponseVO)) {
|
||||||
|
dispatchQuantityResponseVO.setSuccess(0L);
|
||||||
|
} else {
|
||||||
|
dispatchQuantityResponseVO.setSuccess(quantityResponseVO.getTotal());
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchQuantityResponseVO.setFail(dispatchQuantityResponseVO.getTotal() - dispatchQuantityResponseVO.getSuccess());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalDispatchQuantityResponseList;
|
||||||
|
}
|
||||||
|
}
|
@ -74,6 +74,8 @@ public class RetryDeadLetterServiceImpl implements RetryDeadLetterService {
|
|||||||
RetryTask retryTask = new RetryTask();
|
RetryTask retryTask = new RetryTask();
|
||||||
BeanUtils.copyProperties(retryDeadLetter, retryTask);
|
BeanUtils.copyProperties(retryDeadLetter, retryTask);
|
||||||
retryTask.setNextTriggerAt(WaitStrategies.randomWait(1, TimeUnit.SECONDS, 60, TimeUnit.SECONDS).computeRetryTime(null));
|
retryTask.setNextTriggerAt(WaitStrategies.randomWait(1, TimeUnit.SECONDS, 60, TimeUnit.SECONDS).computeRetryTime(null));
|
||||||
|
retryTask.setCreateDt(LocalDateTime.now());
|
||||||
|
retryTask.setUpdateDt(LocalDateTime.now());
|
||||||
RequestDataHelper.setPartition(groupName);
|
RequestDataHelper.setPartition(groupName);
|
||||||
Assert.isTrue(1 == retryTaskMapper.insert(retryTask), new XRetryServerException("新增重试任务失败"));
|
Assert.isTrue(1 == retryTaskMapper.insert(retryTask), new XRetryServerException("新增重试任务失败"));
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ import org.springframework.stereotype.Component;
|
|||||||
/**
|
/**
|
||||||
* 不重试,只更新下次触发时间
|
* 不重试,只更新下次触发时间
|
||||||
*
|
*
|
||||||
* @author: shuguang.zhang
|
* @author: www.byteblogs.com
|
||||||
* @date : 2022-04-14 16:11
|
* @date : 2022-04-14 16:11
|
||||||
*/
|
*/
|
||||||
@Component("NoRetryActor")
|
@Component("NoRetryActor")
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
package com.x.retry.server.web.controller;
|
||||||
|
|
||||||
|
import com.x.retry.server.service.DashBoardService;
|
||||||
|
import com.x.retry.server.web.annotation.LoginRequired;
|
||||||
|
import com.x.retry.server.web.model.response.ActivePodQuantityResponseVO;
|
||||||
|
import com.x.retry.server.web.model.response.DispatchQuantityResponseVO;
|
||||||
|
import com.x.retry.server.web.model.response.SceneQuantityRankResponseVO;
|
||||||
|
import com.x.retry.server.web.model.response.TaskQuantityResponseVO;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: www.byteblogs.com
|
||||||
|
* @date : 2022-04-22 20:17
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/dashboard")
|
||||||
|
public class DashBoardController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DashBoardService dashBoardService;
|
||||||
|
|
||||||
|
@LoginRequired
|
||||||
|
@GetMapping("/task/count")
|
||||||
|
public TaskQuantityResponseVO countTask() {
|
||||||
|
return dashBoardService.countTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
@LoginRequired
|
||||||
|
@GetMapping("/dispatch/count")
|
||||||
|
public DispatchQuantityResponseVO countDispatch() {
|
||||||
|
return dashBoardService.countDispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
@LoginRequired
|
||||||
|
@GetMapping("/active-pod/count")
|
||||||
|
public ActivePodQuantityResponseVO countActivePod() {
|
||||||
|
return dashBoardService.countActivePod();
|
||||||
|
}
|
||||||
|
|
||||||
|
@LoginRequired
|
||||||
|
@GetMapping("/scene/rank")
|
||||||
|
public List<SceneQuantityRankResponseVO> rankSceneQuantity(@RequestParam(value = "groupName", required = false)
|
||||||
|
String groupName) {
|
||||||
|
return dashBoardService.rankSceneQuantity(groupName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@LoginRequired
|
||||||
|
@GetMapping("/dispatch/line")
|
||||||
|
public List<DispatchQuantityResponseVO> lineDispatchQuantity(@RequestParam(value = "groupName", required = false)
|
||||||
|
String groupName) {
|
||||||
|
return dashBoardService.lineDispatchQuantity(groupName);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.x.retry.server.web.model.response;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: www.byteblogs.com
|
||||||
|
* @date : 2022-04-23 10:39
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ActivePodQuantityResponseVO {
|
||||||
|
|
||||||
|
private Long total;
|
||||||
|
|
||||||
|
private Long clientTotal;
|
||||||
|
|
||||||
|
private Long serverTotal;
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.x.retry.server.web.model.response;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: www.byteblogs.com
|
||||||
|
* @date : 2022-04-22 20:27
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DispatchQuantityResponseVO {
|
||||||
|
|
||||||
|
private Long total;
|
||||||
|
|
||||||
|
private BigDecimal successPercent = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
private Long success;
|
||||||
|
|
||||||
|
private Long fail;
|
||||||
|
|
||||||
|
private String createDt;
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.x.retry.server.web.model.response;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: www.byteblogs.com
|
||||||
|
* @date : 2022-04-23 10:56
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SceneQuantityRankResponseVO {
|
||||||
|
|
||||||
|
private String groupName;
|
||||||
|
|
||||||
|
private String sceneName;
|
||||||
|
|
||||||
|
private String total;
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.x.retry.server.web.model.response;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: www.byteblogs.com
|
||||||
|
* @date : 2022-04-22 20:27
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class TaskQuantityResponseVO {
|
||||||
|
|
||||||
|
private Long total;
|
||||||
|
|
||||||
|
private Long running;
|
||||||
|
|
||||||
|
private Long finish;
|
||||||
|
|
||||||
|
private Long maxRetryCount;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,31 +1,80 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
<mapper namespace="com.x.retry.server.persistence.mybatis.mapper.RetryTaskLogMapper">
|
<mapper namespace="com.x.retry.server.persistence.mybatis.mapper.RetryTaskLogMapper">
|
||||||
<resultMap id="BaseResultMap" type="com.x.retry.server.persistence.mybatis.po.RetryTaskLog">
|
<resultMap id="BaseResultMap" type="com.x.retry.server.persistence.mybatis.po.RetryTaskLog">
|
||||||
<id column="id" jdbcType="BIGINT" property="id" />
|
<id column="id" jdbcType="BIGINT" property="id"/>
|
||||||
<result column="group_name" jdbcType="VARCHAR" property="groupName" />
|
<result column="group_name" jdbcType="VARCHAR" property="groupName"/>
|
||||||
<result column="scene_name" jdbcType="VARCHAR" property="sceneName" />
|
<result column="scene_name" jdbcType="VARCHAR" property="sceneName"/>
|
||||||
<result column="biz_id" jdbcType="VARCHAR" property="bizId" />
|
<result column="biz_id" jdbcType="VARCHAR" property="bizId"/>
|
||||||
<result column="biz_no" jdbcType="VARCHAR" property="bizNo" />
|
<result column="biz_no" jdbcType="VARCHAR" property="bizNo"/>
|
||||||
<result column="executor_name" jdbcType="VARCHAR" property="executorName" />
|
<result column="executor_name" jdbcType="VARCHAR" property="executorName"/>
|
||||||
<result column="args_str" jdbcType="VARCHAR" property="argsStr" />
|
<result column="args_str" jdbcType="VARCHAR" property="argsStr"/>
|
||||||
<result column="ext_attrs" jdbcType="VARCHAR" property="extAttrs" />
|
<result column="ext_attrs" jdbcType="VARCHAR" property="extAttrs"/>
|
||||||
<result column="retry_status" jdbcType="TINYINT" property="retryStatus" />
|
<result column="retry_status" jdbcType="TINYINT" property="retryStatus"/>
|
||||||
<result column="error_message" jdbcType="VARCHAR" property="errorMessage" />
|
<result column="error_message" jdbcType="VARCHAR" property="errorMessage"/>
|
||||||
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt" />
|
<result column="create_dt" jdbcType="TIMESTAMP" property="createDt"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<sql id="Base_Column_List">
|
<sql id="Base_Column_List">
|
||||||
id, group_name, scene_name, biz_id, biz_no, executor_name, args_str, ext_attrs, retry_status, error_message,
|
id
|
||||||
|
, group_name, scene_name, biz_id, biz_no, executor_name, args_str, ext_attrs, retry_status, error_message,
|
||||||
create_dt
|
create_dt
|
||||||
</sql>
|
</sql>
|
||||||
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
|
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
|
||||||
select
|
select
|
||||||
<include refid="Base_Column_List" />
|
<include refid="Base_Column_List"/>
|
||||||
from retry_task_log
|
from retry_task_log
|
||||||
where id = #{id,jdbcType=BIGINT}
|
where id = #{id,jdbcType=BIGINT}
|
||||||
</select>
|
</select>
|
||||||
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
|
<select id="countTaskTotal" resultType="java.lang.Long">
|
||||||
delete from retry_task_log
|
select count(*)
|
||||||
where id = #{id,jdbcType=BIGINT}
|
from (
|
||||||
</delete>
|
select group_name, scene_name, biz_id from retry_task_log group by group_name, scene_name, biz_id) a
|
||||||
|
</select>
|
||||||
|
<select id="countTaskByRetryStatus" resultType="java.lang.Long">
|
||||||
|
select count(*)
|
||||||
|
from (
|
||||||
|
select group_name, scene_name, biz_id
|
||||||
|
from retry_task_log
|
||||||
|
where retry_status = #{retryStatus}
|
||||||
|
group by group_name, scene_name, biz_id) a
|
||||||
|
|
||||||
|
</select>
|
||||||
|
<select id="rankSceneQuantity"
|
||||||
|
resultType="com.x.retry.server.web.model.response.SceneQuantityRankResponseVO">
|
||||||
|
select group_name, scene_name, count(*) total
|
||||||
|
from (
|
||||||
|
select group_name, scene_name, biz_id, count(*)
|
||||||
|
from retry_task_log
|
||||||
|
group by group_name, scene_name, biz_id) a
|
||||||
|
<where>
|
||||||
|
<if test="groupName != '' and groupName != null">
|
||||||
|
group_name = #{groupName}
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
group by group_name, scene_name
|
||||||
|
order by total desc;
|
||||||
|
</select>
|
||||||
|
<select id="lineDispatchQuantity"
|
||||||
|
resultType="com.x.retry.server.web.model.response.DispatchQuantityResponseVO">
|
||||||
|
select distinct(create_dt), count(*) total
|
||||||
|
from (
|
||||||
|
select group_name, scene_name, biz_id, DATE_FORMAT(create_dt, '%Y-%m-%d') as create_dt, count(*)
|
||||||
|
from retry_task_log
|
||||||
|
<where>
|
||||||
|
<if test="groupName != '' and groupName != null">
|
||||||
|
group_name = #{groupName}
|
||||||
|
</if>
|
||||||
|
<if test="retryStatus!=null ">
|
||||||
|
retry_status = #{retryStatus}
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
group by group_name, scene_name, biz_id, create_dt) a
|
||||||
|
group by create_dt
|
||||||
|
order by total desc;
|
||||||
|
</select>
|
||||||
|
<delete id="deleteByPrimaryKey" parameterType="java.lang.Long">
|
||||||
|
delete
|
||||||
|
from retry_task_log
|
||||||
|
where id = #{id,jdbcType=BIGINT}
|
||||||
|
</delete>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
Loading…
Reference in New Issue
Block a user