Files
steel_prices_service/src/services/priceService.js
2026-01-06 09:19:12 +08:00

201 lines
5.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const Price = require('../models/Price');
const { validateAndCleanPricesData } = require('../utils/validator');
/**
* 价格服务
* 处理价格相关的业务逻辑
*/
class PriceService {
/**
* 按地区查询价格
*/
static async getByRegion(region, date, page = 1, pageSize = 20) {
try {
const prices = await Price.getByRegion(region, date);
// 手动分页
const total = prices.length;
const startIndex = (page - 1) * pageSize;
const endIndex = startIndex + parseInt(pageSize, 10);
const paginatedData = prices.slice(startIndex, endIndex);
return {
success: true,
data: paginatedData,
pagination: {
page: parseInt(page, 10),
pageSize: parseInt(pageSize, 10),
total,
totalPages: Math.ceil(total / pageSize)
}
};
} catch (error) {
throw error;
}
}
/**
* 搜索价格数据
*/
static async search(filters) {
try {
// 解析分页参数
const page = parseInt(filters.page) || 1;
const pageSize = parseInt(filters.pageSize) || 20;
const searchFilters = {
material: filters.material,
specification: filters.specification,
startDate: filters.startDate,
endDate: filters.endDate,
region: filters.region,
page,
pageSize
};
// 获取数据
const data = await Price.search(searchFilters);
// 获取总数
const total = await Price.count({
material: filters.material,
specification: filters.specification,
startDate: filters.startDate,
endDate: filters.endDate,
region: filters.region
});
return {
success: true,
data,
pagination: {
page,
pageSize,
total,
totalPages: Math.ceil(total / pageSize)
}
};
} catch (error) {
throw error;
}
}
/**
* 获取价格统计
*/
static async getStats(filters) {
try {
const stats = await Price.getStats(filters);
// 计算趋势(如果提供了天数)
let trend = null;
let changeRate = null;
if (filters.days && stats.avgPrice) {
const previousStats = await Price.getStats({
region: filters.region,
material: filters.material,
days: parseInt(filters.days) * 2 // 获取双倍天数的范围
});
if (previousStats.avgPrice) {
const currentAvg = parseFloat(stats.avgPrice);
const previousAvg = parseFloat(previousStats.avgPrice);
const change = currentAvg - previousAvg;
changeRate = (change / previousAvg * 100).toFixed(2);
trend = change > 0 ? 'up' : change < 0 ? 'down' : 'stable';
}
}
return {
success: true,
data: {
count: stats.count,
avgPrice: stats.avgPrice ? parseFloat(parseFloat(stats.avgPrice).toFixed(2)) : null,
minPrice: stats.minPrice,
maxPrice: stats.maxPrice,
stdDev: stats.stdDev ? parseFloat(parseFloat(stats.stdDev).toFixed(2)) : null,
trend,
changeRate: changeRate ? `${changeRate > 0 ? '+' : ''}${changeRate}%` : null
}
};
} catch (error) {
throw error;
}
}
/**
* 获取价格趋势
*/
static async getTrend(filters) {
try {
const trend = await Price.getTrend(filters);
return {
success: true,
data: trend.map(item => ({
date: item.date,
avgPrice: item.avgPrice ? parseFloat(parseFloat(item.avgPrice).toFixed(2)) : null,
minPrice: item.minPrice,
maxPrice: item.maxPrice
})),
meta: {
total: trend.length,
filters: {
region: filters.region || null,
material: filters.material || null,
days: filters.days || null
}
}
};
} catch (error) {
throw error;
}
}
/**
* 导入数据
*/
static async importData(prices) {
try {
if (!Array.isArray(prices) || prices.length === 0) {
throw new Error('无效的数据格式');
}
// 验证并清洗数据
const validation = validateAndCleanPricesData(prices);
if (validation.validCount === 0) {
return {
success: false,
message: '没有有效的数据可以导入',
data: {
total: validation.total,
imported: 0,
errors: validation.errors
}
};
}
// 批量插入有效数据
const result = await Price.batchInsert(validation.validData);
return {
success: true,
message: `成功导入 ${result} 条数据${validation.errorCount > 0 ? `${validation.errorCount} 条数据因格式错误被跳过` : ''}`,
data: {
imported: result,
total: validation.total,
validCount: validation.validCount,
errorCount: validation.errorCount,
errors: validation.errorCount > 0 ? validation.errors.slice(0, 10) : undefined // 只返回前 10 个错误
}
};
} catch (error) {
throw error;
}
}
}
module.exports = PriceService;