feat: potenziata visualizzazione storico consuntivazione. style: disabilitata apertura massiva. feat: migliorata modifica pdf e scaricamento di tutti gli allegati tramite shortcut.

This commit is contained in:
Gabriele Cimaschi committed 2026-09-10 01:02:25 +02:00
1 parent b1754c3a67
commit c7b18ac959
10 files changed
+1545 -191

No files matched your search

+95 -39
View File
@@ -2151,50 +2151,98 @@ router.post('/merge', async (req, res) => {
router.get('/time-accounting/summary', async (req, res) => {
try {
const operatorId = parseInt(req.headers['x-agent-id'], 10) || 1;
const agentId = parseInt(req.query.agent_id, 10) || operatorId;
const agentIdsRaw = req.query.agent_ids || req.query.agent_id || String(operatorId);
const agentIds = agentIdsRaw.split(',').map(x => parseInt(x.trim(), 10)).filter(x => !isNaN(x));
const dateStr = req.query.date || new Date().toISOString().slice(0, 10);
const targetDate = new Date(`${dateStr}T00:00:00Z`);
const startDateObj = new Date(targetDate);
startDateObj.setDate(startDateObj.getDate() - 14);
const endDateObj = new Date(targetDate);
endDateObj.setDate(endDateObj.getDate() + 14);
const rangeParam = req.query.range || '35';
const isAll = rangeParam === 'all';
let result;
if (isAll) {
result = await pool.query(
`SELECT
a.id AS article_id,
a.ticket_id,
a.create_by AS agent_id,
t.tn AS ticket_tn,
t.title AS ticket_title,
ast.name AS sender_type,
cc.name AS channel,
adm.a_subject,
adm.a_body,
adm.a_from,
adm.a_to,
a.create_time,
COALESCE(ta.time_unit, 0) AS time_unit
FROM article a
JOIN ticket t ON a.ticket_id = t.id
JOIN article_sender_type ast ON a.article_sender_type_id = ast.id
LEFT JOIN communication_channel cc ON a.communication_channel_id = cc.id
LEFT JOIN article_data_mime adm ON a.id = adm.article_id
LEFT JOIN (
SELECT article_id, SUM(time_unit) AS time_unit
FROM time_accounting
GROUP BY article_id
) ta ON a.id = ta.article_id
WHERE a.create_by = ANY($1::int[])
ORDER BY a.create_time DESC, a.id DESC`,
[agentIds]
);
} else {
const targetDate = new Date(`${dateStr}T00:00:00Z`);
let startDateObj, endDateObj;
const startTime = `${startDateObj.toISOString().slice(0, 10)} 00:00:00`;
const endTime = `${endDateObj.toISOString().slice(0, 10)} 23:59:59`;
if (rangeParam === 'month') {
const y = targetDate.getUTCFullYear();
const m = targetDate.getUTCMonth();
startDateObj = new Date(Date.UTC(y, m, 1));
endDateObj = new Date(Date.UTC(y, m + 1, 0));
} else {
const daysBack = parseInt(rangeParam, 10) || 35;
startDateObj = new Date(targetDate);
startDateObj.setDate(startDateObj.getDate() - daysBack);
endDateObj = new Date(targetDate);
endDateObj.setDate(endDateObj.getDate() + 5);
}
const result = await pool.query(
`SELECT
a.id AS article_id,
a.ticket_id,
t.tn AS ticket_tn,
t.title AS ticket_title,
ast.name AS sender_type,
cc.name AS channel,
adm.a_subject,
adm.a_body,
adm.a_from,
adm.a_to,
a.create_time,
COALESCE(ta.time_unit, 0) AS time_unit
FROM article a
JOIN ticket t ON a.ticket_id = t.id
JOIN article_sender_type ast ON a.article_sender_type_id = ast.id
LEFT JOIN communication_channel cc ON a.communication_channel_id = cc.id
LEFT JOIN article_data_mime adm ON a.id = adm.article_id
LEFT JOIN (
SELECT article_id, SUM(time_unit) AS time_unit
FROM time_accounting
GROUP BY article_id
) ta ON a.id = ta.article_id
WHERE a.create_by = $1
AND a.create_time >= $2
AND a.create_time <= $3
ORDER BY a.create_time DESC, a.id DESC`,
[agentId, startTime, endTime]
);
const startTime = `${startDateObj.toISOString().slice(0, 10)} 00:00:00`;
const endTime = `${endDateObj.toISOString().slice(0, 10)} 23:59:59`;
result = await pool.query(
`SELECT
a.id AS article_id,
a.ticket_id,
a.create_by AS agent_id,
t.tn AS ticket_tn,
t.title AS ticket_title,
ast.name AS sender_type,
cc.name AS channel,
adm.a_subject,
adm.a_body,
adm.a_from,
adm.a_to,
a.create_time,
COALESCE(ta.time_unit, 0) AS time_unit
FROM article a
JOIN ticket t ON a.ticket_id = t.id
JOIN article_sender_type ast ON a.article_sender_type_id = ast.id
LEFT JOIN communication_channel cc ON a.communication_channel_id = cc.id
LEFT JOIN article_data_mime adm ON a.id = adm.article_id
LEFT JOIN (
SELECT article_id, SUM(time_unit) AS time_unit
FROM time_accounting
GROUP BY article_id
) ta ON a.id = ta.article_id
WHERE a.create_by = ANY($1::int[])
AND a.create_time >= $2
AND a.create_time <= $3
ORDER BY a.create_time DESC, a.id DESC`,
[agentIds, startTime, endTime]
);
}
const dailyTotals = {};
const dailyTotalsByAgent = {};
const dayArticles = [];
let totalMinutes = 0;
@@ -2209,9 +2257,15 @@ router.get('/time-accounting/summary', async (req, res) => {
isoDate = String(r.create_time || '').slice(0, 10);
}
const timeVal = parseFloat(r.time_unit || 0);
const agId = r.agent_id;
dailyTotals[isoDate] = (dailyTotals[isoDate] || 0) + timeVal;
if (!dailyTotalsByAgent[agId]) {
dailyTotalsByAgent[agId] = {};
}
dailyTotalsByAgent[agId][isoDate] = (dailyTotalsByAgent[agId][isoDate] || 0) + timeVal;
if (isoDate === dateStr) {
dayArticles.push(r);
totalMinutes += timeVal;
@@ -2223,13 +2277,15 @@ router.get('/time-accounting/summary', async (req, res) => {
const workDays = workDaysRaw.split(',').map(x => parseInt(x.trim(), 10)).filter(x => !isNaN(x));
res.json({
agent_id: agentId,
agent_id: agentIds[0],
agent_ids: agentIds,
date: dateStr,
total_minutes: totalMinutes,
target_minutes: targetMinutes,
work_days: workDays,
articles: dayArticles,
daily_totals: dailyTotals,
daily_totals_by_agent: dailyTotalsByAgent,
});
} catch (err) {
console.error('Error fetching time accounting summary:', err);