|
"afterRender" : "let p9803003_field = 'txCount';\r\nlet p9803003_sourtorder = 'desc';\r\n\r\nconst p9803003_headers = [\r\n { text: 'Source IP', field: 'Key', type: 'text' },\r\n { text: 'Countries/Regions', field: 'countryName', type: 'text' },\r\n { text: 'Volume', field: 'DocCount', type: 'number' },\r\n { text: 'Distinct Payment Cards Use', field: 'AccountCount', type: 'number' },\r\n { text: 'Number of Distinct Devices', field: 'DeviceCount', type: 'number' },\r\n { text: 'High-Risk', field: 'HighRisk', type: 'number' },\r\n];\r\n\r\n// 加總欄位\r\nconst p9803003_totals = {\r\n DocCount: 0,\r\n AccountCount: 0,\r\n DeviceCount: 0,\r\n HighRisk: 0\r\n};\r\n\r\n\r\n\r\nfunction setupP9803003TableHeader(data) {\r\n\r\n const tableHeader = document.getElementById('p9803003-table-header');\r\n tableHeader.innerHTML = '';\r\n\r\n const headerRow = document.createElement('tr');\r\n\r\n p9803003_headers.forEach(header => {\r\n const th = document.createElement('th');\r\n th.textContent = header.text;\r\n th.dataset.field = header.field;\r\n\r\n if (header.field !== 'countryName') {\r\n th.addEventListener('click', () => {\r\n if (p9803003_field === header.field) {\r\n p9803003_sourtorder = p9803003_sourtorder === 'asc' ? 'desc' : 'asc';\r\n } else {\r\n p9803003_field = header.field;\r\n p9803003_sourtorder = 'asc';\r\n }\r\n generateP9803003Items(data, p9803003_field, p9803003_sourtorder);\r\n updateP980001TableHeaderSortIndicator(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\nfunction generateP9803003Items(data, sortField = '', sortOrder = 'desc') {\r\n\r\n const tableBody = document.getElementById('p9803003-table-body');\r\n const tableFooter = document.getElementById('p9803003-table-footer');\r\n tableBody.innerHTML = '';\r\n tableFooter.innerHTML = '';\r\n\r\n // 排序\r\n data.sort((a, b) => {\r\n const valA = a[sortField];\r\n const 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'\r\n ? String(valA).localeCompare(String(valB))\r\n : String(valB).localeCompare(String(valA));\r\n }\r\n });\r\n\r\n resetP9803003Totals();\r\n\r\n data.forEach(item => {\r\n const row = document.createElement('tr');\r\n // {\r\n // const displayCountry = item.ipAddress;\r\n // row.appendChild(createP9803003Cell(displayCountry));\r\n // }\r\n // {\r\n // const displayCountry = item.countryName;\r\n // row.appendChild(createP9803003Cell(displayCountry));\r\n // }\r\n\r\n // const count = Number(String(item.txCount).replace(/,/g, '')) || 0;\r\n // const amount = Number(String(item.accountCount).replace(/,/g, '')) || 0;\r\n // const auth = Number(String(item.txCountUniDevice).replace(/,/g, '')) || 0;\r\n // const devices = Number(String(item.highCount).replace(/,/g, '')) || 0;\r\n\r\n // p9803003_totals.txCount += count;\r\n // p9803003_totals.accountCount += amount;\r\n // p9803003_totals.txCountUniDevice += auth;\r\n // p9803003_totals.highCount += devices;\r\n\r\n p9803003_headers.forEach(header => {\r\n\r\n let value = item[header.field];\r\n\r\n if (header.field === 'countryName') {\r\n value = value;\r\n } else if (header.type === 'number') {\r\n const numericValue = Number(String(value).replace(/,/g, '')) || 0;\r\n value = numericValue.toLocaleString();\r\n\r\n if (p9803003_totals.hasOwnProperty(header.field)) {\r\n p9803003_totals[header.field] += numericValue;\r\n }\r\n }\r\n row.appendChild(createP9803003Cell(value));\r\n });\r\n\r\n // row.appendChild(createP9803003Cell(count.toLocaleString()));\r\n // row.appendChild(createP9803003Cell(amount.toLocaleString()));\r\n // row.appendChild(createP9803003Cell(auth.toLocaleString()));\r\n // row.appendChild(createP9803003Cell(devices.toLocaleString()));\r\n\r\n tableBody.appendChild(row);\r\n });\r\n\r\n // 表尾加總列\r\n const footerRow = document.createElement('tr');\r\n footerRow.appendChild(createP9803003Cell('Total', true));\r\n footerRow.appendChild(createP9803003Cell('', true));\r\n footerRow.appendChild(createP9803003Cell(p9803003_totals.DocCount.toLocaleString(), true));\r\n footerRow.appendChild(createP9803003Cell(p9803003_totals.AccountCount.toLocaleString(), true));\r\n footerRow.appendChild(createP9803003Cell(p9803003_totals.DeviceCount.toLocaleString(), true));\r\n footerRow.appendChild(createP9803003Cell(p9803003_totals.HighRisk.toLocaleString(), true));\r\n tableFooter.appendChild(footerRow);\r\n}\r\n\r\nfunction createP9803003Cell(text, isFooter = false) {\r\n const cell = document.createElement('td');\r\n cell.textContent = text;\r\n if (isFooter) cell.style.fontWeight = 'bold';\r\n return cell;\r\n}\r\n\r\nfunction updateP980001TableHeaderSortIndicator(headers) {\r\n const ths = document.querySelectorAll('#p9803003-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 === p9803003_field) {\r\n th.textContent = `${header.text} ${p9803003_sourtorder === 'asc' ? '▲' : '▼'}`;\r\n } else {\r\n th.textContent = header.text;\r\n }\r\n });\r\n}\r\n\r\nfunction resetP9803003Totals() {\r\n for (const key in p9803003_totals) {\r\n if (Object.hasOwn(p9803003_totals, key)) p9803003_totals[key] = 0;\r\n }\r\n}\r\n\r\n// 初始化\r\nif (Array.isArray(context.data) && context.data.length > 0 && Array.isArray(context.data[0])) {\r\n const tableData = context.data[0];\r\n setupP9803003TableHeader(tableData);\r\n generateP9803003Items(tableData);\r\n}\r\n\r\n",
|
|
"styles" : "<style>\r\n.p9803003-table-container {\r\n width: 98%;\r\n margin: 0 auto;\r\n max-height: 180px; /* 必須設定 */\r\n overflow-y: auto; /* 讓內容可滾動 */\r\n position: relative; \r\n}\r\n\r\n/* 表格本體 */\r\n.p9803003-table {\r\n border-collapse: collapse;\r\n width: 100%;\r\n table-layout: fixed;\r\n}\r\n\r\n.p9803003-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.p9803003-table thead th, .p9803003-table tfoot td {\r\n position: sticky;\r\n z-index: 2;\r\n}\r\n\r\n/* 表頭固定在頂部 */\r\n.p9803003-table thead th {\r\n top: 0;\r\n text-align: center;\r\n}\r\n\r\n/* 表尾固定在底部 */\r\n.p9803003-table tfoot td {\r\n bottom: 0;\r\n}\r\n\r\n.p9803003-table td:first-child,\r\n.p9803003-table th:first-child {\r\n width: 20%;\r\n \r\n}\r\n.p9803003-table td:nth-child(2),\r\n.p9803003-table th:nth-child(2) {\r\n width: 18%;\r\n \r\n}\r\n.p9803003-table td:nth-child(3),\r\n.p9803003-table th:nth-child(3) {\r\n width: 9%;\r\n \r\n}\r\n.p9803003-table td:nth-child(4),\r\n.p9803003-table th:nth-child(4) {\r\n width: 26%;\r\n \r\n}\r\n.p9803003-table td:nth-child(6),\r\n.p9803003-table th:nth-child(6) {\r\n width: 10%;\r\n \r\n}\r\n/* 表格內容欄位 */\r\n.p9803003-table tbody td {\r\n padding: 8px;\r\n}\r\n\r\n.p9803003-table tbody td, .p9803003-table-footer tbody td, {\r\n text-align: right;\r\n font-variant-numeric: tabular-nums;\r\n}\r\n\r\n.p9803003-table tbody td:first-child {\r\n text-align: left;\r\n}\r\n.p9803003-table tbody td:nth-child(2) {\r\n text-align: center;\r\n}\r\n.p9803003-table-footer td:nth-child(1) {\r\n text-align: left;\r\n}\r\n.p9803003-table-footer, .p9803003-table-footer td {\r\n border: none;\r\n}\r\n.p9803003-table-footer {\r\n border-top: 1px solid rgba(204, 204, 220, 0.2);;\r\n}\r\n/* 滑鼠提示效果 */\r\n.p9803003-table thead th {\r\n cursor: pointer;\r\n}\r\n.p9803003-table td {\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n white-space: nowrap;\r\n}\r\n</style>",
|