diff --git a/scripts/load_path.py b/scripts/load_path.py index dfe341c..07dec68 100644 --- a/scripts/load_path.py +++ b/scripts/load_path.py @@ -156,6 +156,7 @@ PATHS_LOGINED = [ f"/{MOD}/api/exchange_rate_create.dspy", f"/{MOD}/api/exchange_rate_update.dspy", f"/{MOD}/api/exchange_rate_delete.dspy", + f"/{MOD}/api/fetch_forex_rates.dspy", # proxy_recharge/ f"/{MOD}/proxy_recharge.ui", diff --git a/wwwroot/api/fetch_forex_rates.dspy b/wwwroot/api/fetch_forex_rates.dspy new file mode 100644 index 0000000..65587b9 --- /dev/null +++ b/wwwroot/api/fetch_forex_rates.dspy @@ -0,0 +1,63 @@ +# 获取中国银行外汇牌价并插入 exchange_rate 表 +# GET /accounting/api/fetch_forex_rates.dspy +import re +import urllib.request +from datetime import date + +BOC_URL = 'https://www.boc.cn/sourcedb/whpj/index.html' +CURRENCIES = {'美元': 'USD', '日元': 'JPY', '英镑': 'GBP'} + +async with get_sor_context(request._run_ns, 'accounting') as sor: + # 1. 抓取 BOC 页面 + try: + req = urllib.request.Request(BOC_URL, headers={'User-Agent': 'Mozilla/5.0'}) + with urllib.request.urlopen(req, timeout=15) as resp: + html = resp.read().decode('utf-8', errors='replace') + except Exception as e: + return json.dumps({'success': False, 'message': f'获取BOC页面失败: {e}'}, ensure_ascii=False) + + today = date.today().isoformat() + inserted = 0 + + for cn_name, code in CURRENCIES.items(): + pos = html.find(cn_name) + if pos < 0: + continue + chunk = html[pos:pos+500] + tds = re.findall(r']*>(.*?)', chunk, re.DOTALL) + clean = [re.sub(r'<[^>]+>', '', t).strip() for t in tds] + if len(clean) < 6: + continue + try: + buy_rate = float(clean[1]) # 现汇买入价 + sell_rate = float(clean[3]) # 现汇卖出价 + mid_rate = float(clean[5]) # 中行折算价 + except ValueError: + continue + + # BOC quotes USD/GBP per 100 units, JPY per 100 units + if code in ('USD', 'GBP'): + buy_rate = round(buy_rate / 100, 6) + sell_rate = round(sell_rate / 100, 6) + mid_rate = round(mid_rate / 100, 6) + elif code == 'JPY': + buy_rate = round(buy_rate / 100, 6) + sell_rate = round(sell_rate / 100, 6) + mid_rate = round(mid_rate / 100, 6) + + record_id = f'er_{code.lower()}_cny_{today.replace("-","")}' + + await sor.execute( + """INSERT INTO exchange_rate (id, from_currency, to_currency, buy_rate, sell_rate, mid_rate, effective_date, updated_at) + VALUES (${id}$, ${from_cur}$, 'CNY', ${buy}$, ${sell}$, ${mid}$, ${date}$, NOW()) + ON DUPLICATE KEY UPDATE buy_rate=${buy}$, sell_rate=${sell}$, mid_rate=${mid}$, updated_at=NOW()""", + {'id': record_id, 'from_cur': code, 'buy': buy_rate, 'sell': sell_rate, 'mid': mid_rate, 'date': today} + ) + inserted += 1 + + return json.dumps({ + 'success': True, + 'message': f'已更新 {inserted} 条汇率', + 'date': today, + 'source': '中国银行外汇牌价' + }, ensure_ascii=False)