获取指标说明的能力
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
spring:
|
||||
cache.type: simple
|
||||
datasource:
|
||||
postgre:
|
||||
jdbc-url: jdbc:postgresql://localhost:5432/verich
|
||||
|
||||
@@ -383,7 +383,17 @@ blockquote.layui-elem-quote {
|
||||
box-shadow: 1px 1px 10px rgba(0, 0, 0, .1);
|
||||
border-radius: 0;
|
||||
}
|
||||
.layui-layer>.layui-layer-content {
|
||||
.layui-layer-indexDetail>.layui-layer-content>*:not(:last-child) {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
.layui-layer-indexDetail>.layui-layer-content>* {
|
||||
max-width: 100%;
|
||||
}
|
||||
.layui-layer-indexDetail>.layui-layer-content>img {
|
||||
margin: auto;
|
||||
display: block
|
||||
}
|
||||
.layui-layer-adminRight>.layui-layer-content {
|
||||
overflow: visible !important;
|
||||
}
|
||||
.layui-anim-rl {
|
||||
@@ -442,4 +452,15 @@ fieldset>legend:before {
|
||||
font-weight: bold;
|
||||
margin-right: .25em;
|
||||
color: rgb(22, 183, 119)
|
||||
}
|
||||
.ipInfo {
|
||||
color: #000
|
||||
}
|
||||
.ipInfo>dl {
|
||||
max-width: 100px
|
||||
}
|
||||
.ipInfo .ipv6>a {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
@@ -1,14 +1,75 @@
|
||||
if (!window.Helper) {window.Helper = {}}
|
||||
if (!window.Helper) { window.Helper = {} }
|
||||
window.Helper = {
|
||||
emoneyPeriodToName: function(x) {
|
||||
if (x < 10000) return `${x} 分钟`;
|
||||
if (x == 10000) return '日线';
|
||||
if (x == 20000) return '周线';
|
||||
if (x == 30000) return '月线';
|
||||
if (x == 40000) return '季线';
|
||||
if (x == 50000) return '半年线';
|
||||
if (x == 60000) return '年线';
|
||||
},
|
||||
allEmoneyPeriods: [1, 5, 15, 30, 60, 120, 10000, 20000, 30000, 40000, 50000, 60000]
|
||||
|
||||
emoneyPeriodToName: function(x) {
|
||||
if (x < 10000) return `${x} 分钟`;
|
||||
if (x == 10000) return '日线';
|
||||
if (x == 20000) return '周线';
|
||||
if (x == 30000) return '月线';
|
||||
if (x == 40000) return '季线';
|
||||
if (x == 50000) return '半年线';
|
||||
if (x == 60000) return '年线';
|
||||
},
|
||||
allEmoneyPeriods: [1, 5, 15, 30, 60, 120, 10000, 20000, 30000, 40000, 50000, 60000],
|
||||
showIndexDetailLayer: async function(obj, forceRefresh) {
|
||||
// obj: {indexCode: _, indexName: _}
|
||||
var layer = layui.layer;
|
||||
var load = layer.load(2);
|
||||
var url = !!forceRefresh ?
|
||||
'/admin/v1/manage/indexInfo/forceRefreshAndGetIndexDetail?indexCode=' :
|
||||
'/admin/v1/manage/indexInfo/getIndexDetail?indexCode=';
|
||||
url += obj.indexCode;
|
||||
var res = await (await fetch(url)).json();
|
||||
if (res.ok) {
|
||||
// build content
|
||||
var html = [];
|
||||
for (var i = 0; i < res.data.details.length; i++) {
|
||||
var detail = res.data.details[i];
|
||||
if (detail.type == 'TITLE') {
|
||||
html.push('<h3>');
|
||||
html.push(Helper.trimChars(detail.content, '::'));
|
||||
html.push('</h3>');
|
||||
}
|
||||
else if (detail.type == 'IMAGE') {
|
||||
if (detail.content.indexOf('data:image/') == 0 &&
|
||||
detail.content.indexOf('base64') != -1) {
|
||||
html.push('<img src="');
|
||||
html.push(detail.content);
|
||||
html.push('">');
|
||||
}
|
||||
}
|
||||
else {
|
||||
html.push('<p>');
|
||||
html.push(detail.content.replaceAll(/\n+/g, '<br>'));
|
||||
html.push('</p>');
|
||||
}
|
||||
}
|
||||
console.log(res.data);
|
||||
layer.open({
|
||||
title: obj.indexName + '指标说明',
|
||||
content: html.join(''),
|
||||
skin: 'layui-layer-indexDetail',
|
||||
area: ['520px', '320px'],
|
||||
btn: ['刷新', '确定'],
|
||||
btn1: function(index, layero, that) {
|
||||
layer.close(index);
|
||||
Helper.showIndexDetailLayer(obj, !0);
|
||||
},
|
||||
success: function(layero, index) {
|
||||
var btns = layero.find('.layui-layer-btn>*');
|
||||
btns[0].setAttribute('class', 'layui-layer-btn1');
|
||||
btns[1].setAttribute('class', 'layui-layer-btn0');
|
||||
}
|
||||
})
|
||||
}
|
||||
else {
|
||||
Dog.error({ msg: res && res.message || '服务器错误' });
|
||||
}
|
||||
layer.close(load);
|
||||
},
|
||||
trimChars: function (str, chars) {
|
||||
const escaped = chars.split('').map(c => c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('');
|
||||
const pattern = new RegExp(`^[${escaped}]+|[${escaped}]+$`, 'g');
|
||||
return str.replace(pattern, '');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -224,29 +224,34 @@
|
||||
el.value = !!el.checked;
|
||||
});
|
||||
})
|
||||
form.on('submit(submit)', function(data){
|
||||
var field = data.field;
|
||||
document.querySelectorAll('input[lay-skin="switch"]').forEach(checkbox => {
|
||||
field[checkbox.getAttribute('name')] = checkbox.getAttribute('value') == 'true'
|
||||
});
|
||||
form.on('submit(submit)', async function(data){
|
||||
|
||||
$.ajax({
|
||||
url: location.href,
|
||||
data: JSON.stringify(field),
|
||||
contentType: 'application/json',
|
||||
method: 'POST',
|
||||
success: function (result) {
|
||||
Dog.success({
|
||||
onClose: () => location.reload()
|
||||
})
|
||||
},
|
||||
error: function (res) {
|
||||
var r = res.responseJSON;
|
||||
Dog.error({
|
||||
msg: r && r.data,
|
||||
})
|
||||
}
|
||||
layui.layer.confirm('若设备信息修改,会导致清空鉴权信息,确定吗?', async function() {
|
||||
var load = layui.layer.load(2);
|
||||
var field = data.field;
|
||||
document.querySelectorAll('input[lay-skin="switch"]').forEach(checkbox => {
|
||||
field[checkbox.getAttribute('name')] = checkbox.getAttribute('value') == 'true'
|
||||
});
|
||||
try {
|
||||
var res = await (await fetch(location.href, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(field)
|
||||
})).json();
|
||||
if (res && res.ok) {
|
||||
Dog.success({onClose: () => location.reload()});
|
||||
}
|
||||
else {
|
||||
Dog.error({msg: res && res.data || '服务器错误'})
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
Dog.error({msg: e})
|
||||
}
|
||||
layui.layer.close(load);
|
||||
})
|
||||
});
|
||||
form.render();
|
||||
|
||||
|
||||
@@ -63,6 +63,20 @@
|
||||
<dd><a th:href="@{/admin/v1/logout}">退出登录</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
<li class="layui-nav-item ipInfo" style="float:right;margin-right: 1px" lay-unselect="">
|
||||
<a id="ipThroughProxy" href="javascript:manualRefreshIp()" title="立即刷新">
|
||||
IP 属地:
|
||||
<span th:if="${@proxyConfig.ipInfo == null}" class="layui-badge layui-bg-cyan">加载中...</span>
|
||||
<span th:if="${@proxyConfig.ipInfo != null}" class="layui-badge layui-bg-cyan">[[${@proxyConfig.ipInfo.geoString}]]</span>
|
||||
</a>
|
||||
<th:block th:if="${@proxyConfig.ipInfo != null}">
|
||||
<dl class="layui-nav-child">
|
||||
<dd class="ip"><a title="点击复制">[[${@proxyConfig.ipInfo.ip}]]</a></dd>
|
||||
<dd class="ipv6" th:if="${@proxyConfig.ipInfo.ipv6 != null}"><a title="点击复制">[[${@proxyConfig.ipInfo.ipv6}]]</a></dd>
|
||||
</dl>
|
||||
</th:block>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
<script type="text/html" id="editUser">
|
||||
<div class="layui-form" style="margin:10px 15px" id="editUserForm" lay-filter="editUserForm">
|
||||
@@ -111,13 +125,47 @@
|
||||
<script>
|
||||
|
||||
let refreshTimer = null;
|
||||
|
||||
document.querySelectorAll('dd.ip,dd.ipv6').forEach(el => {
|
||||
el.addEventListener('click', () => {
|
||||
let text = el.querySelector('a').textContent;
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
Dog.success({msg: '复制成功'})
|
||||
}).catch(err => {
|
||||
Dog.error({msg: '复制失败'})
|
||||
});
|
||||
})
|
||||
});
|
||||
async function refreshIpThroughProxy() {
|
||||
try {
|
||||
let geoEl =
|
||||
document.querySelector('#ipThroughProxy>span');
|
||||
geoEl.textContent = '加载中...';
|
||||
let res = await (await fetch('/admin/v1/config/proxy/refreshIpThroughProxy')).json();
|
||||
if (res.ok) {
|
||||
let ip = res.data.string || '获取代理 IP 失败';
|
||||
document.getElementById('ipThroughProxy').textContent = ip;
|
||||
geoEl.textContent = res.data.geoString || '获取失败';
|
||||
let ipMenu = document.querySelector('.ipInfo>dl');
|
||||
let genIpEL = (clazz, title) => {
|
||||
let el = ipMenu.querySelector('.' + selector);
|
||||
if (!el) {
|
||||
el = document.createElement('dd');
|
||||
let a = document.createElement('a');
|
||||
a.setAttribute('title', title || '点击复制');
|
||||
el.classList.add(clazz);
|
||||
el.appendChild(a);
|
||||
ipMenu.appendChild(el);
|
||||
}
|
||||
return el;
|
||||
};
|
||||
let ipEl = genIpEL('ip');
|
||||
let ipv6El = ipMenu.querySelector('.ipv6');
|
||||
ipEl.querySelector('a').textContent = res.data.ip;
|
||||
if (res.data.ipv6) {
|
||||
ipv6El = ipv6El || genIpEL('ipv6');
|
||||
ipv6El.querySelector('a').textContent = res.data.ipv6;
|
||||
}
|
||||
else if (ipv6El) {
|
||||
ipv6El.remove();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('刷新失败:', e);
|
||||
@@ -221,10 +269,6 @@
|
||||
</script>
|
||||
</th:block>
|
||||
<div th:fragment="feet" class="layui-trans layadmin-user-login-footer">
|
||||
<a id="ipThroughProxy" href="javascript:manualRefreshIp()" title="立即刷新">
|
||||
[[${@proxyConfig.ipInfo == null ? '当前 IP 信息:加载中...' :
|
||||
@proxyConfig.ipInfo.string}]]
|
||||
</a><br>
|
||||
Driven by Latte<br />
|
||||
©2025-[[${#dates.format(new java.util.Date().getTime(),'yyyy')}]]
|
||||
<a href="#">Latte</a>
|
||||
|
||||
@@ -67,8 +67,8 @@
|
||||
cols: [ [
|
||||
{field: 'indexCode', title: '指标代码'},
|
||||
{field: 'indexName', title: '指标名称'},
|
||||
{field: 'isCalc', title: '是否传统算法', templet: (d) => {
|
||||
return d.isCalc ?
|
||||
{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>';
|
||||
}},
|
||||
@@ -102,13 +102,13 @@
|
||||
}
|
||||
}
|
||||
})
|
||||
table.on('tool(indexInfos)', (obj) => {
|
||||
table.on('tool(indexInfos)', async function (obj) {
|
||||
if (obj.event == 'detail') {
|
||||
|
||||
Helper.showIndexDetailLayer(obj.data);
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
});
|
||||
</script>
|
||||
<th:block th:replace="~{admin/v1/manage/indexInfo/updateForm::indexInfoUpdateForm}"></th:block>
|
||||
</body>
|
||||
|
||||
@@ -114,7 +114,32 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
enableCodeMirrorResize(editor, document.getElementById("editor-wrapper"))
|
||||
enableCodeMirrorResize(editor, document.getElementById("editor-wrapper"));
|
||||
|
||||
let submitBtn = document.querySelector('[lay-filter="submitIndexConfigFile"]');
|
||||
submitBtn.addEventListener('click', async function(e) {
|
||||
e.preventDefault();
|
||||
let res = await (await fetch('/admin/v1/config/indexInfo', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
configIndOnlineUrl: document.querySelector('[name="configIndOnlineUrl"]').value,
|
||||
configIndOnline: JSON.parse(editor.getValue())
|
||||
})
|
||||
})).json();
|
||||
if (res.ok) {
|
||||
Dog.success({
|
||||
onClose: () => location.reload()
|
||||
})
|
||||
}
|
||||
else {
|
||||
Dog.error({
|
||||
msg: res && res.data,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -160,5 +185,6 @@
|
||||
document.body.style.cursor = "default";
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</th:block>
|
||||
@@ -25,6 +25,9 @@
|
||||
<option value="">选择更新指标</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<a style="display:none" href="#" id="showIndexDetailLayer" onclick="javascript:showIndexDetailLayer(this, event)"><i class="fa fa-solid fa-circle-question"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="params">
|
||||
@@ -112,6 +115,13 @@
|
||||
}
|
||||
})
|
||||
})
|
||||
function showIndexDetailLayer(el, event) {
|
||||
event.preventDefault();
|
||||
Helper.showIndexDetailLayer({
|
||||
indexCode: el.dataset.indexCode,
|
||||
indexName: el.dataset.indexName
|
||||
});
|
||||
}
|
||||
function openEditForm(r) {
|
||||
if (r && r.ok) {
|
||||
window.editLayer = layui.layer.open({
|
||||
@@ -149,11 +159,21 @@
|
||||
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 paramsEl = document.getElementById('params'); // 参数选择控件
|
||||
const periodsEl = document.getElementById('periods'); // 时间粒度选择控件
|
||||
paramsEl.textContent = periodsEl.textContent = ''; // 清除参数和时间粒度选择控件
|
||||
const dataset = obj.elem.querySelector(`[value="${obj.value}"]`).dataset;
|
||||
const detailTriggerEl = document.getElementById('showIndexDetailLayer');
|
||||
if (!dataset || !dataset.indInfo) {
|
||||
// 未存在 dataset/.indInfo, 则去除可能存在的指标详情按钮
|
||||
detailTriggerEl.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
detailTriggerEl.style.display = '';
|
||||
detailTriggerEl.dataset.indexCode = obj.value;
|
||||
detailTriggerEl.dataset.indexName = dataset.indName;
|
||||
const indInfo =
|
||||
JSON.parse(obj.elem.querySelector(`[value="${obj.value}"]`).dataset.indInfo);
|
||||
JSON.parse(dataset.indInfo);
|
||||
const paramTemplet = document.getElementById('paramTemplet');
|
||||
const periodsTemplet = document.getElementById('periodsTemplet');
|
||||
if (indInfo.indParam) {
|
||||
@@ -211,6 +231,7 @@
|
||||
option.textContent = `${key} ${jo.indIdNameConfig[key]}`;
|
||||
option.selected = r.data.indexCode == key;
|
||||
option.dataset.indInfo = JSON.stringify(indInfo);
|
||||
option.dataset.indName = jo.indIdNameConfig[key];
|
||||
|
||||
optionsFragment.appendChild(option);
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user