feat: contatore tempo allocato, pagina miei ticket, unione ticket (da db)
This commit is contained in:
+51
-69
@@ -17,16 +17,31 @@ async function otrsRequest(method, path, bodyData = {}) {
|
||||
Password: OTRS_API_PASSWORD,
|
||||
...bodyData
|
||||
};
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`OTRS REST API error (${response.status}): ${errorText}`);
|
||||
|
||||
const controller = new AbortController();
|
||||
const timeoutId = setTimeout(() => controller.abort(), 6000);
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload),
|
||||
signal: controller.signal
|
||||
});
|
||||
clearTimeout(timeoutId);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`OTRS REST API error (${response.status}): ${errorText}`);
|
||||
}
|
||||
return await response.json();
|
||||
} catch (err) {
|
||||
clearTimeout(timeoutId);
|
||||
if (err.name === 'AbortError') {
|
||||
throw new Error('OTRS REST API request timed out (6s limit exceeded)');
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +110,32 @@ router.get('/users', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/config — Application config
|
||||
router.get('/config', (req, res) => {
|
||||
res.json({
|
||||
defaultAgentLogin: process.env.OTRS_API_USER || '',
|
||||
dailyTargetTime: parseInt(process.env.DAILY_TARGET_TIME, 10) || 480
|
||||
});
|
||||
});
|
||||
|
||||
// GET /api/users/time-today — Get sum of today's time units for active agent
|
||||
router.get('/users/time-today', async (req, res) => {
|
||||
try {
|
||||
const operatorId = parseInt(req.headers['x-agent-id'], 10) || 1;
|
||||
const result = await pool.query(
|
||||
`SELECT COALESCE(SUM(time_unit), 0) AS total_today
|
||||
FROM time_accounting
|
||||
WHERE create_by = $1 AND DATE(create_time) = CURRENT_DATE`,
|
||||
[operatorId]
|
||||
);
|
||||
res.json({ totalToday: parseFloat(result.rows[0].total_today) });
|
||||
} catch (err) {
|
||||
console.error('Error fetching today\'s time units:', err);
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// GET /api/types — Ticket types
|
||||
router.get('/types', async (req, res) => {
|
||||
try {
|
||||
@@ -150,70 +191,11 @@ router.get('/customer-companies/search', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/customer-users/search — Search customer users
|
||||
// GET /api/customer-users/search — Search customer users (always from local DB)
|
||||
router.get('/customer-users/search', async (req, res) => {
|
||||
try {
|
||||
const { q = '', customer_company_id } = req.query;
|
||||
|
||||
// Try OTRS API first if configured
|
||||
const OTRS_API_URL = process.env.OTRS_API_URL;
|
||||
const OTRS_API_USER = process.env.OTRS_API_USER;
|
||||
if (OTRS_API_URL && OTRS_API_USER) {
|
||||
try {
|
||||
const searchParams = {
|
||||
Search: q ? `*${q}*` : '*',
|
||||
Valid: 1
|
||||
};
|
||||
if (customer_company_id) {
|
||||
searchParams.CustomerID = customer_company_id;
|
||||
}
|
||||
|
||||
const searchRes = await otrsRequest('POST', '/CustomerUserSearch', searchParams);
|
||||
let logins = [];
|
||||
if (searchRes) {
|
||||
if (Array.isArray(searchRes.CustomerUserID)) {
|
||||
logins = searchRes.CustomerUserID;
|
||||
} else if (searchRes.Data && Array.isArray(searchRes.Data.CustomerUserID)) {
|
||||
logins = searchRes.Data.CustomerUserID;
|
||||
} else if (Array.isArray(searchRes)) {
|
||||
logins = searchRes;
|
||||
}
|
||||
}
|
||||
|
||||
if (logins.length > 0) {
|
||||
// Limit to top 20 logins to avoid rate/performance issues
|
||||
const limitedLogins = logins.slice(0, 20);
|
||||
const detailPromises = limitedLogins.map(async (login) => {
|
||||
try {
|
||||
const detailRes = await otrsRequest('POST', '/CustomerUserGet', { UserLogin: login });
|
||||
const userObj = detailRes?.CustomerUser;
|
||||
if (userObj) {
|
||||
return {
|
||||
login: userObj.UserLogin || login,
|
||||
email: userObj.UserEmail || '',
|
||||
first_name: userObj.UserFirstname || '',
|
||||
last_name: userObj.UserLastname || '',
|
||||
customer_id: userObj.UserCustomerID || ''
|
||||
};
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Error fetching details for user ${login}:`, err.message);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
const details = await Promise.all(detailPromises);
|
||||
const validUsers = details.filter(u => u !== null);
|
||||
if (validUsers.length > 0) {
|
||||
return res.json(validUsers);
|
||||
}
|
||||
}
|
||||
} catch (apiErr) {
|
||||
console.warn('OTRS CustomerUserSearch API request failed, falling back to local DB:', apiErr.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: local DB query
|
||||
let queryText;
|
||||
let queryParams;
|
||||
if (q) {
|
||||
|
||||
Reference in New Issue
Block a user