diff --git a/public-frontend/src/App.tsx b/public-frontend/src/App.tsx index 56fdd40..a097c64 100644 --- a/public-frontend/src/App.tsx +++ b/public-frontend/src/App.tsx @@ -1,13 +1,15 @@ import { useState } from "react"; -import { Boxes, Search, PlusCircle } from "lucide-react"; +import { Boxes, Search, PlusCircle, Code2 } from "lucide-react"; import Home from "./components/Home"; import ProductView from "./components/ProductView"; import Contribute from "./components/Contribute"; +import ApiDocs from "./components/ApiDocs"; type View = | { name: "home" } | { name: "product"; id: string } - | { name: "contribute" }; + | { name: "contribute" } + | { name: "api" }; export default function App() { const [view, setView] = useState({ name: "home" }); @@ -41,6 +43,14 @@ export default function App() { > 贡献档案 + @@ -50,6 +60,7 @@ export default function App() { setView({ name: "product", id })} onContribute={() => setView({ name: "contribute" })} + onApi={() => setView({ name: "api" })} /> )} {view.name === "product" && ( @@ -58,12 +69,16 @@ export default function App() { {view.name === "contribute" && ( setView({ name: "home" })} /> )} + {view.name === "api" && }
OpenGoods 是公益性「商品事实库」,仅收录客观商品信息(条码、品牌、品类、营养、官方建议零售价快照等),不含任何购买/交易功能。 公众投稿须经人工审核后方可收纳。 +
diff --git a/public-frontend/src/components/ApiDocs.tsx b/public-frontend/src/components/ApiDocs.tsx new file mode 100644 index 0000000..a985ed7 --- /dev/null +++ b/public-frontend/src/components/ApiDocs.tsx @@ -0,0 +1,279 @@ +import { useState } from "react"; +import { Check, Copy } from "lucide-react"; + +const ORIGIN = typeof window !== "undefined" ? window.location.origin : "https://goods.tangshasha.com"; +const BASE = `${ORIGIN}/api/v1`; + +function CopyBtn({ text }: { text: string }) { + const [done, setDone] = useState(false); + return ( + + ); +} + +function Code({ children }: { children: string }) { + return ( +
+
+        {children}
+      
+
+ +
+
+ ); +} + +function Method({ m }: { m: string }) { + const color = m === "GET" ? "bg-sky-100 text-sky-700" : "bg-emerald-100 text-emerald-700"; + return {m}; +} + +type Param = { name: string; required?: boolean; desc: string }; + +function Endpoint({ + method, + path, + title, + desc, + params, + example, + response, +}: { + method: string; + path: string; + title: string; + desc: string; + params?: Param[]; + example: string; + response: string; +}) { + return ( +
+
+ + {path} + + +
+
{title}
+

{desc}

+ + {params && params.length > 0 && ( + + + + + + + + + + {params.map((p) => ( + + + + + + ))} + +
参数必填说明
{p.name}{p.required ? "是" : "否"}{p.desc}
+ )} + +
请求示例
+ {example} +
返回示例
+ {response} +
+ ); +} + +export default function ApiDocs() { + return ( +
+
+

API 调用说明

+

+ OpenGoods 提供公开、只读、免鉴权的商品事实 REST API,任何人都可直接调用, + 用于按条码/名称查询商品的客观资料(品牌、品类、净含量、产地、配料、营养成分、Nutri-Score、 + 厂商建议零售价快照等)。返回均为 JSON(UTF-8)。本服务不含任何购买/交易接口。 +

+
+
+ 基础地址:{BASE} +
+
    +
  • 无需 API Key / Token,直接 GET 即可。
  • +
  • + 分页参数 page(默认 1)、 + size(默认 20,最大 100)。 +
  • +
  • + 未找到资源返回 404,错误体形如 + {` {"error":{"code","message","request_id"}}`}。 +
  • +
  • 请合理控制调用频率;商品数据遵循各来源许可,引用时请注明 OpenGoods 及原始来源。
  • +
+
+
+ + + + + + + + + + + + + + + + + + + +
+ 数据可能存在误差或滞后,按「现状」提供,不构成医疗/购买建议。商品资料版权归各原始来源所有, + 请遵循其许可(如 OpenFoodFacts 的 ODbL)。 +
+
+ ); +} diff --git a/public-frontend/src/components/Home.tsx b/public-frontend/src/components/Home.tsx index 4ea9c51..6fc55fd 100644 --- a/public-frontend/src/components/Home.tsx +++ b/public-frontend/src/components/Home.tsx @@ -1,14 +1,16 @@ import { useState } from "react"; -import { Search, PlusCircle } from "lucide-react"; +import { Search, PlusCircle, Code2 } from "lucide-react"; import { api } from "../api"; import type { ProductSummary } from "../types"; export default function Home({ onOpen, onContribute, + onApi, }: { onOpen: (id: string) => void; onContribute: () => void; + onApi: () => void; }) { const [q, setQ] = useState(""); const [items, setItems] = useState([]); @@ -59,6 +61,12 @@ export default function Home({ {loading ? "检索中…" : "检索"} + {error && (