|
|
@@ -0,0 +1,145 @@
|
|
|
+import { Hono } from 'hono'
|
|
|
+import type { Variables, WithAuth } from "./middlewares.ts";
|
|
|
+import debug from "debug";
|
|
|
+import dayjs from 'dayjs'
|
|
|
+
|
|
|
+interface ApiResponse<T = any> {
|
|
|
+ success: boolean;
|
|
|
+ code?: string;
|
|
|
+ message?: string;
|
|
|
+ data?: T;
|
|
|
+}
|
|
|
+
|
|
|
+interface DateNote {
|
|
|
+ date: string;
|
|
|
+ memo: string;
|
|
|
+ [key: string]: string;
|
|
|
+}
|
|
|
+
|
|
|
+const log = {
|
|
|
+ api: debug("api:stock"),
|
|
|
+};
|
|
|
+
|
|
|
+export function createStockRoutes(withAuth: WithAuth) {
|
|
|
+ const stockRoutes = new Hono<{ Variables: Variables }>()
|
|
|
+
|
|
|
+ stockRoutes.get('/history', async (c) => {
|
|
|
+ const apiClient = c.get('apiClient')
|
|
|
+ const url = new URL(c.req.url)
|
|
|
+ const code = url.searchParams.get("code") || '001339'
|
|
|
+ const dh = 'dn' // 固定值
|
|
|
+
|
|
|
+ if (!code || !dh) {
|
|
|
+ return c.text("Missing required parameters", 400)
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const license = Deno.env.get('STOCK_API_LICENSE')
|
|
|
+ if (!license) {
|
|
|
+ throw new Error('STOCK_API_LICENSE environment variable not set')
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询数据库中是否存在今天的数据
|
|
|
+ const today = dayjs().format('YYYY-MM-DD')
|
|
|
+ const existingData = await apiClient.database
|
|
|
+ .table("stock_data")
|
|
|
+ .select("*")
|
|
|
+ .where("code", code)
|
|
|
+ .where("updated_at", ">=", `${today} 00:00:00`)
|
|
|
+ .first()
|
|
|
+
|
|
|
+ if (existingData) {
|
|
|
+ return c.json(existingData.data)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果没有今天的数据,调用外部API
|
|
|
+ const apiUrl = `http://api.mairui.club/hszbl/fsjy/${code}/${dh}/${license}`
|
|
|
+ const response = await fetch(apiUrl, {
|
|
|
+ method: "GET",
|
|
|
+ headers: {
|
|
|
+ "Accept": "application/json"
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ if (!response.ok) {
|
|
|
+ throw new Error(`API request failed with status ${response.status}`)
|
|
|
+ }
|
|
|
+
|
|
|
+ const newData = await response.json()
|
|
|
+
|
|
|
+ // 更新或插入数据库
|
|
|
+ await apiClient.database
|
|
|
+ .table("stock_data")
|
|
|
+ .insert({
|
|
|
+ code,
|
|
|
+ data: JSON.stringify(newData),
|
|
|
+ created_at: dayjs().format('YYYY-MM-DD HH:mm:ss'),
|
|
|
+ updated_at: dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
|
+ })
|
|
|
+ .onConflict("code")
|
|
|
+ .merge({
|
|
|
+ data: JSON.stringify(newData),
|
|
|
+ updated_at: dayjs().format('YYYY-MM-DD HH:mm:ss')
|
|
|
+ })
|
|
|
+ .execute()
|
|
|
+
|
|
|
+ return c.json(newData)
|
|
|
+
|
|
|
+ } catch (error) {
|
|
|
+ log.api("Error getting stock history:", error)
|
|
|
+ return c.text("Internal Server Error", 500)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ stockRoutes.get('/memos', async (c) => {
|
|
|
+ const apiClient = c.get('apiClient')
|
|
|
+ const url = new URL(c.req.url)
|
|
|
+ const code = url.searchParams.get("code")
|
|
|
+
|
|
|
+ if (!code) {
|
|
|
+ const response: ApiResponse<Array<DateNote>> = {
|
|
|
+ success: true,
|
|
|
+ data: []
|
|
|
+ }
|
|
|
+ return c.json(response)
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ const notes = await apiClient.database
|
|
|
+ .table("date_notes")
|
|
|
+ .select(["note_date as date", "note as memo"])
|
|
|
+ .where("code", code)
|
|
|
+ .orderBy("note_date", "asc")
|
|
|
+ .execute() as DateNote[]
|
|
|
+
|
|
|
+ if (!notes || notes.length === 0) {
|
|
|
+ const response: ApiResponse<Array<DateNote>> = {
|
|
|
+ success: true,
|
|
|
+ data: []
|
|
|
+ }
|
|
|
+ return c.json(response)
|
|
|
+ }
|
|
|
+
|
|
|
+ notes.forEach((note) => {
|
|
|
+ note.日期 = dayjs(note.date).format("YYYY-MM-DD")
|
|
|
+ note.提示 = note.memo
|
|
|
+ })
|
|
|
+
|
|
|
+ const response: ApiResponse<Array<DateNote>> = {
|
|
|
+ success: true,
|
|
|
+ data: notes
|
|
|
+ }
|
|
|
+ return c.json(response)
|
|
|
+ } catch (error) {
|
|
|
+ log.api("Error fetching memo data:", error)
|
|
|
+ const response: ApiResponse = {
|
|
|
+ success: false,
|
|
|
+ code: "SYSTEM.ERROR",
|
|
|
+ message: error instanceof Error ? error.message : "获取备忘录数据失败"
|
|
|
+ }
|
|
|
+ return c.json(response, 500)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ return stockRoutes
|
|
|
+}
|