+
+
-
日期范围
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
无可选 LinkName
-
尚未需要汇率换算
@@ -193,11 +223,17 @@
filters: document.getElementById('filters'),
currency: document.getElementById('currency-select'),
currencyHelp: document.getElementById('currency-help'),
+ rangeSelect: document.getElementById('range-select'),
+ dateFields: document.getElementById('date-fields'),
startDate: document.getElementById('start-date'),
endDate: document.getElementById('end-date'),
- linkName: document.getElementById('link-name-select'),
+ linkNamePicker: document.getElementById('link-name-picker'),
+ linkNameTrigger: document.getElementById('link-name-trigger'),
+ linkNamePanel: document.getElementById('link-name-panel'),
+ linkNameSearch: document.getElementById('link-name-search'),
+ linkNameList: document.getElementById('link-name-list'),
+ linkNameActions: Array.from(document.querySelectorAll('[data-action]')),
linkNameSummary: document.getElementById('link-name-summary'),
- rangeButtons: Array.from(document.querySelectorAll('[data-range]')),
rateStatus: document.getElementById('rate-status'),
metrics: document.getElementById('metrics'),
recordCount: document.getElementById('record-count'),
@@ -223,7 +259,9 @@
invalidCurrencyRows: 0,
syncLog: null,
syncLogUnavailable: false,
- selectedLinkNames: new Set()
+ availableLinkNames: [],
+ selectedLinkNames: new Set(),
+ draftLinkNames: new Set()
};
function setStatus(message, status) {
@@ -408,13 +446,19 @@
var dates = state.rawRecords.map(function (record) { return record.date; }).sort(function (a, b) { return a.time - b.time; });
var first = dates[0];
var latest = dates[dates.length - 1];
+ elements.rangeSelect.value = rangeName;
+ elements.dateFields.hidden = rangeName !== 'custom';
+ if (rangeName === 'custom') {
+ if (!elements.startDate.value) elements.startDate.value = first.key;
+ if (!elements.endDate.value) elements.endDate.value = latest.key;
+ return;
+ }
var start = first;
if (rangeName === 'month') start = parseDate(latest.key.slice(0, 7) + '-01');
if (rangeName === 'recent') start = new Date(latest.time - 29 * 24 * 60 * 60 * 1000);
var startKey = rangeName === 'recent' ? new Date(Date.UTC(start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate())).toISOString().slice(0, 10) : start.key;
- elements.startDate.value = startKey < first.key ? first.key : startKey;
+ elements.startDate.value = rangeName === 'all' ? first.key : (startKey < first.key ? first.key : startKey);
elements.endDate.value = latest.key;
- elements.rangeButtons.forEach(function (button) { button.dataset.active = button.dataset.range === rangeName ? 'true' : 'false'; });
}
function currentRange() {
@@ -425,15 +469,65 @@
}
function updateLinkNameSummary() {
- var total = elements.linkName.options.length;
- var selected = elements.linkName.selectedOptions.length;
+ var total = state.availableLinkNames.length;
+ var selected = state.selectedLinkNames.size;
+ var label;
if (!total) {
- elements.linkNameSummary.textContent = '无可选 LinkName';
+ label = '无可选 LinkName';
} else if (selected === total) {
- elements.linkNameSummary.textContent = '全部 LinkName(' + formatNumber(total) + ')';
+ label = '全部 LinkName';
} else {
- elements.linkNameSummary.textContent = '已选 ' + formatNumber(selected) + ' / ' + formatNumber(total) + ' 个 LinkName';
+ label = '已选 ' + formatNumber(selected) + ' 项';
}
+ elements.linkNameTrigger.textContent = label;
+ elements.linkNameSummary.textContent = label;
+ }
+
+ function renderLinkNameOptions() {
+ elements.linkNameList.replaceChildren();
+ var query = elements.linkNameSearch.value.trim().toLocaleLowerCase();
+ var visibleCount = 0;
+ state.availableLinkNames.forEach(function (linkName) {
+ if (query && linkName.toLocaleLowerCase().indexOf(query) === -1) return;
+ visibleCount += 1;
+ var label = document.createElement('label');
+ label.className = 'multi-select-option';
+ var checkbox = document.createElement('input');
+ checkbox.type = 'checkbox';
+ checkbox.value = linkName;
+ checkbox.checked = state.draftLinkNames.has(linkName);
+ checkbox.setAttribute('aria-label', linkName);
+ checkbox.addEventListener('change', function () {
+ if (checkbox.checked) state.draftLinkNames.add(linkName);
+ else state.draftLinkNames.delete(linkName);
+ });
+ var text = document.createElement('span');
+ text.textContent = linkName;
+ label.appendChild(checkbox);
+ label.appendChild(text);
+ elements.linkNameList.appendChild(label);
+ });
+ if (!visibleCount) {
+ var empty = document.createElement('div');
+ empty.className = 'multi-select-empty';
+ empty.textContent = '没有匹配的 LinkName';
+ elements.linkNameList.appendChild(empty);
+ }
+ }
+
+ function closeLinkNamePicker() {
+ elements.linkNamePanel.hidden = true;
+ elements.linkNameTrigger.setAttribute('aria-expanded', 'false');
+ }
+
+ function openLinkNamePicker() {
+ if (elements.linkNameTrigger.disabled) return;
+ state.draftLinkNames = new Set(state.selectedLinkNames);
+ elements.linkNameSearch.value = '';
+ renderLinkNameOptions();
+ elements.linkNamePanel.hidden = false;
+ elements.linkNameTrigger.setAttribute('aria-expanded', 'true');
+ elements.linkNameSearch.focus();
}
function updateLinkNameOptions() {
@@ -448,16 +542,12 @@
} catch (error) {
available = [];
}
- elements.linkName.replaceChildren();
- available.forEach(function (linkName) {
- var option = document.createElement('option');
- option.value = linkName;
- option.textContent = linkName;
- option.selected = true;
- elements.linkName.appendChild(option);
- });
+ state.availableLinkNames = available;
state.selectedLinkNames = new Set(available);
- elements.linkName.disabled = available.length === 0;
+ state.draftLinkNames = new Set(available);
+ elements.linkNameTrigger.disabled = available.length === 0;
+ closeLinkNamePicker();
+ renderLinkNameOptions();
updateLinkNameSummary();
}
@@ -696,25 +786,47 @@
state.selectedCurrency = elements.currency.value;
renderCurrentView();
});
- elements.linkName.addEventListener('change', function () {
- state.selectedLinkNames = new Set(Array.from(elements.linkName.selectedOptions).map(function (option) {
- return option.value;
- }));
- updateLinkNameSummary();
+ elements.rangeSelect.addEventListener('change', function () {
+ setRange(elements.rangeSelect.value);
+ updateLinkNameOptions();
renderCurrentView();
});
elements.startDate.addEventListener('change', function () {
- elements.rangeButtons.forEach(function (button) { button.dataset.active = 'false'; });
updateLinkNameOptions();
renderCurrentView();
});
elements.endDate.addEventListener('change', function () {
- elements.rangeButtons.forEach(function (button) { button.dataset.active = 'false'; });
updateLinkNameOptions();
renderCurrentView();
});
- elements.rangeButtons.forEach(function (button) {
- button.addEventListener('click', function () { setRange(button.dataset.range); updateLinkNameOptions(); renderCurrentView(); });
+ elements.linkNameTrigger.addEventListener('click', function () {
+ if (elements.linkNamePanel.hidden) openLinkNamePicker();
+ else closeLinkNamePicker();
+ });
+ elements.linkNameSearch.addEventListener('input', renderLinkNameOptions);
+ elements.linkNameActions.forEach(function (button) {
+ button.addEventListener('click', function () {
+ var action = button.dataset.action;
+ if (action === 'select-all') state.draftLinkNames = new Set(state.availableLinkNames);
+ if (action === 'clear') state.draftLinkNames = new Set();
+ if (action === 'confirm') {
+ state.selectedLinkNames = new Set(state.draftLinkNames);
+ updateLinkNameSummary();
+ closeLinkNamePicker();
+ renderCurrentView();
+ return;
+ }
+ renderLinkNameOptions();
+ });
+ });
+ document.addEventListener('click', function (event) {
+ if (!elements.linkNamePicker.contains(event.target)) closeLinkNamePicker();
+ });
+ document.addEventListener('keydown', function (event) {
+ if (event.key === 'Escape' && !elements.linkNamePanel.hidden) {
+ closeLinkNamePicker();
+ elements.linkNameTrigger.focus();
+ }
});
window.addEventListener('resize', function () { charts.forEach(function (chart) { chart.resize(); }); });
loadData();