feat: 搭建二期项目架构
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
function element(tag, className, text) {
|
||||
const el = document.createElement(tag);
|
||||
if (className) el.className = className;
|
||||
if (text !== undefined) el.textContent = text;
|
||||
return el;
|
||||
}
|
||||
|
||||
function button(label, { active = false, onClick, className = '' } = {}) {
|
||||
const el = element('button', className, label);
|
||||
el.type = 'button';
|
||||
el.dataset.active = String(active);
|
||||
if (onClick) el.addEventListener('click', onClick);
|
||||
return el;
|
||||
}
|
||||
|
||||
export function createAppShell(root, { onReload }) {
|
||||
root.replaceChildren();
|
||||
|
||||
const header = element('header', 'app-header');
|
||||
const brand = element('div', 'app-brand');
|
||||
brand.append(element('h1', '', '财报图表'), element('p', '', '选择公司与分析维度,数据更新后可重新加载。'));
|
||||
header.append(brand, button('重新加载数据', { onClick: onReload, className: 'reload-button' }));
|
||||
|
||||
const layout = element('div', 'app-layout');
|
||||
const companyNav = element('aside', 'sidebar company-sidebar');
|
||||
const content = element('main', 'content');
|
||||
const tabs = element('nav', 'tabs');
|
||||
const cards = element('div', 'cards');
|
||||
content.append(tabs, cards);
|
||||
const chartNav = element('aside', 'sidebar chart-sidebar');
|
||||
layout.append(companyNav, content, chartNav);
|
||||
root.append(header, layout);
|
||||
|
||||
return { companyNav, tabs, cards, chartNav };
|
||||
}
|
||||
|
||||
export function renderCompanies(container, companies, activeCompanyId, onSelect) {
|
||||
container.replaceChildren(element('h2', 'sidebar-title', '公司'));
|
||||
const list = element('div', 'company-list');
|
||||
companies.forEach((company) => {
|
||||
list.append(button(company.name, {
|
||||
active: company.id === activeCompanyId,
|
||||
onClick: () => onSelect(company.id),
|
||||
className: 'company-button',
|
||||
}));
|
||||
});
|
||||
container.append(list);
|
||||
}
|
||||
|
||||
export function renderTabs(container, tabs, activeTabId, onSelect) {
|
||||
container.replaceChildren();
|
||||
tabs.forEach((tab) => {
|
||||
container.append(button(tab.name, {
|
||||
active: tab.id === activeTabId,
|
||||
onClick: () => onSelect(tab.id),
|
||||
className: 'tab-button',
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
export function renderCards(container, charts, activeViews, { onExport, onSelectView }) {
|
||||
container.replaceChildren();
|
||||
if (!charts.length) {
|
||||
container.append(element('p', 'empty-state', '该分类暂时没有图表。'));
|
||||
return;
|
||||
}
|
||||
|
||||
charts.forEach((chart) => {
|
||||
const card = element('section', 'card');
|
||||
card.id = `card-${chart.id}`;
|
||||
const bar = element('div', 'card-bar');
|
||||
const heading = element('div', 'card-heading');
|
||||
heading.append(element('h2', 'card-title', chart.title));
|
||||
|
||||
const viewNames = Object.keys(chart.views || {});
|
||||
const activeView = activeViews.get(chart.id) || chart.defaultView || viewNames[0];
|
||||
const source = chart.views ? chart.views[activeView] : chart.csv;
|
||||
heading.append(element('span', 'src', source));
|
||||
bar.append(heading);
|
||||
|
||||
if (viewNames.length > 1) {
|
||||
const switcher = element('div', 'view-switcher');
|
||||
const labels = { annual: '年度', halfyear: '半年', quarter: '季度' };
|
||||
viewNames.forEach((view) => {
|
||||
switcher.append(button(labels[view] || view, {
|
||||
active: view === activeView,
|
||||
onClick: () => onSelectView(chart.id, view),
|
||||
className: 'view-button',
|
||||
}));
|
||||
});
|
||||
bar.append(switcher);
|
||||
}
|
||||
|
||||
bar.append(button('导出 PNG', {
|
||||
onClick: () => onExport(chart.id, chart.filename || chart.title),
|
||||
className: 'export-button',
|
||||
}));
|
||||
const chartEl = element('div', 'chart');
|
||||
chartEl.id = `chart-${chart.id}`;
|
||||
chartEl.style.height = `${chart.height || 680}px`;
|
||||
card.append(bar, chartEl);
|
||||
container.append(card);
|
||||
});
|
||||
}
|
||||
|
||||
export function renderAnchors(container, charts, onSelect) {
|
||||
container.replaceChildren(element('h2', 'sidebar-title', '当前图表'));
|
||||
const list = element('div', 'anchor-list');
|
||||
charts.forEach((chart) => {
|
||||
container.append(button(chart.title, {
|
||||
onClick: () => onSelect(chart.id),
|
||||
className: 'anchor-button',
|
||||
}));
|
||||
});
|
||||
if (!charts.length) container.append(element('p', 'sidebar-empty', '暂无图表'));
|
||||
}
|
||||
|
||||
export function showChartError(chartId, message) {
|
||||
const chartEl = document.getElementById(`chart-${chartId}`);
|
||||
if (!chartEl) return;
|
||||
chartEl.replaceChildren(element('div', 'chart-error', message));
|
||||
}
|
||||
Reference in New Issue
Block a user