"use client"; import { useEffect, useMemo, useState } from "react"; import type { Market } from "@/src/domain/types"; import { useWatchlistStore } from "@/src/stores/watchlistStore"; function normalizeCode(raw: string) { return raw.trim(); } export default function WatchlistPage() { const { items, loading, error, refresh, add, update, remove } = useWatchlistStore(); const [code, setCode] = useState(""); const [market, setMarket] = useState("SZ"); const [notes, setNotes] = useState(""); useEffect(() => { void refresh(); }, [refresh]); const canSubmit = useMemo(() => { return normalizeCode(code).length > 0; }, [code]); return (

自选股

MVP:添加/删除、备注、置顶(本地 IndexedDB 持久化,userId=anon)。

添加自选股
{ e.preventDefault(); if (!canSubmit) return; await add({ code: normalizeCode(code), market, notes: notes.trim() || undefined, }); setCode(""); setNotes(""); }} >
{error ? (
{error}
) : null}
列表
{items.length === 0 ? ( ) : null} {items.map((item) => ( ))}
置顶 代码 市场 备注 创建时间 操作
暂无自选股
{item.code} {item.market} { const v = e.target.value.trim(); if ((item.notes ?? "") !== v) { void update(item.code, item.market, { notes: v || undefined, }); } }} /> {new Date(item.createdAt).toLocaleString()}
{loading ? (
加载中…
) : null}
); }