feat(web): 增加离线检索页面和任务查看
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
package com.lanyuanxiaoyao.service.web.controller;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.lanyuanxiaoyao.service.configuration.ExecutorProvider;
|
||||
import com.lanyuanxiaoyao.service.forest.service.TaskService;
|
||||
import com.lanyuanxiaoyao.service.web.controller.base.AmisMapResponse;
|
||||
import com.lanyuanxiaoyao.service.web.controller.base.AmisResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 任务提交
|
||||
*
|
||||
* @author lanyuanxiaoyao
|
||||
* @date 2024-01-10
|
||||
*/
|
||||
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
|
||||
@RestController
|
||||
@RequestMapping("task")
|
||||
public class TaskController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(TaskController.class);
|
||||
|
||||
private final TaskService taskService;
|
||||
|
||||
public TaskController(TaskService taskService) {
|
||||
this.taskService = taskService;
|
||||
}
|
||||
|
||||
@GetMapping("scan")
|
||||
public AmisResponse<Object> scan(
|
||||
@RequestParam("hdfs") String hdfs,
|
||||
@RequestParam("key") String key,
|
||||
@RequestParam(value = "mode", defaultValue = "") String mode
|
||||
) {
|
||||
if (StrUtil.isBlank(hdfs) || StrUtil.isBlank(key)) {
|
||||
throw new RuntimeException("Argument cannot be blank");
|
||||
}
|
||||
ExecutorProvider.EXECUTORS.submit(() -> {
|
||||
boolean scanLog = StrUtil.contains(mode, "log");
|
||||
boolean scanData = StrUtil.contains(mode, "data");
|
||||
String applicationId = taskService.scan(hdfs, key, scanLog, scanData);
|
||||
logger.info("Task: {}", applicationId);
|
||||
});
|
||||
return AmisResponse.responseSuccess();
|
||||
}
|
||||
|
||||
@GetMapping("results")
|
||||
public AmisMapResponse results(@RequestParam("task_id") String taskId) {
|
||||
return AmisResponse.responseMapData()
|
||||
.setData("text", taskService.results(taskId).makeString("\n"));
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.lanyuanxiaoyao.service.configuration.entity.yarn.YarnApplication;
|
||||
import com.lanyuanxiaoyao.service.configuration.utils.DatetimeUtil;
|
||||
import java.time.Instant;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* YarnApplication 展示类
|
||||
@@ -15,12 +17,15 @@ import java.time.Instant;
|
||||
* @date 2023-04-21
|
||||
*/
|
||||
public class YarnApplicationVO {
|
||||
private static final Pattern TASK_REGEX = Pattern.compile("^Service_Task_(.+)_(.{8})$");
|
||||
|
||||
@JsonIgnore
|
||||
private final YarnApplication yarnApplication;
|
||||
|
||||
private final Boolean isHudiApplication;
|
||||
private final Boolean isSyncApplication;
|
||||
private final Boolean isCompactionApplication;
|
||||
private final Boolean isTaskApplication;
|
||||
private String startTimeFromNow;
|
||||
private String finishTimeFromNow;
|
||||
|
||||
@@ -28,6 +33,9 @@ public class YarnApplicationVO {
|
||||
private String flinkJobName;
|
||||
private String alias;
|
||||
|
||||
private String taskName;
|
||||
private String taskId;
|
||||
|
||||
private Double compactionCompletionRatio = 0.0;
|
||||
|
||||
public YarnApplicationVO(YarnApplication yarnApplication) {
|
||||
@@ -37,6 +45,13 @@ public class YarnApplicationVO {
|
||||
isCompactionApplication = NameHelper.isCompactionJob(yarnApplication.getName());
|
||||
isHudiApplication = isSyncApplication || isCompactionApplication;
|
||||
|
||||
Matcher matcher = TASK_REGEX.matcher(yarnApplication.getName());
|
||||
isTaskApplication = matcher.matches();
|
||||
if (isTaskApplication && matcher.groupCount() == 2) {
|
||||
taskName = matcher.group(1);
|
||||
taskId = matcher.group(2);
|
||||
}
|
||||
|
||||
long now = Instant.now().toEpochMilli();
|
||||
if (ObjectUtil.isNotNull(yarnApplication.getStartedTime()) && yarnApplication.getStartedTime() != 0) {
|
||||
startTimeFromNow = DatetimeUtil.fromNow(now, yarnApplication.getStartedTime());
|
||||
@@ -147,6 +162,10 @@ public class YarnApplicationVO {
|
||||
return isHudiApplication;
|
||||
}
|
||||
|
||||
public Boolean getTaskApplication() {
|
||||
return isTaskApplication;
|
||||
}
|
||||
|
||||
public String getStartTimeFromNow() {
|
||||
return startTimeFromNow;
|
||||
}
|
||||
@@ -167,6 +186,14 @@ public class YarnApplicationVO {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public String getTaskName() {
|
||||
return taskName;
|
||||
}
|
||||
|
||||
public String getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public Double getCompactionCompletionRatio() {
|
||||
return compactionCompletionRatio;
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ function yarnCrudColumns() {
|
||||
label: '名称',
|
||||
className: 'nowrap',
|
||||
type: 'tpl',
|
||||
tpl: "${IF(syncApplication, '<span class=\"rounded-xl label label-primary\">S</span>', IF(compactionApplication, '<span class=\"rounded-xl label label-primary\">C</span>', ''))}${IF(hudiApplication, '<span class=\"mx-2\"/>', '')}${IF(syncApplication, flinkJobName, IF(compactionApplication, alias, name))}",
|
||||
tpl: "${IF(syncApplication, '<span class=\"rounded-xl label label-primary\">S</span>', IF(compactionApplication, '<span class=\"rounded-xl label label-primary\">C</span>', IF(taskApplication, '<span class=\"rounded-xl label label-primary\">T</span>', '')))}${IF(hudiApplication || taskApplication, '<span class=\"mx-2\"/>', '')}${IF(syncApplication, flinkJobName, IF(compactionApplication, alias, IF(taskApplication, taskName, name)))}",
|
||||
// tpl: '${name}',
|
||||
backgroundScale: {
|
||||
min: 0.001,
|
||||
@@ -399,6 +399,40 @@ function yarnCrudColumns() {
|
||||
level: 'link',
|
||||
tooltip: '${alias}'
|
||||
},
|
||||
{
|
||||
disabledOn: '${finalStatus != \'SUCCEEDED\' || state != \'FINISHED\'}',
|
||||
disabledTip: '无结果',
|
||||
visibleOn: 'taskId',
|
||||
label: '结果',
|
||||
level: 'link',
|
||||
type: 'action',
|
||||
actionType: 'dialog',
|
||||
dialog: {
|
||||
title: '结果',
|
||||
...readOnlyDialogOptions(),
|
||||
size: 'xl',
|
||||
body: [
|
||||
{
|
||||
type: 'service',
|
||||
api: {
|
||||
method: 'get',
|
||||
url: '${base}/task/results',
|
||||
data: {
|
||||
task_id: '${taskId|default:undefined}'
|
||||
}
|
||||
},
|
||||
body: {
|
||||
type: 'editor',
|
||||
disabled: true,
|
||||
name: 'text',
|
||||
options: {
|
||||
wordWrap: 'on'
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'ID',
|
||||
type: 'action',
|
||||
|
||||
96
service-web/src/main/resources/static/components/task-tab.js
Normal file
96
service-web/src/main/resources/static/components/task-tab.js
Normal file
@@ -0,0 +1,96 @@
|
||||
function taskTab() {
|
||||
return {
|
||||
title: `离线检索`,
|
||||
tab: [
|
||||
{
|
||||
type: 'form',
|
||||
title: '检索文件',
|
||||
actions: [
|
||||
{
|
||||
type: 'submit',
|
||||
label: '提交任务',
|
||||
actionType: 'ajax',
|
||||
api: {
|
||||
method: 'get',
|
||||
url: '${base}/task/scan',
|
||||
data: {
|
||||
hdfs: '${hdfs|default:undefined}',
|
||||
key: '${key|default:undefined}',
|
||||
mode: '${scan_mode|default:undefined}',
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
body: [
|
||||
{
|
||||
name: 'scan_mode',
|
||||
type: 'checkboxes',
|
||||
label: '检索范围',
|
||||
checkAll: true,
|
||||
required: true,
|
||||
value: 'log',
|
||||
options: [
|
||||
{label: '日志文件', value: 'log'},
|
||||
{label: '数据文件', value: 'data'},
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'group',
|
||||
body: [
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'key',
|
||||
label: '检索字段',
|
||||
required: true,
|
||||
clearable: true,
|
||||
description: '检索带有该字符的记录',
|
||||
columnRatio: 4,
|
||||
},
|
||||
{
|
||||
type: 'input-text',
|
||||
name: 'hdfs',
|
||||
label: 'HDFS路经',
|
||||
required: true,
|
||||
clearable: true,
|
||||
description: '输入表HDFS路径',
|
||||
autoComplete: '${base}/table/all_hdfs?key=$term',
|
||||
columnRatio: 8,
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'crud',
|
||||
api: {
|
||||
method: 'get',
|
||||
url: `\${base}/yarn/job_list`,
|
||||
data: {
|
||||
clusters: `b12`,
|
||||
page: '${page|default:undefined}',
|
||||
count: '${perPage|default:undefined}',
|
||||
order: '${orderBy|default:undefined}',
|
||||
direction: '${orderDir|default:undefined}',
|
||||
filter_state: '${state|default:undefined}',
|
||||
filter_final_status: '${finalStatus|default:undefined}',
|
||||
search_id: '${id|default:undefined}',
|
||||
search_name: 'Service_Task',
|
||||
precise: false,
|
||||
}
|
||||
},
|
||||
affixHeader: false,
|
||||
interval: 10000,
|
||||
syncLocation: false,
|
||||
silentPolling: true,
|
||||
resizable: false,
|
||||
perPage: 10,
|
||||
headerToolbar: [
|
||||
"reload",
|
||||
paginationCommonOptions(),
|
||||
],
|
||||
footerToolbar: [],
|
||||
columns: yarnCrudColumns(),
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,7 @@
|
||||
<script src="components/version-tab.js"></script>
|
||||
<script src="components/overview-tab.js"></script>
|
||||
<script src="components/tool-tab.js"></script>
|
||||
<script src="components/task-tab.js"></script>
|
||||
<script type="text/javascript">
|
||||
(function () {
|
||||
let amis = amisRequire('amis/embed')
|
||||
@@ -73,6 +74,7 @@
|
||||
cloudTab(),
|
||||
yarnClusterTab(),
|
||||
toolTab(),
|
||||
taskTab(),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user