stock-portfolio/prisma/seed.ts
kennethcheng 0051f92b2b v1.0.5 (2026-04-13)
- 📛 证券名称增强:修复 INTC 等证券名称显示为空的问题 (BUG-101)
- 🔒 SELL超量校验:修复卖出数量超过持仓导致持仓变负的Bug (BUG-002)
- 🔄 撤销BUY成本还原:修复撤销买入时平均成本计算公式错误 (BUG-003)
- 💹 Decimal精度计算:持仓分析改用Prisma.Decimal进行金融计算,防止浮点精度丢失 (BUG-004)
- 📛 证券名称显示:在持仓分析卡片、资产分布、盈亏排行等位置同时显示股票代码和名称
- 📋 证券数据库扩展:新增 Intel Corp. (INTC) 证券记录
- 🔍 回退逻辑增强:确保证券名称为空时显示代码而非空白
- 📈 腾讯行情解析升级:精准解析股票名称(索引1),支持港/A/美股及 ETF 名称自动获取
- 🔀 多市场涨跌解析修复:重构腾讯行情多市场适配层,美股(索引4/5)与港A股(索引31/32)使用差异化索引解析涨跌数据
- 🇨🇳 GBK中文解码修复:改用 `arrayBuffer() + TextDecoder('gbk')` 替代 `text()`,彻底解决A股/港股中文股票名称乱码问题
- 💱 JisuAPI实时汇率:接入 JisuAPI 获取实时汇率,缓存1小时,支持 CNY/HKD/USD 转换
- 📊 资产配置动态图:环形图改由后端实时聚合持仓数据驱动,支持 Tooltip 和百分比显示
- 🎨 资产配置图表优化:精美毛玻璃 Tooltip、颜色图标、去除生硬描边、useMemo 性能优化
- 💱 全局货币联动:资产配置图表数值随 CNY/USD/HKD 切换实时转换
- 📝 交易流水增强:新增证券名称列,显示"名称+代码"双行格式
- 💹 全局汇率展示:在导航栏实时显示 USD/CNY/HKD 汇率信息
- 🔧 BUG-202 修复:修正 `convertCurrency` 汇率换算逻辑(原逻辑除法/乘法颠倒,导致 USD→CNY 换算失效)
- 🔧 BUG-201 修复:腾讯行情 API 获取失败时,`priceAvailable` 标记配合前端显示 "N/A" 替代虚假 0%
- 🔧 BUG-203 增强:持仓分析 `name` 字段确保回退到 `pos.symbol`,名称永不空
- 💹 Decimal 精度保障:所有盈亏/汇率计算均使用 Prisma.Decimal,防止浮点精度丢失
2026-04-13 18:41:37 +08:00

101 lines
3.9 KiB
TypeScript

import { PrismaClient, MarketType } from '@prisma/client'
const prisma = new PrismaClient()
async function main() {
// 创建默认用户
const user = await prisma.user.upsert({
where: { email: 'demo@portfolio.local' },
update: {},
create: {
email: 'demo@portfolio.local',
name: 'Demo User',
},
})
// 创建各市场的账户
const accounts = [
{ name: '港股账户', marketType: MarketType.HK, baseCurrency: 'HKD' },
{ name: '美股账户', marketType: MarketType.US, baseCurrency: 'USD' },
{ name: 'A股账户', marketType: MarketType.CN, baseCurrency: 'CNY' },
{ name: '加密货币账户', marketType: MarketType.CRYPTO, baseCurrency: 'USDT' },
]
for (const acc of accounts) {
await prisma.account.upsert({
where: { id: `${user.id}-${acc.marketType}` },
update: {},
create: {
id: `${user.id}-${acc.marketType}`,
userId: user.id,
name: acc.name,
marketType: acc.marketType,
baseCurrency: acc.baseCurrency,
balance: 0,
},
})
}
// 初始化汇率(以 USD 为基准)
const exchangeRates = [
{ fromCurrency: 'USD', toCurrency: 'USD', rate: 1, date: new Date('2026-01-01') },
{ fromCurrency: 'CNY', toCurrency: 'USD', rate: 0.137, date: new Date('2026-01-01') },
{ fromCurrency: 'HKD', toCurrency: 'USD', rate: 0.129, date: new Date('2026-01-01') },
{ fromCurrency: 'USDT', toCurrency: 'USD', rate: 1, date: new Date('2026-01-01') },
]
for (const rate of exchangeRates) {
await prisma.exchangeRate.upsert({
where: {
fromCurrency_toCurrency_effectiveDate: {
fromCurrency: rate.fromCurrency,
toCurrency: rate.toCurrency,
effectiveDate: rate.date,
},
},
update: {},
create: {
fromCurrency: rate.fromCurrency,
toCurrency: rate.toCurrency,
rate: rate.rate,
effectiveDate: rate.date,
},
})
}
// 初始化常见证券
const securities = [
{ symbol: '00700', name: '腾讯控股', market: MarketType.HK, currency: 'HKD', lotSize: 100, priceDecimals: 2, qtyDecimals: 0 },
{ symbol: '09868', name: '小鹏汽车', market: MarketType.HK, currency: 'HKD', lotSize: 100, priceDecimals: 2, qtyDecimals: 0 },
{ symbol: '09988', name: '阿里巴巴', market: MarketType.HK, currency: 'HKD', lotSize: 100, priceDecimals: 2, qtyDecimals: 0 },
{ symbol: 'AAPL', name: 'Apple Inc.', market: MarketType.US, currency: 'USD', lotSize: 1, priceDecimals: 2, qtyDecimals: 0 },
{ symbol: 'MSFT', name: 'Microsoft Corp.', market: MarketType.US, currency: 'USD', lotSize: 1, priceDecimals: 2, qtyDecimals: 0 },
{ symbol: 'NVDA', name: 'NVIDIA Corp.', market: MarketType.US, currency: 'USD', lotSize: 1, priceDecimals: 2, qtyDecimals: 0 },
{ symbol: 'GOOGL', name: 'Alphabet Inc.', market: MarketType.US, currency: 'USD', lotSize: 1, priceDecimals: 2, qtyDecimals: 0 },
{ symbol: 'INTC', name: 'Intel Corp.', market: MarketType.US, currency: 'USD', lotSize: 1, priceDecimals: 2, qtyDecimals: 0 },
{ symbol: '600690', name: '海尔智家', market: MarketType.CN, currency: 'CNY', lotSize: 100, priceDecimals: 2, qtyDecimals: 0 },
{ symbol: '159235', name: '中证现金流ETF', market: MarketType.CN, currency: 'CNY', lotSize: 100, priceDecimals: 3, qtyDecimals: 0 },
{ symbol: 'BTC', name: 'Bitcoin', market: MarketType.CRYPTO, currency: 'USDT', lotSize: 1, priceDecimals: 2, qtyDecimals: 8, isCrypto: true },
{ symbol: 'ETH', name: 'Ethereum', market: MarketType.CRYPTO, currency: 'USDT', lotSize: 1, priceDecimals: 2, qtyDecimals: 8, isCrypto: true },
]
for (const sec of securities) {
await prisma.security.upsert({
where: { symbol: sec.symbol },
update: {},
create: sec,
})
}
console.log('Seed completed:', { user, accountsCreated: accounts.length })
}
main()
.catch((e) => {
console.error(e)
process.exit(1)
})
.finally(async () => {
await prisma.$disconnect()
})