88 lines
2.7 KiB
JavaScript
88 lines
2.7 KiB
JavaScript
// 浙江省油价历史: 走 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),
|
|
}))
|
|
}
|