Show authenticated daily operation records
This commit is contained in:
@@ -67,6 +67,31 @@ export function createApp(options = process.env) {
|
||||
return results.sort((a, b) => String(b.period_end || b.id).localeCompare(String(a.period_end || a.id)));
|
||||
}
|
||||
|
||||
async function dailyRecords() {
|
||||
let directory;
|
||||
try { directory = await realpath(path.join(dataDir, 'daily')); }
|
||||
catch (error) { if (error.code === 'ENOENT') return { records: [], invalid_count: 0 }; throw error; }
|
||||
const actualRoot = await realpath(dataDir);
|
||||
if (!directory.startsWith(actualRoot + path.sep)) throw new Error('Data path escapes DATA_DIR');
|
||||
const names = await readdir(directory);
|
||||
const fields = ['planned', 'executed', 'evidence', 'costs', 'review', 'tomorrow'];
|
||||
const records = []; let invalidCount = 0;
|
||||
for (const name of names.filter(n => /^\d{4}-\d{2}-\d{2}\.json$/.test(n)).sort().reverse()) {
|
||||
const day = name.slice(0, -5);
|
||||
const parsed = new Date(day + 'T00:00:00Z');
|
||||
if (!Number.isFinite(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== day) { invalidCount++; continue; }
|
||||
try {
|
||||
const item = await jsonFile(`daily/${name}`, null);
|
||||
if (!item || Array.isArray(item) || typeof item !== 'object' || item.date !== day ||
|
||||
fields.some(field => item[field] !== undefined && (!Array.isArray(item[field]) || item[field].some(value => typeof value !== 'string')))) {
|
||||
invalidCount++; continue;
|
||||
}
|
||||
records.push({ date: day, ...Object.fromEntries(fields.map(field => [field, item[field] || []])) });
|
||||
} catch { invalidCount++; }
|
||||
}
|
||||
return { records, invalid_count: invalidCount };
|
||||
}
|
||||
|
||||
function json(res, status, body, extra = {}) {
|
||||
res.writeHead(status, { 'Content-Type': 'application/json; charset=utf-8', ...extra });
|
||||
res.end(JSON.stringify(body));
|
||||
@@ -130,6 +155,7 @@ export function createApp(options = process.env) {
|
||||
if (route.startsWith('/api/')) {
|
||||
if (!session(req)) return json(res, 401, { error: '请先登录' });
|
||||
if (req.method === 'GET' && route === '/api/evolution') return json(res, 200, await jsonFile('evolution.json', { schema_version: 1, events: [] }));
|
||||
if (req.method === 'GET' && route === '/api/daily') return json(res, 200, await dailyRecords());
|
||||
if (req.method === 'GET' && route === '/api/dashboard') {
|
||||
const list = await reports();
|
||||
const config = await jsonFile('config.json', { title: 'PawPlay 运营台', timezone: 'Asia/Shanghai', budget: { billing_period: 'pending' } });
|
||||
|
||||
Reference in New Issue
Block a user