⚲
專案
一般
配置概況
登入
註冊
網站首頁
專案清單
說明
搜尋
:
Grafana報表系統
全部的專案
Grafana報表系統
概觀
活動
議題清單
新聞
下載 (9.84 KB)
工作單 #199
» P9801010-3DS Result Overview.json
marlboro chu, 2025-06-30 02:03
{
"result"
:
{
"id"
:
618
,
"orgId"
:
1
,
"folderId"
:
136
,
"folderUid"
:
"bemeqa2prz7k0d"
,
"uid"
:
"fen3y5c3e8q2of"
,
"name"
:
"P9801010-3DS Result Overview"
,
"kind"
:
1
,
"type"
:
"marcusolsson-dynamictext-panel"
,
"description"
:
"Provides a clearer understanding that the section summarizes the results of 3D Secure authentication."
,
"model"
:
{
"datasource"
:
{
"type"
:
"elasticsearch"
,
"uid"
:
"f45b49c9-ba56-43c8-b278-a87adffdb57c"
},
"description"
:
"Provides a clearer understanding that the section summarizes the results of 3D Secure authentication."
,
"fieldConfig"
:
{
"defaults"
:
{
"thresholds"
:
{
"mode"
:
"absolute"
,
"steps"
:
[
{
"color"
:
"green"
,
"value"
:
null
}
]
},
"unit"
:
"locale"
},
"overrides"
:
[
]
},
"gridPos"
:
{
"h"
:
9
,
"w"
:
16
,
"x"
:
8
,
"y"
:
1
},
"id"
:
9801010
,
"options"
:
{
"afterRender"
:
"let currentSortField = 'Count';
\r\n
let currentSortOrder = 'desc';
\r\n\r\n
function generate3DSResultItems(data, sortField = 'Count', sortOrder = 'desc') {
\r\n
const tableBody = document.getElementById('dsresult-table-body');
\r\n
const tableFooter = document.getElementById('dsresult-table-footer');
\r\n
tableBody.innerHTML = '';
\r\n
tableFooter.innerHTML = '';
\r\n\r\n
// 計算筆數總和(數字型)
\r\n
const totalCount = data.reduce((acc, item) => {
\r\n
const num = Number(String(item.Count).replace(/,/g, ''));
\r\n
return acc + (isNaN(num) ? 0 : num);
\r\n
}, 0);
\r\n\r\n
// 排序
\r\n
data.sort((a, b) => {
\r\n
let valA = a[sortField];
\r\n
let valB = b[sortField];
\r\n\r\n
const numA = Number(String(valA).replace(/,/g, ''));
\r\n
const numB = Number(String(valB).replace(/,/g, ''));
\r\n\r\n
if (!isNaN(numA) && !isNaN(numB)) {
\r\n
return sortOrder === 'asc' ? numA - numB : numB - numA;
\r\n
} else {
\r\n
return sortOrder === 'asc' ? String(valA).localeCompare(String(valB)) : String(valB).localeCompare(String(valA));
\r\n
}
\r\n
});
\r\n\r\n
// 產生資料列
\r\n
data.forEach(item => {
\r\n
const tr = document.createElement('tr');
\r\n\r\n
// 交易狀態欄
\r\n
const tdStatus = document.createElement('td');
\r\n
tdStatus.textContent = item.feedbackInfo__transStatus;
\r\n
tr.appendChild(tdStatus);
\r\n\r\n
// 筆數欄
\r\n
const tdCount = document.createElement('td');
\r\n
tdCount.textContent = item.Count;
\r\n
tr.appendChild(tdCount);
\r\n\r\n
// 百分比欄
\r\n
const tdPercent = document.createElement('td');
\r\n
const numCount = Number(String(item.Count).replace(/,/g, ''));
\r\n
let percentText = totalCount > 0 ? ((numCount / totalCount) * 100).toFixed(2) + '%' : '0.00%';
\r\n
tdPercent.textContent = percentText;
\r\n
tr.appendChild(tdPercent);
\r\n\r\n
tableBody.appendChild(tr);
\r\n
});
\r\n\r\n
// 產生表尾加總
\r\n
const footerRow = document.createElement('tr');
\r\n\r\n
// 合併前兩欄 (狀態欄顯示 Total)
\r\n
const totalLabelCell = document.createElement('td');
\r\n
totalLabelCell.textContent = 'Total';
\r\n
totalLabelCell.colSpan = 1;
\r\n
totalLabelCell.style.textAlign = 'left';
\r\n
footerRow.appendChild(totalLabelCell);
\r\n\r\n
// 筆數總和欄
\r\n
const totalCountCell = document.createElement('td');
\r\n
totalCountCell.textContent = totalCount.toLocaleString();
\r\n
footerRow.appendChild(totalCountCell);
\r\n\r\n
// 百分比欄空白
\r\n
const emptyCell = document.createElement('td');
\r\n
emptyCell.textContent = '';
\r\n
footerRow.appendChild(emptyCell);
\r\n\r\n
tableFooter.appendChild(footerRow);
\r\n
}
\r\n\r\n
function setup3DSResultTableHeader(data) {
\r\n
const tableHeader = document.getElementById('dsresult-table-header');
\r\n
tableHeader.innerHTML = '';
\r\n\r\n
const headers = [
\r\n
{ text: 'Transaction Status', field: 'feedbackInfo__transStatus' },
\r\n
{ text: 'Volume', field: 'Count' },
\r\n
{ text: 'Percentage', field: 'Percent' } // 注意這是虛擬欄位,不在原始資料裡
\r\n
];
\r\n\r\n
const headerRow = document.createElement('tr');
\r\n\r\n
headers.forEach(header => {
\r\n
const th = document.createElement('th');
\r\n
th.textContent = header.text;
\r\n
th.style.cursor = header.field !== 'Percent' ? 'pointer' : 'default'; // 百分比欄不可排序
\r\n
th.dataset.field = header.field;
\r\n\r\n
if (header.field !== 'Percent') {
\r\n
th.addEventListener('click', () => {
\r\n
if (currentSortField === header.field) {
\r\n
currentSortOrder = currentSortOrder === 'asc' ? 'desc' : 'asc';
\r\n
} else {
\r\n
currentSortField = header.field;
\r\n
currentSortOrder = 'asc';
\r\n
}
\r\n
generate3DSResultItems(data, currentSortField, currentSortOrder);
\r\n
updateTableHeaderSortIndicator(headers);
\r\n
});
\r\n
}
\r\n\r\n
headerRow.appendChild(th);
\r\n
});
\r\n\r\n
tableHeader.appendChild(headerRow);
\r\n
}
\r\n\r\n
function updateTableHeaderSortIndicator(headers) {
\r\n
const ths = document.querySelectorAll('#dsresult-table-header th');
\r\n
ths.forEach(th => {
\r\n
const field = th.dataset.field;
\r\n
const header = headers.find(h => h.field === field);
\r\n
if (!header) return;
\r\n\r\n
if (field === currentSortField) {
\r\n
th.textContent = `${header.text} ${currentSortOrder === 'asc' ? '▲' : '▼'}`;
\r\n
} else {
\r\n
th.textContent = header.text;
\r\n
}
\r\n
});
\r\n
}
\r\n\r\n
// 初始化
\r\n
if (Array.isArray(context.data) && context.data.length > 0 && Array.isArray(context.data[0])) {
\r\n
const tableData = context.data[0];
\r\n
setup3DSResultTableHeader(tableData);
\r\n
generate3DSResultItems(tableData);
\r\n
}
\r\n
"
,
"content"
:
"<div class=
\"
dsresult-table-container
\"
>
\n
<table class=
\"
dsresult-table
\"
>
\n
<thead id=
\"
dsresult-table-header
\"
></thead>
\n
<tbody id=
\"
dsresult-table-body
\"
></tbody>
\n
</table>
\n
<p>
\n
<table class=
\"
dsresult-table-footer dsresult-table
\"
>
\n
<tfoot id=
\"
dsresult-table-footer
\"
></tfoot>
\n
</table>
\n
</div>
\n
"
,
"contentPartials"
:
[
],
"defaultContent"
:
"The query didn't return any results."
,
"editor"
:
{
"format"
:
"auto"
,
"language"
:
"markdown"
},
"editors"
:
[
"afterRender"
,
"styles"
],
"externalStyles"
:
[
],
"helpers"
:
""
,
"renderMode"
:
"data"
,
"styles"
:
"
\r\n
/* 表格本體 */
\r\n
.dsresult-table {
\r\n
border-collapse: collapse;
\r\n
width: 100%;
\r\n
//font-family: 'Segoe UI', 'Roboto Mono', 'Noto Sans TC', monospace;
\r\n
table-layout: fixed;
\r\n
}
\r\n\r\n
.dsresult-table-footer {
\r\n
position: sticky;
\r\n
bottom: 0;
\r\n
z-index: 3;
\r\n
//pointer-events: none; /* 若不需互動 */
\r\n
backdrop-filter: blur(15px);
\r\n
}
\r\n\r\n
/* 固定 header 和 footer */
\r\n
.dsresult-table thead th, .dsresult-table tfoot td {
\r\n
position: sticky;
\r\n
z-index: 2;
\r\n
}
\r\n\r\n
/* 表頭固定在頂部 */
\r\n
.dsresult-table thead th {
\r\n
top: 0;
\r\n
text-align: center;
\r\n
//padding: 8px;
\r\n
//font-weight: bold;
\r\n
//border-bottom: 1px solid rgba(100, 181, 246, 0.4);
\r\n
}
\r\n\r\n
/* 表尾固定在底部 */
\r\n
.dsresult-table tfoot td {
\r\n
bottom: 0;
\r\n
//font-weight: bold;
\r\n
//padding: 8px;
\r\n
//border-top: 1px solid rgba(100, 181, 246, 0.4);
\r\n
}
\r\n\r\n
.dsresult-table td:first-child,
\r\n
.dsresult-table th:first-child {
\r\n
width: 20%;
\r\n
}
\r\n\r\n
/* 表格內容欄位 */
\r\n
.dsresult-table tbody td {
\r\n
padding: 8px;
\r\n
//font-size: 16px;
\r\n
//color: #e0f7fa;
\r\n
//border-bottom: 1px solid rgba(100, 181, 246, 0.1);
\r\n
}
\r\n\r\n
/* 交易狀態置中 */
\r\n
.dsresult-table tbody td:first-child {
\r\n
text-align: center;
\r\n
}
\r\n\r\n
.dsresult-table tfoot td:first-child{
\r\n
text-align: left;
\r\n
}
\r\n
/* 筆數與百分比靠右 */
\r\n
.dsresult-table tbody td:nth-child(2),
\r\n
.dsresult-table tfoot td:nth-child(2),
\r\n
.dsresult-table tbody td:nth-child(3),
\r\n
.dsresult-table tfoot td:nth-child(3) {
\r\n
text-align: right;
\r\n
font-variant-numeric: tabular-nums;
\r\n
}
\r\n\r\n
/* 滑鼠提示效果 */
\r\n
.dsresult-table thead th {
\r\n
cursor: pointer;
\r\n
}
\r\n\r\n
.dsresult-table-footer, .dsresult-table-footer td {
\r\n
border: none;
\r\n
}
\r\n
.dsresult-table-footer {
\r\n
border-top: 1px solid rgba(204, 204, 220, 0.2);;
\r\n
}
\r\n\r\n
/* hover 效果 */
\r\n
.dsresult-table tbody tr:hover {
\r\n
//background-color: rgba(66, 165, 245, 0.1);
\r\n
}
\r\n
"
,
"wrap"
:
true
},
"pluginVersion"
:
"5.7.0"
,
"targets"
:
[
{
"alias"
:
""
,
"bucketAggs"
:
[
{
"field"
:
"feedbackInfo__transStatus"
,
"id"
:
"2"
,
"settings"
:
{
"min_doc_count"
:
"1"
,
"missing"
:
"nan"
,
"order"
:
"desc"
,
"orderBy"
:
"_term"
,
"size"
:
"0"
},
"type"
:
"terms"
}
],
"datasource"
:
{
"type"
:
"elasticsearch"
,
"uid"
:
"f45b49c9-ba56-43c8-b278-a87adffdb57c"
},
"metrics"
:
[
{
"id"
:
"1"
,
"type"
:
"count"
}
],
"query"
:
"${process_query:raw}"
,
"refId"
:
"A"
,
"timeField"
:
"create_datetime"
}
],
"title"
:
"A-07. 3DS Authentication Outcome Breakdown"
,
"type"
:
"marcusolsson-dynamictext-panel"
},
"version"
:
39
,
"meta"
:
{
"folderName"
:
"R98-Library"
,
"folderUid"
:
"bemeqa2prz7k0d"
,
"connectedDashboards"
:
4
,
"created"
:
"2025-05-27T10:43:32+08:00"
,
"updated"
:
"2025-06-04T17:48:05+08:00"
,
"createdBy"
:
{
"avatarUrl"
:
"/avatar/ce6412d58e966caaa26cac12eb99734b"
,
"id"
:
1
,
"name"
:
"admin"
},
"updatedBy"
:
{
"avatarUrl"
:
"/avatar/ce6412d58e966caaa26cac12eb99734b"
,
"id"
:
1
,
"name"
:
"admin"
}
}
}
}
« 上一頁
1
…
13
14
15
16
17
…
30
下一頁 »
(15-15/30)
載入中...