First Commit
This commit is contained in:
116
src/main/resources/webpage/admin/v1/manage/indexInfo/index.html
Normal file
116
src/main/resources/webpage/admin/v1/manage/indexInfo/index.html
Normal file
@@ -0,0 +1,116 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head th:replace="~{admin/v1/include::head}">
|
||||
</head>
|
||||
<style>
|
||||
.layui-elem-quote-warning {
|
||||
border-left: 5px solid #d8a900;
|
||||
}
|
||||
.layui-form-mid {
|
||||
float: none;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<ul th:replace="~{admin/v1/include::nav}"></ul>
|
||||
|
||||
<div class="manage-body">
|
||||
<div>
|
||||
<h1 class="manage-title">
|
||||
<b>指标配置</b>
|
||||
<a href="#" class="help"><i class="layui-icon layui-icon-help"></i></a>
|
||||
<a href="javascript:openUpdateForm()" class="operate">更新</a>
|
||||
</h1>
|
||||
</div>
|
||||
<div>
|
||||
<table class="layui-table" id="indexInfos" lay-filter="indexInfos">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/html" id="operationTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="detail">详情</a>
|
||||
</div>
|
||||
</script>
|
||||
<div th:replace="~{admin/v1/include::feet}"></div>
|
||||
<th:block th:replace="~{admin/v1/include::head-script}"></th:block>
|
||||
|
||||
<script>
|
||||
layui.use(function(){
|
||||
const form = layui.form, layer = layui.layer, table = layui.table;
|
||||
const help = document.querySelector('.help');
|
||||
|
||||
help.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
layer.open({
|
||||
title: '帮助',
|
||||
shadeClose: !0,
|
||||
content:
|
||||
[
|
||||
'益盟操盘手指标配置,一般需要从 APK 包中获取 <span>config_ind_online.json</span> 文件',
|
||||
'该界面提供可视化查看指标信息的功能,并允许用户从云端拉取、编辑配置文件',
|
||||
'此处的指标配置决定了任务能够更新的指标和细节,包括指标参数限制、数据粒度限制等'
|
||||
].join('<br/>')
|
||||
})
|
||||
})
|
||||
|
||||
document.querySelectorAll('[lay-skin="switch"]').forEach(check => {
|
||||
form.on(`switch(${check.getAttribute('lay-filter')})`, (data) => {
|
||||
var el = data.elem;
|
||||
el.value = !!el.checked;
|
||||
});
|
||||
})
|
||||
|
||||
table.render({
|
||||
elem: '#indexInfos',
|
||||
url: '/admin/v1/manage/indexInfo/configIndOnline',
|
||||
skin: 'line',
|
||||
cols: [ [
|
||||
{field: 'indexCode', title: '指标代码'},
|
||||
{field: 'indexName', title: '指标名称'},
|
||||
{field: 'isCalc', title: '是否传统算法', templet: (d) => {
|
||||
return d.isCalc ?
|
||||
'<i class="op-green fa-solid fa-circle-check"></i>' :
|
||||
'<i class="op-red fa-solid fa-circle-exclamation"></i>';
|
||||
}},
|
||||
{field:'operation', title: '操作', toolbar: '#operationTpl'}
|
||||
]],
|
||||
where: {
|
||||
fields: 'configIndOnline'
|
||||
},
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
parseData: (json) => {
|
||||
console.log(json)
|
||||
const jo = json.data, indMap = jo.indMap;
|
||||
const data = [];
|
||||
Object.keys(indMap).forEach(key => {
|
||||
const indInfo = indMap[key];
|
||||
const row = {
|
||||
indexCode: key,
|
||||
indexName: jo.indIdNameConfig[key],
|
||||
isCalc: indInfo.isCalc,
|
||||
indInfo: indInfo
|
||||
};
|
||||
data.push(row)
|
||||
})
|
||||
return {
|
||||
code: json.ok ? 0 : 1,
|
||||
msg: json.message,
|
||||
data: data,
|
||||
count: data.length
|
||||
}
|
||||
}
|
||||
})
|
||||
table.on('tool(indexInfos)', (obj) => {
|
||||
if (obj.event == 'detail') {
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
<th:block th:replace="~{admin/v1/manage/indexInfo/updateForm::indexInfoUpdateForm}"></th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,164 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<th:block th:fragment="indexInfoUpdateForm">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.2/codemirror.min.css">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.2/codemirror.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.62.2/mode/javascript/javascript.min.js"></script>
|
||||
<!-- JSON通常用JavaScript模式 -->
|
||||
<script id="index-info-update-form" type="text/html">
|
||||
<style>
|
||||
.layui-layer>#updateFormLayer.layui-layer-content {
|
||||
overflow: auto !important;
|
||||
}
|
||||
.CodeMirror {
|
||||
border: 1px solid #eee;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
<div class="layui-form" style="margin:10px 15px" id="editPlanForm" lay-filter="editPlanForm">
|
||||
<div class="layui-form-item with-inline-btn">
|
||||
<label class="layui-form-label">配置文件 URL</label>
|
||||
<div class="layui-inline">
|
||||
<input type="text" name="configIndOnlineUrl" placeholder="" autocomplete="off" class="layui-input"/>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn" id="pull-online-file">拉取</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">配置文件</label>
|
||||
<div class="layui-input-block" id="editor-wrapper">
|
||||
<textarea id="config-editor" class="layui-textarea"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:none" class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="*" lay-filter="submitIndexConfigFile">提交</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
|
||||
async function openUpdateForm() {
|
||||
// 获取必要项
|
||||
const base = '/admin/v1/manage/indexInfo';
|
||||
const res = await fetch(
|
||||
`${base}/getFields?fields=${['configIndOnlineUrl', 'configIndOnlineStr'].join(',')}`
|
||||
);
|
||||
const result = await res.json();
|
||||
|
||||
if (!res.ok) {
|
||||
Dog.error({msg: result.message || '获取配置失败'});
|
||||
return
|
||||
}
|
||||
window.updateConfigLayer = layui.layer.open({
|
||||
id: 'updateFormLayer',
|
||||
type: 1,
|
||||
title: '更新配置文件',
|
||||
btn: ['提交', '关闭'],
|
||||
yes: function (index, layero) {
|
||||
const submitBtn = document.querySelector('[lay-filter="submitIndexConfigFile"]');
|
||||
submitBtn.click();
|
||||
const formData = new FormData(document.getElementById(editPlanForm));
|
||||
console.log(formData)
|
||||
//layero.find('[lay-filter="submitIndexConfigFile"]').click()
|
||||
},
|
||||
area: ['800px', '540px'],
|
||||
shadeClose: !0,
|
||||
content: document.getElementById('index-info-update-form').innerHTML,
|
||||
success: function (layero, layerIndex) {
|
||||
const textarea = document.getElementById("config-editor");
|
||||
const urlInput = document.querySelector('[name="configIndOnlineUrl"]');
|
||||
const data = result.data;
|
||||
urlInput.value = data.configIndOnlineUrl;
|
||||
textarea.textContent = data.configIndOnlineStr;
|
||||
document.getElementById('pull-online-file').addEventListener('click', async function (e) {
|
||||
const load = layui.layer.load(2);
|
||||
const resJson =
|
||||
await (await fetch(`${base}/getConfigIndOnlineByUrl?url=${urlInput.value}`)).json();
|
||||
try {
|
||||
if (!resJson.ok) {
|
||||
Dog.error({msg: resJson.message || '拉取失败'});
|
||||
return
|
||||
}
|
||||
Dog.success({msg: '拉取成功'});
|
||||
editor.setValue(textarea.textContent = resJson.data)
|
||||
}
|
||||
finally {
|
||||
layui.layer.close(load)
|
||||
}
|
||||
});
|
||||
const editor = CodeMirror.fromTextArea(textarea, {
|
||||
mode: {name: "javascript", json: true}, // 使用JavaScript模式来高亮JSON
|
||||
lineNumbers: true,
|
||||
indentUnit: 4, // 每一级缩进为 4 个空格
|
||||
indentWithTabs: false, // 不使用 tab 字符,使用空格缩进
|
||||
extraKeys: {
|
||||
Tab: function (cm) {
|
||||
if (cm.somethingSelected()) {
|
||||
cm.indentSelection("add");
|
||||
} else {
|
||||
const cursor = cm.getCursor();
|
||||
const line = cm.getLine(cursor.line);
|
||||
const beforeCursor = line.slice(0, cursor.ch);
|
||||
const col = CodeMirror.countColumn(beforeCursor, null, cm.getOption("tabSize"));
|
||||
const indentSize = cm.getOption("indentUnit");
|
||||
const spacesToInsert = indentSize - (col % indentSize);
|
||||
const spaces = " ".repeat(spacesToInsert);
|
||||
cm.replaceSelection(spaces, "end", "+input");
|
||||
}
|
||||
},
|
||||
"Shift-Tab": function (cm) {
|
||||
cm.indentSelection("subtract");
|
||||
}
|
||||
}
|
||||
});
|
||||
enableCodeMirrorResize(editor, document.getElementById("editor-wrapper"))
|
||||
}
|
||||
})
|
||||
}
|
||||
function enableCodeMirrorResize(editor, wrapperElement, minHeight = 100) {
|
||||
// 创建拖动手柄
|
||||
const handle = document.createElement("div");
|
||||
handle.className = "cm-resize-handle";
|
||||
wrapperElement.appendChild(handle);
|
||||
|
||||
Object.assign(handle.style, {
|
||||
height: "8px",
|
||||
background: "#ccc",
|
||||
cursor: "ns-resize",
|
||||
position: "absolute",
|
||||
bottom: "-8px",
|
||||
left: "0",
|
||||
right: "0",
|
||||
zIndex: "10"
|
||||
});
|
||||
|
||||
// 添加 wrapper 相对定位
|
||||
wrapperElement.style.position = "relative";
|
||||
|
||||
let isDragging = false;
|
||||
|
||||
handle.addEventListener("mousedown", (e) => {
|
||||
isDragging = true;
|
||||
document.body.style.cursor = "ns-resize";
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
document.addEventListener("mousemove", (e) => {
|
||||
if (!isDragging) return;
|
||||
const wrapperTop = wrapperElement.getBoundingClientRect().top;
|
||||
const newHeight = e.clientY - wrapperTop;
|
||||
if (newHeight > minHeight) {
|
||||
editor.setSize(null, newHeight + "px");
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("mouseup", () => {
|
||||
isDragging = false;
|
||||
document.body.style.cursor = "default";
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</th:block>
|
||||
289
src/main/resources/webpage/admin/v1/manage/plan/include.html
Normal file
289
src/main/resources/webpage/admin/v1/manage/plan/include.html
Normal file
@@ -0,0 +1,289 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<div th:fragment="planExtra">
|
||||
<script id="addPlan" type="text/html">
|
||||
<style>.layui-form-select dl{max-height: 160px}</style>
|
||||
<div class="layui-form" style="margin:10px 15px" id="editPlanForm" lay-filter="editPlanForm">
|
||||
<div class="layui-form-item">
|
||||
<input type="hidden" name="planId"/>
|
||||
<label class="layui-form-label">计划名称<span>*</span></label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" lay-verify="required" name="planName" placeholder="" autocomplete="off" class="layui-input"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">计划表达式<span>*</span></label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" lay-verify="required" name="cronExpression" placeholder="" autocomplete="off" class="layui-input"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">更新指标<span>*</span></label>
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-inline">
|
||||
<select name="indexCode" lay-filter="indexCodeFilter" lay-search>
|
||||
<option value="">选择更新指标</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="params">
|
||||
</div>
|
||||
<div id="periods">
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">启用<span>*</span></label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox"
|
||||
name="enabled" lay-skin="switch" lay-filter="enabled" lay-text="ON|OFF">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">交易日校验<span>*</span></label>
|
||||
<div class="layui-input-block">
|
||||
<input type="checkbox"
|
||||
name="openDayCheck" lay-skin="switch" lay-filter="openDayCheck" lay-text="ON|OFF">
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:none" class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="*" lay-filter="submitPlan">提交</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="periodsTemplet">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">更新粒度<span>*</span></label>
|
||||
<div class="layui-input-block">
|
||||
<div id="period-xm-select" style="width: 100%" class="layui-inline"></div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="paramTemplet">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">{{d.pName}}<span>*</span></label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number"
|
||||
min="{{d.pMin}}" max="{{d.pMax}}"
|
||||
name="params.{{d.pName}}"
|
||||
lay-verify="required|min:{{d.pMin}}|max:{{d.pMax}}|number"
|
||||
placeholder="范围:{{d.pMin}} ~ {{d.pMax}}"
|
||||
value="{{d.pValue}}" autocomplete="off" class="layui-input"/>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
layui.form.on('submit(submitPlan)', function (obj) {
|
||||
var field = obj.field, data = {params: {}}
|
||||
Object.keys(field).forEach(key => {
|
||||
if (key.indexOf('params') == 0) {
|
||||
data.params[key.substr(7)] = field[key]
|
||||
}
|
||||
else if (key == 'periods') {
|
||||
data.periods = field.periods.split(',')
|
||||
}
|
||||
else {
|
||||
data[key] = field[key]
|
||||
}
|
||||
})
|
||||
$.ajax({
|
||||
url: '/admin/v1/manage/plan/save',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(data),
|
||||
success: function (r) {
|
||||
layer.msg('操作成功', {
|
||||
offset: '15px',
|
||||
icon: 1,
|
||||
time: 1000
|
||||
},
|
||||
function () {
|
||||
if (window.editLayer) {
|
||||
layui.layer.close(window.editLayer);
|
||||
}
|
||||
layui.table.reload('plans', {
|
||||
page: {
|
||||
curr: $(".layui-laypage-em").next().html() //当前页码值
|
||||
}
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
function openEditForm(r) {
|
||||
if (r && r.ok) {
|
||||
window.editLayer = layui.layer.open({
|
||||
type: 1,
|
||||
title: `${r.data.planId ? '编辑' : '新增'}计划任务`,
|
||||
btn: ['提交', '关闭'],
|
||||
yes: function (index, layero) {
|
||||
layero.find('[lay-filter="submitPlan"]').click()
|
||||
},
|
||||
skin: "layui-anim layui-anim-rl layui-layer-adminRight",
|
||||
area: '500px',
|
||||
anim: -1,
|
||||
shadeClose: !0,
|
||||
closeBtn: !1,
|
||||
move: !1,
|
||||
offset: 'r',
|
||||
content: $('#addPlan').html(),
|
||||
success: async function (layero, layerIndex) {
|
||||
var el = $(layero);
|
||||
['planId', 'planName', 'cronExpression', 'indexCode'].forEach(x => {
|
||||
const fieldEl = el[0].querySelector(`[name="${x}"]`);
|
||||
if (!fieldEl) return;
|
||||
fieldEl.value = r.data[x];
|
||||
});
|
||||
['enabled', 'openDayCheck'].forEach(x => {
|
||||
const fieldEl = el[0].querySelector(`[name="${x}"]`);
|
||||
if (!fieldEl) return;
|
||||
fieldEl.checked = r.data[x];
|
||||
fieldEl.value = r.data[x];
|
||||
layui.form.on('switch(' + x + ')', obj => obj.elem.value = obj.elem.checked)
|
||||
});
|
||||
layui.cron.render({
|
||||
elem: '[name="cronExpression"]',
|
||||
btns: ['confirm'],
|
||||
cssPath: '/admin/v1/static/css/cron.css'
|
||||
});
|
||||
layui.form.on('select(indexCodeFilter)', async function (obj) {
|
||||
const paramsEl = document.getElementById('params');
|
||||
const periodsEl = document.getElementById('periods');
|
||||
paramsEl.textContent = periodsEl.textContent = '';
|
||||
const indInfo =
|
||||
JSON.parse(obj.elem.querySelector(`[value="${obj.value}"]`).dataset.indInfo);
|
||||
const paramTemplet = document.getElementById('paramTemplet');
|
||||
const periodsTemplet = document.getElementById('periodsTemplet');
|
||||
if (indInfo.indParam) {
|
||||
var tpl = layui.laytpl(paramTemplet.textContent);
|
||||
for (var i = 0; i < indInfo.indParam.pName.length; i++) {
|
||||
var d = {
|
||||
pName: indInfo.indParam.pName[i],
|
||||
pMin: indInfo.indParam.min[i],
|
||||
pMax: indInfo.indParam.max[i],
|
||||
pValue: indInfo.indParam.value[i]
|
||||
}
|
||||
if (obj.params && obj.params[d.pName]) {
|
||||
d.pValue = obj.params[d.pName]
|
||||
}
|
||||
paramsEl.insertAdjacentHTML('beforeend', tpl.render(d));
|
||||
}
|
||||
}
|
||||
var periods = Helper.allEmoneyPeriods;
|
||||
if (indInfo.supportPeriod) periods = indInfo.supportPeriod;
|
||||
periodsEl.insertAdjacentHTML('beforeend', periodsTemplet.textContent);
|
||||
|
||||
var data = [];
|
||||
for (var i = 0; i < periods.length; i++) {
|
||||
var period = periods[i];
|
||||
data.push({
|
||||
name: Helper.emoneyPeriodToName(period),
|
||||
value: period,
|
||||
selected: r.data.periods.indexOf(period + '') != -1
|
||||
})
|
||||
}
|
||||
layui.xmSelect.render({
|
||||
name: 'periods',
|
||||
el: '#period-xm-select',
|
||||
language: 'zn',
|
||||
data: data,
|
||||
autoRow: !0
|
||||
})
|
||||
layui.form.render()
|
||||
})
|
||||
|
||||
const loadConfigLayer = layui.layer.load(2);
|
||||
const json = await (await fetch('/admin/v1/manage/indexInfo/configIndOnline')).json();
|
||||
|
||||
if (json.ok) {
|
||||
const indexNameSelectEl = document.querySelector('[name="indexCode"]');
|
||||
const jo = json.data, indMap = jo.indMap;
|
||||
let selected = undefined;
|
||||
const optionsFragment = document.createDocumentFragment();
|
||||
Object.keys(indMap).forEach(key => {
|
||||
const indInfo = indMap[key];
|
||||
if (indInfo.isCalc) return;
|
||||
if (r.data.indexCode == key) selected = key;
|
||||
const option = document.createElement('option');
|
||||
option.value = key;
|
||||
option.textContent = `${key} ${jo.indIdNameConfig[key]}`;
|
||||
option.selected = r.data.indexCode == key;
|
||||
option.dataset.indInfo = JSON.stringify(indInfo);
|
||||
|
||||
optionsFragment.appendChild(option);
|
||||
})
|
||||
indexNameSelectEl.appendChild(optionsFragment);
|
||||
if (selected)
|
||||
// 如果有选择内容, 手动触发指标选择下拉框,并附带参数
|
||||
layui.event.call(this, 'form', 'select(indexCodeFilter)', {
|
||||
elem: indexNameSelectEl,
|
||||
value: selected,
|
||||
params: r.data.params
|
||||
});
|
||||
layui.form.render();
|
||||
}
|
||||
else {
|
||||
Dog.error({
|
||||
msg: json.data || '获取指标配置错误'
|
||||
});
|
||||
layui.layer.close(window.editLayer);
|
||||
}
|
||||
layui.form.render();
|
||||
layui.layer.close(loadConfigLayer);
|
||||
}
|
||||
})
|
||||
}
|
||||
else Dog.error({
|
||||
msg: r && r.data || '服务器错误'
|
||||
});
|
||||
}
|
||||
async function openNewForm(planId) {
|
||||
const json = await (await fetch((() => {
|
||||
const url = '/admin/v1/manage/plan/getOne';
|
||||
if (planId) return url + '?planId=' + planId;
|
||||
return url
|
||||
})())).json();
|
||||
if (json.ok) {
|
||||
openEditForm(json)
|
||||
}
|
||||
else {
|
||||
window.toastModule.errorLayer({
|
||||
msg: json.data || '服务器错误'
|
||||
});
|
||||
}
|
||||
}
|
||||
layui.table.on('tool(plans)', async function (obj) {
|
||||
if (obj.event == 'edit') {
|
||||
openNewForm(obj.data.planId)
|
||||
}
|
||||
else if (obj.event == 'del') {
|
||||
layui.layer.confirm('确定删除该计划任务吗?', function (index) {
|
||||
layui.layer.close(index);
|
||||
$.ajax({
|
||||
url: '/admin/v1/manage/plan/delete',
|
||||
method: 'POST',
|
||||
data: {planId: obj.data.planId},
|
||||
success: function (data) {
|
||||
layui.table.reload('plans', {
|
||||
page: {
|
||||
curr: $(".layui-laypage-em").next().html() //当前页码值
|
||||
}
|
||||
});
|
||||
layer.msg('删除成功', {offset: '15px', icon: 1, time: 1000})
|
||||
},
|
||||
error: function (res) {
|
||||
var r = res.responseJSON;
|
||||
layer.msg(r && r.data || '服务器错误',
|
||||
{offset: '15px', icon: 2, time: 2000});
|
||||
return
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</div>
|
||||
|
||||
</html>
|
||||
168
src/main/resources/webpage/admin/v1/manage/plan/index.html
Normal file
168
src/main/resources/webpage/admin/v1/manage/plan/index.html
Normal file
@@ -0,0 +1,168 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head th:insert="~{admin/v1/include::head}"
|
||||
th:with="title=${'计划任务管理'}">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ul th:replace="~{admin/v1/include::nav}"></ul>
|
||||
|
||||
<div class="manage-body">
|
||||
<div>
|
||||
<h1 class="manage-title">
|
||||
<b>计划任务列表</b><a href="javascript:openNewForm()" class="operate">新增</a>
|
||||
</h1>
|
||||
|
||||
</div>
|
||||
<button class="layui-btn layui-btn-sm operdown">
|
||||
<span>选中项<i
|
||||
class="layui-icon layui-icon-sm layui-icon-triangle-d"></i></span>
|
||||
</button>
|
||||
<div>
|
||||
<table class="layui-table" id="plans" lay-filter="plans">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div th:replace="~{admin/v1/include::feet}"></div>
|
||||
<script type="text/html" id="operationTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</div>
|
||||
</script>
|
||||
<th:block th:replace="~{admin/v1/include::head-script}"></th:block>
|
||||
<script th:inline="javascript">
|
||||
layui
|
||||
.extend({
|
||||
xmSelect: '/admin/v1/static/layuiadmin/lib/xm-select',
|
||||
cron: '/admin/v1/static/layuiadmin/lib/cron'
|
||||
})
|
||||
.use(['table', 'form', 'dropdown', 'layer', 'xmSelect', 'cron'], function(){
|
||||
var dropdown = layui.dropdown, table = layui.table, form = layui.form;
|
||||
function switchTemplet(d) {
|
||||
var fieldName = d.LAY_COL.field;
|
||||
return `<input type="checkbox" lay-skin="switch" lay-text="|"
|
||||
data-field="${fieldName}" data-id="${d.planId}"
|
||||
${d[fieldName] ? 'checked' : ''} lay-filter="switchFilter">`;
|
||||
}
|
||||
table.render({
|
||||
elem: '#plans',
|
||||
url:'/admin/v1/manage/plan/list',
|
||||
page:true, skin:'line',
|
||||
cols: [ [
|
||||
{type:'checkbox'},
|
||||
{field:'enabled', title: '启用', width: 95, templet: switchTemplet},
|
||||
{field:'openDayCheck', title: '交易日校验', width: 95, templet: switchTemplet},
|
||||
{field:'planId', hide: true, width: 60, title: 'ID'},
|
||||
{field:'planName', title: '计划名称'},
|
||||
{field:'cronExpression', title: '计划表达式'},
|
||||
{field:'indexCode', title: '指标代码'},
|
||||
{field:'params', title: '请求参数',templet: function(d) {
|
||||
if (typeof d.params === 'object' && d.params !== null) {
|
||||
return Object.entries(d.params).map(([key, value]) => `${key}=${value}`).join(', ');
|
||||
}
|
||||
return d.params || '无';
|
||||
}},
|
||||
{field:'periods', title: '更新粒度', templet: function(d) {
|
||||
if (typeof d.periods === 'object' && d.periods !== null) {
|
||||
return d.periods.map(x => Helper.emoneyPeriodToName(x)).join(', ')
|
||||
}
|
||||
return d.periods || '无';
|
||||
}},
|
||||
{field:'operation', title: '操作', toolbar: '#operationTpl'}
|
||||
]]
|
||||
});
|
||||
form.on('switch(switchFilter)', function(obj) {
|
||||
console.log(obj);
|
||||
console.log(obj.elem.checked);
|
||||
$.ajax({
|
||||
url: '/admin/v1/manage/plan/updateBool',
|
||||
method: 'POST',
|
||||
data: {
|
||||
planId: obj.elem.dataset.id,
|
||||
field: obj.elem.dataset.field,
|
||||
value: obj.elem.checked
|
||||
},
|
||||
success: function () {
|
||||
layer.msg('操作成功', {
|
||||
offset: '15px',
|
||||
icon: 1,
|
||||
time: 1000
|
||||
},
|
||||
function() {}
|
||||
)
|
||||
},
|
||||
error: function (res) {
|
||||
var r = res.responseJSON;
|
||||
layer.msg(r && r.data || '服务器错误', {
|
||||
offset: '15px',
|
||||
icon: 2,
|
||||
time: 1000
|
||||
});
|
||||
// 恢复 enabled 状态
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
layui.form.render('checkbox')
|
||||
return
|
||||
}
|
||||
})
|
||||
});
|
||||
dropdown.render({
|
||||
elem: '.operdown',
|
||||
data: [
|
||||
{title: '删除'},
|
||||
{title: '启用', op: 'enable'},
|
||||
{title: '停用', op: 'disable'},
|
||||
{title: '开启交易日校验', op: 'enableOpenDayCheck'},
|
||||
{title: '关闭交易日校验', op: 'disableOpenDayCheck'}],
|
||||
click: function (data, othis){
|
||||
var checked = layui.table.checkStatus('plans'), planIds = [];
|
||||
if (!checked.data.length) {
|
||||
layui.layer.msg('未选中任何项', {time: 1000});
|
||||
return;
|
||||
}
|
||||
$.each(checked.data, function (i, plan){
|
||||
planIds.push(plan.planId);
|
||||
});
|
||||
data = $.extend(data, {ids: planIds});
|
||||
var op = function() {
|
||||
$.ajax({
|
||||
url: '/admin/v1/manage/plan/batchOp',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
success: function () {
|
||||
layer.msg('批量操作成功', {
|
||||
offset: '15px',
|
||||
icon: 1,
|
||||
time: 1000
|
||||
},
|
||||
function() {
|
||||
layui.table.reload('plans', {
|
||||
page: {
|
||||
curr: $(".layui-laypage-em").next().html() //当前页码值
|
||||
}
|
||||
});
|
||||
}
|
||||
)
|
||||
},
|
||||
error: function (res) {
|
||||
var r = res.responseJSON;
|
||||
layer.msg(r&&r.data||'服务器错误', {
|
||||
offset: '15px',
|
||||
icon: 2,
|
||||
time: 1000
|
||||
});
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
data.op ? op() : layer.confirm('确认批量删除吗?该操作不可恢复', function(){
|
||||
op();
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
<th:block th:replace="~{admin/v1/manage/plan/include::planExtra}"></th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,128 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<div th:fragment="protocolMatchExtra">
|
||||
<script id="addProtocolMatch" type="text/html">
|
||||
<style>.layui-form-select dl{max-height: 160px}</style>
|
||||
<div class="layui-form" style="margin:10px 15px" id="editPlanForm" lay-filter="editPlanForm">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">Protocol ID<span>*</span></label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" lay-verify="required|number" name="protocolId" placeholder="" autocomplete="off" class="layui-input"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">类名</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="className" placeholder="" autocomplete="off" class="layui-input"/>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:none" class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="*" lay-filter="submitProtocolMatch">提交</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
layui.form.on('submit(submitProtocolMatch)', function(obj){
|
||||
var field = obj.field, data = {params: {}}
|
||||
Object.keys(field).forEach(key => {
|
||||
data[key] = field[key]
|
||||
});
|
||||
$.ajax({
|
||||
url: '/admin/v1/manage/protocolMatch/save',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(data),
|
||||
success: function (r) {
|
||||
layer.msg('操作成功', {
|
||||
offset: '15px',
|
||||
icon: 1,
|
||||
time: 1000
|
||||
},
|
||||
function() {
|
||||
if (window.editLayer) {
|
||||
layui.layer.close(window.editLayer);
|
||||
}
|
||||
layui.table.reload('protocolMatches',{
|
||||
page: {
|
||||
curr: $(".layui-laypage-em").next().html() //当前页码值
|
||||
}
|
||||
});
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
function openEditForm(r) {
|
||||
if (r && r.ok) {
|
||||
window.editLayer = layui.layer.open({
|
||||
type: 1,
|
||||
title: `${r.data.planId ? '编辑' : '新增'}Protocol`,
|
||||
btn: ['提交', '关闭'],
|
||||
yes: function(index, layero) {
|
||||
layero.find('[lay-filter="submitProtocolMatch"]').click()
|
||||
},
|
||||
skin: "layui-anim layui-anim-rl layui-layer-adminRight",
|
||||
area: '500px',
|
||||
anim: -1,
|
||||
shadeClose: !0,
|
||||
closeBtn: !1,
|
||||
move: !1,
|
||||
offset: 'r',
|
||||
content: $('#addProtocolMatch').html(),
|
||||
success: function(layero, layerIndex) {
|
||||
var el = $(layero);
|
||||
['protocolId', 'className'].forEach(x => {
|
||||
el.find(`[name="${x}"]`).val(r.data[x])
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
else layer.msg(r && r.data || '服务器错误', {offset: '15px', icon: 2, time: 1000})
|
||||
}
|
||||
function openNewForm(protocolId) {
|
||||
$.ajax({
|
||||
url: '/admin/v1/manage/protocolMatch/getOne',
|
||||
data: {protocolId: protocolId},
|
||||
success: function(r) {
|
||||
openEditForm(r)
|
||||
},
|
||||
error: function(xhr) {
|
||||
var r = xhr.responseJSON;
|
||||
layer.msg(r && r.data || '服务器错误', {offset: '15px', icon: 2, time: 100})
|
||||
}
|
||||
})
|
||||
}
|
||||
layui.table.on('tool(protocolMatches)', function(obj) {
|
||||
if (obj.event == 'edit') {
|
||||
openNewForm(obj.data.protocolId)
|
||||
}
|
||||
else if (obj.event == 'del') {
|
||||
layui.layer.confirm('确定删除该映射吗?', function (index) {
|
||||
layui.layer.close(index);
|
||||
$.ajax({
|
||||
url: '/admin/v1/manage/protocolMatch/delete',
|
||||
method: 'POST',
|
||||
data: {planId: obj.data.protocolId},
|
||||
success: function (data) {
|
||||
layui.table.reload('protocolMatches',{
|
||||
page: {
|
||||
curr: $(".layui-laypage-em").next().html() //当前页码值
|
||||
}
|
||||
});
|
||||
layer.msg('删除成功', {offset: '15px', icon: 1, time: 1000})
|
||||
},
|
||||
error: function (res) {
|
||||
var r = res.responseJSON;
|
||||
layer.msg(r&&r.data||'服务器错误',
|
||||
{offset: '15px', icon: 2, time: 2000});
|
||||
return
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</div>
|
||||
</html>
|
||||
@@ -0,0 +1,134 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head th:insert="~{admin/v1/include::head}"
|
||||
th:with="title=${'Protocol 管理'}">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ul th:replace="~{admin/v1/include::nav}"></ul>
|
||||
|
||||
<div class="manage-body">
|
||||
<div>
|
||||
<h1 class="manage-title">
|
||||
<b>Protocol ID 映射表</b>
|
||||
<a href="#" class="help"><i class="layui-icon layui-icon-help"></i></a>
|
||||
<a href="javascript:openUploadForm()" class="operate">上传</a>
|
||||
<a href="javascript:openNewForm()" class="operate">新增</a>
|
||||
</h1>
|
||||
|
||||
</div>
|
||||
<button class="layui-btn layui-btn-sm operdown">
|
||||
<span>选中项<i
|
||||
class="layui-icon layui-icon-sm layui-icon-triangle-d"></i></span>
|
||||
</button>
|
||||
<div>
|
||||
<table class="layui-table" id="protocolMatches" lay-filter="protocolMatches">
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div th:replace="~{admin/v1/include::feet}"></div>
|
||||
<script type="text/html" id="operationTpl">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-xs" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a>
|
||||
</div>
|
||||
</script>
|
||||
<th:block th:replace="~{admin/v1/include::head-script}"></th:block>
|
||||
<script th:inline="javascript">
|
||||
layui
|
||||
.extend({
|
||||
xmSelect: '/admin/v1/static/layuiadmin/lib/xm-select',
|
||||
cron: '/admin/v1/static/layuiadmin/lib/cron'
|
||||
})
|
||||
.use(['table', 'form', 'dropdown', 'layer', 'xmSelect', 'cron'], function(){
|
||||
var dropdown = layui.dropdown, table = layui.table, form = layui.form;
|
||||
|
||||
$('.help').on('click', function (e) {
|
||||
e.preventDefault();
|
||||
layer.open({
|
||||
title: '帮助',
|
||||
content:
|
||||
'益盟操盘手 Protocol-Id 设置,用来映射 Id 与解析类的关系。<br>'+
|
||||
'一般需要从 APK 包中获取 nano 包下的文件以及 ProtocolIDs.java 文件'
|
||||
})
|
||||
})
|
||||
|
||||
function switchTemplet(d) {
|
||||
var fieldName = d.LAY_COL.field;
|
||||
return `<input type="checkbox" lay-skin="switch" lay-text="|"
|
||||
data-field="${fieldName}" data-id="${d.planId}"
|
||||
${d[fieldName] ? 'checked' : ''} lay-filter="switchFilter">`;
|
||||
}
|
||||
|
||||
table.render({
|
||||
elem: '#protocolMatches',
|
||||
url:'/admin/v1/manage/protocolMatch/list',
|
||||
page:true, skin:'line',
|
||||
cols: [ [
|
||||
{type:'checkbox'},
|
||||
{field:'protocolId', width: 100, title: 'ID'},
|
||||
{field:'className', title: '类名'},
|
||||
{field:'operation', title: '操作', width: 150, toolbar: '#operationTpl'}
|
||||
]]
|
||||
});
|
||||
|
||||
dropdown.render({
|
||||
elem: '.operdown',
|
||||
data: [
|
||||
{title: '删除'},
|
||||
{title: '启用', op: 'enable'},
|
||||
{title: '停用', op: 'disable'},
|
||||
{title: '开启交易日校验', op: 'enableOpenDayCheck'},
|
||||
{title: '关闭交易日校验', op: 'disableOpenDayCheck'}],
|
||||
click: function (data, othis){
|
||||
var checked = layui.table.checkStatus('protocolMatches'), planIds = [];
|
||||
if (!checked.data.length) {
|
||||
layui.layer.msg('未选中任何项', {time: 1000});
|
||||
return;
|
||||
}
|
||||
$.each(checked.data, function (i, plan){
|
||||
planIds.push(plan.planId);
|
||||
});
|
||||
data = $.extend(data, {ids: planIds});
|
||||
var op = function() {
|
||||
$.ajax({
|
||||
url: '/admin/v1/manage/plan/batchOp',
|
||||
method: 'POST',
|
||||
data: data,
|
||||
success: function () {
|
||||
layer.msg('批量操作成功', {
|
||||
offset: '15px',
|
||||
icon: 1,
|
||||
time: 1000
|
||||
},
|
||||
function() {
|
||||
layui.table.reload('protocolMatches', {
|
||||
page: {
|
||||
curr: $(".layui-laypage-em").next().html() //当前页码值
|
||||
}
|
||||
});
|
||||
}
|
||||
)
|
||||
},
|
||||
error: function (res) {
|
||||
var r = res.responseJSON;
|
||||
layer.msg(r&&r.data||'服务器错误', {
|
||||
offset: '15px',
|
||||
icon: 2,
|
||||
time: 1000
|
||||
});
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
data.op ? op() : layer.confirm('确认批量删除吗?该操作不可恢复', function(){
|
||||
op();
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
</script>
|
||||
<th:block th:replace="~{admin/v1/manage/protocolMatch/include::protocolMatchExtra}"></th:block>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user