Files
iistwin/server/routes/task-transitions.routes.ts
Ильяс Султанов 1f5ecb6da4 fix(number-fields): избегаем потери точности длинных чисел
- number-поля теперь рендерятся как text + inputMode=numeric,
  чтобы браузер не округлял значения через input type=number
- пробелы при вставке в number-поля удаляются
- бэкенд нормализует значения number-полей в строку перед сохранением
- добавлен хелпер normalizeFieldValueForStorage

Closes: искажение расчётного счёта и других длинных числовых полей
2026-07-07 21:03:40 +03:00

57 lines
1.8 KiB
TypeScript

import { Router } from "express";
import { authenticateToken, type AuthenticatedRequest } from "../middleware/auth.middleware";
import { tenantIsolation } from "../middleware/tenant.middleware";
import { executeTaskTransition } from "../services/task-transition.service";
import { parseOfflineTimestamp } from "./task-helpers";
export function registerTaskTransitionRoutes(router: ReturnType<typeof import("express").Router>): void {
router.post('/api/tasks/:id/transition',
authenticateToken,
tenantIsolation,
async (req: AuthenticatedRequest, res) => {
try {
const taskId = parseInt(req.params.id);
const { transitionId, action } = req.body; // action: 'approve' | 'reject'
if (isNaN(taskId) || !transitionId) {
return res.status(400).json({
success: false,
error: 'Неверные параметры'
});
}
const result = await executeTaskTransition({
taskId,
transitionId,
action,
user: req.user,
organizationId: req.organizationId!,
offlineEnqueuedAt: parseOfflineTimestamp(req),
});
if (!result.success) {
return res.status(result.status || 500).json({
success: false,
error: result.error,
...(result.fields ? { fields: result.fields } : {})
});
}
return res.json({
success: true,
message: result.message,
task: result.task
});
} catch (error) {
console.error('Transition route error:', error);
return res.status(500).json({
success: false,
error: 'Ошибка при выполнении перехода'
});
}
}
);
// Get task field values
}