feat: 添加货币和汇率管理功能
refactor: 重构前端路由和登录逻辑 docs: 更新业务闭环、任务和架构文档 style: 调整代码格式和文件结构 chore: 更新依赖项和配置文件
This commit is contained in:
261
server/src/api/controllers/CurrencyController.ts
Normal file
261
server/src/api/controllers/CurrencyController.ts
Normal file
@@ -0,0 +1,261 @@
|
||||
import { Request, Response } from 'express';
|
||||
import currencyService from '../../services/CurrencyService';
|
||||
import exchangeRateService from '../../services/ExchangeRateService';
|
||||
import currencyConversionService from '../../services/CurrencyConversionService';
|
||||
import currencyCalculationService from '../../services/CurrencyCalculationService';
|
||||
import { PriceCalculationParams, ProfitCalculationParams } from '../../services/CurrencyCalculationService';
|
||||
|
||||
export class CurrencyController {
|
||||
// 货币管理相关接口
|
||||
static async getCurrencies(req: Request, res: Response) {
|
||||
try {
|
||||
const currencies = await currencyService.getCurrencies();
|
||||
res.json({ success: true, data: currencies });
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getCurrencyByCode(req: Request, res: Response) {
|
||||
const { code } = req.params;
|
||||
try {
|
||||
const currency = await currencyService.getCurrencyByCode(code);
|
||||
if (currency) {
|
||||
res.json({ success: true, data: currency });
|
||||
} else {
|
||||
res.status(404).json({ success: false, error: 'Currency not found' });
|
||||
}
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getDefaultCurrency(req: Request, res: Response) {
|
||||
try {
|
||||
const currency = await currencyService.getDefaultCurrency();
|
||||
if (currency) {
|
||||
res.json({ success: true, data: currency });
|
||||
} else {
|
||||
res.status(404).json({ success: false, error: 'Default currency not set' });
|
||||
}
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async createCurrency(req: Request, res: Response) {
|
||||
const { code, name, symbol, decimal_places, format, is_default } = req.body;
|
||||
const { userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const currency = await currencyService.createCurrency({
|
||||
code,
|
||||
name,
|
||||
symbol,
|
||||
decimal_places,
|
||||
format,
|
||||
is_default,
|
||||
created_by: userId,
|
||||
});
|
||||
res.status(201).json({ success: true, data: currency });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async updateCurrency(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { name, symbol, decimal_places, format, is_active, is_default } = req.body;
|
||||
const { userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const currency = await currencyService.updateCurrency(id, {
|
||||
name,
|
||||
symbol,
|
||||
decimal_places,
|
||||
format,
|
||||
is_active,
|
||||
is_default,
|
||||
updated_by: userId,
|
||||
});
|
||||
res.json({ success: true, data: currency });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async deactivateCurrency(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const currency = await currencyService.deactivateCurrency(id, userId);
|
||||
res.json({ success: true, data: currency });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async setDefaultCurrency(req: Request, res: Response) {
|
||||
const { id } = req.params;
|
||||
const { userId } = (req as any).traceContext;
|
||||
|
||||
try {
|
||||
const currency = await currencyService.setDefaultCurrency(id, userId);
|
||||
res.json({ success: true, data: currency });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
// 汇率相关接口
|
||||
static async getExchangeRate(req: Request, res: Response) {
|
||||
const { from, to } = req.params;
|
||||
try {
|
||||
const rate = await exchangeRateService.getExchangeRate(from, to);
|
||||
if (rate) {
|
||||
res.json({ success: true, data: rate });
|
||||
} else {
|
||||
res.status(404).json({ success: false, error: 'Exchange rate not found' });
|
||||
}
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async updateExchangeRates(req: Request, res: Response) {
|
||||
try {
|
||||
const count = await exchangeRateService.updateExchangeRates();
|
||||
res.json({ success: true, data: { updated_count: count } });
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getExchangeRateHistory(req: Request, res: Response) {
|
||||
const { from, to } = req.params;
|
||||
const { days = 30 } = req.query;
|
||||
|
||||
try {
|
||||
const history = await exchangeRateService.getExchangeRateHistory(from, to, parseInt(days as string));
|
||||
res.json({ success: true, data: history });
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async getAllExchangeRates(req: Request, res: Response) {
|
||||
try {
|
||||
const rates = await exchangeRateService.getAllExchangeRates();
|
||||
res.json({ success: true, data: rates });
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
// 货币转换相关接口
|
||||
static async convertCurrency(req: Request, res: Response) {
|
||||
const { amount, from, to } = req.body;
|
||||
try {
|
||||
const convertedAmount = await currencyConversionService.convert(amount, from, to);
|
||||
res.json({ success: true, data: { amount: convertedAmount, currency: to } });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async convertMultipleCurrencies(req: Request, res: Response) {
|
||||
const { amounts, from, to } = req.body;
|
||||
try {
|
||||
const convertedAmounts = await currencyConversionService.convertMultiple(amounts, from, to);
|
||||
res.json({ success: true, data: { amounts: convertedAmounts, currency: to } });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async convertToDefaultCurrency(req: Request, res: Response) {
|
||||
const { amount, from } = req.body;
|
||||
try {
|
||||
const convertedAmount = await currencyConversionService.convertToDefault(amount, from);
|
||||
const defaultCurrency = await currencyService.getDefaultCurrency();
|
||||
res.json({ success: true, data: { amount: convertedAmount, currency: defaultCurrency?.code } });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async convertFromDefaultCurrency(req: Request, res: Response) {
|
||||
const { amount, to } = req.body;
|
||||
try {
|
||||
const convertedAmount = await currencyConversionService.convertFromDefault(amount, to);
|
||||
res.json({ success: true, data: { amount: convertedAmount, currency: to } });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
// 货币计算相关接口
|
||||
static async calculatePrice(req: Request, res: Response) {
|
||||
const params: PriceCalculationParams = req.body;
|
||||
try {
|
||||
const price = await currencyCalculationService.calculatePrice(params);
|
||||
res.json({ success: true, data: { price, currency: params.targetCurrency } });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async calculateProfit(req: Request, res: Response) {
|
||||
const params: ProfitCalculationParams = req.body;
|
||||
try {
|
||||
const profit = await currencyCalculationService.calculateProfit(params);
|
||||
res.json({ success: true, data: { profit, currency: params.sellingCurrency } });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async calculateProfitPercentage(req: Request, res: Response) {
|
||||
const params: ProfitCalculationParams = req.body;
|
||||
try {
|
||||
const profitPercentage = await currencyCalculationService.calculateProfitPercentage(params);
|
||||
res.json({ success: true, data: { profitPercentage } });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async calculateBreakEvenPrice(req: Request, res: Response) {
|
||||
const { costPrice, costCurrency, targetCurrency, additionalCosts, additionalCostCurrency } = req.body;
|
||||
try {
|
||||
const breakEvenPrice = await currencyCalculationService.calculateBreakEvenPrice(
|
||||
costPrice,
|
||||
costCurrency,
|
||||
targetCurrency,
|
||||
additionalCosts,
|
||||
additionalCostCurrency
|
||||
);
|
||||
res.json({ success: true, data: { breakEvenPrice, currency: targetCurrency } });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
static async calculateMarkupPercentage(req: Request, res: Response) {
|
||||
const { sellingPrice, sellingCurrency, costPrice, costCurrency, additionalCosts, additionalCostCurrency } = req.body;
|
||||
try {
|
||||
const markupPercentage = await currencyCalculationService.calculateMarkupPercentage(
|
||||
sellingPrice,
|
||||
sellingCurrency,
|
||||
costPrice,
|
||||
costCurrency,
|
||||
additionalCosts,
|
||||
additionalCostCurrency
|
||||
);
|
||||
res.json({ success: true, data: { markupPercentage } });
|
||||
} catch (error: any) {
|
||||
res.status(400).json({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
36
server/src/api/routes/currency.ts
Normal file
36
server/src/api/routes/currency.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Router } from 'express';
|
||||
import { requireTraceContext } from '../../core/guards/trace-context.guard';
|
||||
import { requirePermission } from '../../core/guards/rbac.guard';
|
||||
import { CurrencyController } from '../controllers/CurrencyController';
|
||||
|
||||
const router = Router();
|
||||
|
||||
// 货币管理路由
|
||||
router.get('/currencies', CurrencyController.getCurrencies);
|
||||
router.get('/currencies/:code', CurrencyController.getCurrencyByCode);
|
||||
router.get('/currencies/default', CurrencyController.getDefaultCurrency);
|
||||
router.post('/currencies', requireTraceContext, requirePermission('currency:write'), CurrencyController.createCurrency);
|
||||
router.put('/currencies/:id', requireTraceContext, requirePermission('currency:write'), CurrencyController.updateCurrency);
|
||||
router.patch('/currencies/:id/deactivate', requireTraceContext, requirePermission('currency:write'), CurrencyController.deactivateCurrency);
|
||||
router.patch('/currencies/:id/set-default', requireTraceContext, requirePermission('currency:write'), CurrencyController.setDefaultCurrency);
|
||||
|
||||
// 汇率管理路由
|
||||
router.get('/exchange-rates/:from/:to', CurrencyController.getExchangeRate);
|
||||
router.get('/exchange-rates', CurrencyController.getAllExchangeRates);
|
||||
router.post('/exchange-rates/update', requireTraceContext, requirePermission('currency:write'), CurrencyController.updateExchangeRates);
|
||||
router.get('/exchange-rates/history/:from/:to', CurrencyController.getExchangeRateHistory);
|
||||
|
||||
// 货币转换路由
|
||||
router.post('/convert', CurrencyController.convertCurrency);
|
||||
router.post('/convert/multiple', CurrencyController.convertMultipleCurrencies);
|
||||
router.post('/convert/to-default', CurrencyController.convertToDefaultCurrency);
|
||||
router.post('/convert/from-default', CurrencyController.convertFromDefaultCurrency);
|
||||
|
||||
// 货币计算路由
|
||||
router.post('/calculate/price', CurrencyController.calculatePrice);
|
||||
router.post('/calculate/profit', CurrencyController.calculateProfit);
|
||||
router.post('/calculate/profit-percentage', CurrencyController.calculateProfitPercentage);
|
||||
router.post('/calculate/break-even', CurrencyController.calculateBreakEvenPrice);
|
||||
router.post('/calculate/markup-percentage', CurrencyController.calculateMarkupPercentage);
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user