油价集成
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
// 浙江省油价历史: 走 Prisma 落库 + apizero price 接口写入
|
||||
// 设计:
|
||||
// - 每天 04:00 cron 检查 schedule, 待定且 <= 昨天的调价日 -> 抓 price?province=浙江 存本表
|
||||
// - unique (date, province, fuel) 防重复
|
||||
// - 查询 API: 取某省某油品最近 N 天 (默认 180)
|
||||
import { prisma } from '../db.js'
|
||||
import * as client from './client.js'
|
||||
|
||||
const PROVINCE = '浙江'
|
||||
// 油品 -> apizero prices 对象里的 key (price action 返回 "92号汽油" 这种带后缀的 key)
|
||||
const FUEL_KEYS = {
|
||||
'92': '92号汽油',
|
||||
'95': '95号汽油',
|
||||
'0': '0号柴油',
|
||||
}
|
||||
|
||||
// 解析 apizero price action 返回的 prices (中文 key) -> 标准 fuel code
|
||||
function parsePrice(data) {
|
||||
if (!data || !data.prices) throw new Error('apizero 响应无 prices 字段')
|
||||
const out = {}
|
||||
for (const [fuel, label] of Object.entries(FUEL_KEYS)) {
|
||||
const raw = data.prices[label]
|
||||
if (typeof raw === 'string') {
|
||||
// "7.64 元/升" -> 7.64
|
||||
const m = raw.match(/^([\d.]+)/)
|
||||
if (m) out[fuel] = parseFloat(m[1])
|
||||
} else if (typeof raw === 'number') {
|
||||
out[fuel] = raw
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// 抓一次浙江当前价并入库 (date = 今日)
|
||||
// 返回 { inserted, skipped } (按 unique 约束: 已存在则 skip)
|
||||
export async function fetchAndStore() {
|
||||
const data = await client.get('oil-price-forecast', { action: 'price', province: PROVINCE })
|
||||
const prices = parsePrice(data)
|
||||
if (Object.keys(prices).length === 0) {
|
||||
throw new Error('apizero 返回价格为空')
|
||||
}
|
||||
const date = new Date()
|
||||
// 抹掉时分秒, 便于按天比较
|
||||
date.setHours(0, 0, 0, 0)
|
||||
|
||||
let inserted = 0
|
||||
let skipped = 0
|
||||
for (const [fuel, price] of Object.entries(prices)) {
|
||||
try {
|
||||
await prisma.oilPriceHistory.create({
|
||||
data: { date, province: PROVINCE, fuel, price, source: 'apizero' },
|
||||
})
|
||||
inserted++
|
||||
} catch (e) {
|
||||
// P2002: unique 冲突 -> 跳过
|
||||
if (e?.code === 'P2002') skipped++
|
||||
else throw e
|
||||
}
|
||||
}
|
||||
return { inserted, skipped, date: date.toISOString().slice(0, 10) }
|
||||
}
|
||||
|
||||
// 查询某省某油品最近 N 天
|
||||
// province 必填, 默认 浙江
|
||||
// fuel 可选, 留空返回 4 个油品
|
||||
// days 默认 180
|
||||
export async function query({ province = PROVINCE, fuel, days = 180 }) {
|
||||
const since = new Date()
|
||||
since.setDate(since.getDate() - days)
|
||||
since.setHours(0, 0, 0, 0)
|
||||
|
||||
const where = { province, date: { gte: since } }
|
||||
if (fuel) where.fuel = fuel
|
||||
|
||||
const rows = await prisma.oilPriceHistory.findMany({
|
||||
where,
|
||||
orderBy: [{ date: 'asc' }],
|
||||
})
|
||||
|
||||
// 整形: Decimal -> number
|
||||
return rows.map((r) => ({
|
||||
date: r.date.toISOString().slice(0, 10),
|
||||
province: r.province,
|
||||
fuel: r.fuel,
|
||||
price: Number(r.price),
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user