Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ef5d0b3d3 | |||
| 4b5e70a3bf | |||
| ea60d4b4c6 |
@@ -402,6 +402,13 @@
|
||||
"type": "text",
|
||||
"description": "GPU简介",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"key": "publish_date",
|
||||
"label": "发布日期",
|
||||
"type": "text",
|
||||
"description": "产品发布日期,格式 YYYY-MM-DD",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -589,6 +596,13 @@
|
||||
"type": "text",
|
||||
"description": "CPU简介",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"key": "publish_date",
|
||||
"label": "发布日期",
|
||||
"type": "text",
|
||||
"description": "产品发布日期,格式 YYYY-MM-DD",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -706,6 +720,13 @@
|
||||
"type": "text",
|
||||
"description": "产品简介",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"key": "publish_date",
|
||||
"label": "发布日期",
|
||||
"type": "text",
|
||||
"description": "产品发布日期,格式 YYYY-MM-DD",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -829,6 +850,13 @@
|
||||
"type": "text",
|
||||
"description": "产品简介",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"key": "publish_date",
|
||||
"label": "发布日期",
|
||||
"type": "text",
|
||||
"description": "产品发布日期,格式 YYYY-MM-DD",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -914,6 +942,13 @@
|
||||
"type": "text",
|
||||
"description": "车型简介",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"key": "publish_date",
|
||||
"label": "发布日期",
|
||||
"type": "text",
|
||||
"description": "产品发布日期,格式 YYYY-MM-DD",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -1033,6 +1068,13 @@
|
||||
"type": "text",
|
||||
"description": "产品简介",
|
||||
"required": false
|
||||
},
|
||||
{
|
||||
"key": "publish_date",
|
||||
"label": "发布日期",
|
||||
"type": "text",
|
||||
"description": "产品发布日期,格式 YYYY-MM-DD",
|
||||
"required": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
"l3_cache_mb": 384,
|
||||
"tdp_watts": 360,
|
||||
"price_usd": 11000,
|
||||
"release_year": 2022,
|
||||
"description": "AMD顶级服务器CPU,96核心",
|
||||
"subcategory_id": "server"
|
||||
"subcategory_id": "server",
|
||||
"publish_date": "2022-01-01"
|
||||
},
|
||||
{
|
||||
"id": "epyc9554",
|
||||
@@ -27,9 +27,9 @@
|
||||
"l3_cache_mb": 256,
|
||||
"tdp_watts": 360,
|
||||
"price_usd": 6800,
|
||||
"release_year": 2022,
|
||||
"description": "64核心高性能服务器CPU",
|
||||
"subcategory_id": "server"
|
||||
"subcategory_id": "server",
|
||||
"publish_date": "2022-01-01"
|
||||
},
|
||||
{
|
||||
"id": "epyc9454",
|
||||
@@ -43,9 +43,9 @@
|
||||
"l3_cache_mb": 192,
|
||||
"tdp_watts": 290,
|
||||
"price_usd": 4100,
|
||||
"release_year": 2022,
|
||||
"description": "48核心服务器CPU",
|
||||
"subcategory_id": "server"
|
||||
"subcategory_id": "server",
|
||||
"publish_date": "2022-01-01"
|
||||
},
|
||||
{
|
||||
"id": "xeonw9359x",
|
||||
@@ -59,9 +59,9 @@
|
||||
"l3_cache_mb": 105,
|
||||
"tdp_watts": 350,
|
||||
"price_usd": 6200,
|
||||
"release_year": 2023,
|
||||
"description": "Intel顶级工作站CPU",
|
||||
"subcategory_id": "server"
|
||||
"subcategory_id": "server",
|
||||
"publish_date": "2023-01-01"
|
||||
},
|
||||
{
|
||||
"id": "xeonw5345",
|
||||
@@ -75,9 +75,9 @@
|
||||
"l3_cache_mb": 45,
|
||||
"tdp_watts": 230,
|
||||
"price_usd": 950,
|
||||
"release_year": 2023,
|
||||
"description": "中端工作站CPU",
|
||||
"subcategory_id": "server"
|
||||
"subcategory_id": "server",
|
||||
"publish_date": "2023-01-01"
|
||||
},
|
||||
{
|
||||
"id": "ryzen97950x",
|
||||
@@ -91,9 +91,9 @@
|
||||
"l3_cache_mb": 64,
|
||||
"tdp_watts": 170,
|
||||
"price_usd": 550,
|
||||
"release_year": 2022,
|
||||
"description": "顶级消费级CPU,适合AI开发",
|
||||
"subcategory_id": "desktop"
|
||||
"subcategory_id": "desktop",
|
||||
"publish_date": "2022-01-01"
|
||||
},
|
||||
{
|
||||
"id": "ryzen97950x3d",
|
||||
@@ -107,9 +107,9 @@
|
||||
"l3_cache_mb": 144,
|
||||
"tdp_watts": 120,
|
||||
"price_usd": 700,
|
||||
"release_year": 2023,
|
||||
"description": "带3D V-Cache,游戏性能更强",
|
||||
"subcategory_id": "mobile"
|
||||
"subcategory_id": "mobile",
|
||||
"publish_date": "2023-01-01"
|
||||
},
|
||||
{
|
||||
"id": "intel14900k",
|
||||
@@ -123,9 +123,9 @@
|
||||
"l3_cache_mb": 36,
|
||||
"tdp_watts": 125,
|
||||
"price_usd": 580,
|
||||
"release_year": 2023,
|
||||
"description": "Intel顶级消费级CPU",
|
||||
"subcategory_id": "desktop"
|
||||
"subcategory_id": "desktop",
|
||||
"publish_date": "2023-01-01"
|
||||
},
|
||||
{
|
||||
"name": "AMD 锐龙 AI 9 H 365",
|
||||
@@ -142,7 +142,7 @@
|
||||
"created_at": "2026-04-20 23:19:20",
|
||||
"visible": true,
|
||||
"raw_text": "AMD 锐龙 AI 9 H 365\nAMD 锐龙 AI 处理器助力打造卓越 AI PC\n\n \n全部折叠\n一般规格\n名称\nAMD 锐龙 AI 9 H 365\n产品系列\n锐龙\n系列\n锐龙 AI 300 系列\n外形规格\n笔记本电脑 , 台式机\nAMD PRO 技术\n否\n区域供货状况\n中国\n原代号\nStrix Point\n处理器架构\n4x Zen 5 , 6x Zen 5c\nCPU 核心数\n10\n多线程 (SMT)\n是\n线程数\n20\n最高加速时钟频率 \n最高可达 5 GHz\nMax Zen5c Clock \n最高可达 3.3 GHz\n基准时钟频率 \n2 GHz\nZen5 Base Clock\n2 GHz\nZen5c Base Clock\n2 GHz\nL2 高速缓存\n10 MB\nL3 高速缓存\n24 MB\n默认热设计功耗 (TDP)\n28W\nAMD 可配置热设计功耗 (cTDP)\n15-54W\nCPU 核心的处理器工艺\nTSMC 4nm FinFET\n封装芯片计数\n1\nAMD EXPO™ 内存超频技术\n是\n精准频率提升 (PBO)\n是\n曲线优化器电压偏移\n是\nCPU 平台\nFP8\n支持的扩展\nAES , AMD-V , AVX , AVX2 , AVX512 , FMA3 , MMX-plus , SHA , SSE , SSE2 , SSE3 , SSE4.1 , SSE4.2 , SSE4A , SSSE3 , x86-64\n最高工作温度 (Tjmax)\n100°C\n*支持的操作系统\nWindows 11 - 64-Bit Edition , RHEL x86 64-Bit , Ubuntu x86 64-Bit\n连接\nNative USB 4 (40Gbps)\n2\nNative USB 3.2 Gen 2 (10Gbps)\n2\nNative USB 2.0 (480Mbps)\n4\nPCI Express® Version\nPCIe® 4.0\n原生 PCIe® 通道 (总共/可用)\n16 , 16\nNVMe 支持\nBoot , RAID0 , RAID1\n系统内存类型\nDDR5 (FP8) , LPDDR5X (FP8)\n内存通道数\n2\n最大内存\n256 GB\n最高内存速度\n2x2R\tDDR5-5600, LPDDR5x-8000\n支持 ECC\n否\n显卡功能\n显卡型号\nAMD Radeon™ 880M\n显卡核心数\n12\n显卡频率\n2900 MHz\nDirectX® 版本\n12\nDisplayPort™ 版本\n2.1\nDisplayPort 扩展功能\nAdaptive-Sync , HDR Metadata , UHBR10\nDisplayPort 最高刷新率 (SDR)\n7680x4320 @ 60Hz , 3840x2160 @ 240Hz , 3440x1440 @ 360Hz , 2560x1440 @ 480Hz , 1920x1080 @ 600Hz\nDisplayPort 最高刷新率 (HDR)\n7680x4320 @ 60Hz , 3840x2160 @ 240Hz , 3440x1440 @ 360Hz , 2560x1440 @ 480Hz , 1920x1080 @ 600Hz\nHDMI® 版本\n2.1\n支持的 HDCP 版本\n2.3\nUSB Type-C® DisplayPort™ 备用模式\n是\n支持多个显示器\n是\n显示器个数上限\n4\nAMD FreeSync™\n是\n无线显示\nMiracast\n最大视频编码带宽 (SDR)\n1080p630 8bpc H.264, 1440p373 8bpc H.264, 2160p175 8bpc H.264, 1080p630 8bpc H.265, 1440p373 8bpc H.265, 2160p175 8bpc H.265, 4320p43 8bpc H.265, 1080p864 8/10bpc AV1, 1440p513 8/10bpc AV1, 2160p240 8/10bpc AV1, 4320p60 8/10bpc AV1\n\n最大视频解码带宽\n1080p60 8bpc MPEG2, 1080p60 8bpc VC1, 1080p786 8/10bpc VP9, 2160p196 8/10bpc VP9, 4320p49 8/10bpc VP9, 1080p1200 8bpc H.264, 2160p300 8bpc H.264, 4320p75 8bpc H.264, 1080p786 8/10bpc H.265, 2160p196 8/10bpc H.265, 4320p49 8/10bpc H.265, 1080p960 8/10bpc\n\nAMD SmartShift MAX\n是\nAMD 显存智取技术\n支持\nAI 引擎性能\nAMD Ryzen™ AI\n支持\nOverall TOPS\n最高可达 73 TOPS\nNPU TOPS\n最高可达 50 TOPS\n产品 ID\nTray 产品 ID\n100-000001530 (FP8)\n安全\nAMD 增强病毒防护 (NX bit)\n是",
|
||||
"publish_date": "",
|
||||
"publish_date": "2022-01-01",
|
||||
"views": 0,
|
||||
"is_pinned": false,
|
||||
"subcategory_id": "mobile"
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
"fp16_tflops": 1979,
|
||||
"int8_perf_tops": 3958,
|
||||
"price_usd": 30000,
|
||||
"release_year": 2022,
|
||||
"description": "数据中心顶级GPU,专为AI训练设计",
|
||||
"subcategory_id": "datacenter"
|
||||
"subcategory_id": "datacenter",
|
||||
"publish_date": "2022-01-01"
|
||||
},
|
||||
{
|
||||
"id": "a100",
|
||||
@@ -29,9 +29,9 @@
|
||||
"fp16_tflops": 312,
|
||||
"int8_perf_tops": 624,
|
||||
"price_usd": 10000,
|
||||
"release_year": 2020,
|
||||
"description": "数据中心主力GPU,AI训练推理通用",
|
||||
"subcategory_id": "datacenter"
|
||||
"subcategory_id": "datacenter",
|
||||
"publish_date": "2020-01-01"
|
||||
},
|
||||
{
|
||||
"id": "a10040g",
|
||||
@@ -46,9 +46,9 @@
|
||||
"fp16_tflops": 312,
|
||||
"int8_perf_tops": 624,
|
||||
"price_usd": 6000,
|
||||
"release_year": 2020,
|
||||
"description": "A100 40GB版本,性价比更高",
|
||||
"subcategory_id": "datacenter"
|
||||
"subcategory_id": "datacenter",
|
||||
"publish_date": "2020-01-01"
|
||||
},
|
||||
{
|
||||
"id": "l40s",
|
||||
@@ -63,9 +63,9 @@
|
||||
"fp16_tflops": 362,
|
||||
"int8_perf_tops": 724,
|
||||
"price_usd": 7000,
|
||||
"release_year": 2023,
|
||||
"description": "新一代数据中心GPU,推理优化",
|
||||
"subcategory_id": "datacenter"
|
||||
"subcategory_id": "datacenter",
|
||||
"publish_date": "2023-01-01"
|
||||
},
|
||||
{
|
||||
"id": "rtx4090",
|
||||
@@ -80,9 +80,9 @@
|
||||
"fp16_tflops": 330,
|
||||
"int8_perf_tops": 660,
|
||||
"price_usd": 1600,
|
||||
"release_year": 2022,
|
||||
"description": "消费级最强GPU,适合个人AI开发",
|
||||
"subcategory_id": "gaming"
|
||||
"subcategory_id": "gaming",
|
||||
"publish_date": "2022-01-01"
|
||||
},
|
||||
{
|
||||
"id": "rtx4090d",
|
||||
@@ -97,9 +97,9 @@
|
||||
"fp16_tflops": 294,
|
||||
"int8_perf_tops": 588,
|
||||
"price_usd": 1400,
|
||||
"release_year": 2024,
|
||||
"description": "4090中国特供版,性能略降",
|
||||
"subcategory_id": "gaming"
|
||||
"subcategory_id": "gaming",
|
||||
"publish_date": "2024-01-01"
|
||||
},
|
||||
{
|
||||
"id": "rtx3090",
|
||||
@@ -114,9 +114,9 @@
|
||||
"fp16_tflops": 142,
|
||||
"int8_perf_tops": 284,
|
||||
"price_usd": 1200,
|
||||
"release_year": 2020,
|
||||
"description": "上一代旗舰,性价比高",
|
||||
"subcategory_id": "gaming"
|
||||
"subcategory_id": "gaming",
|
||||
"publish_date": "2020-01-01"
|
||||
},
|
||||
{
|
||||
"id": "rtx3080",
|
||||
@@ -131,9 +131,9 @@
|
||||
"fp16_tflops": 119,
|
||||
"int8_perf_tops": 238,
|
||||
"price_usd": 700,
|
||||
"release_year": 2020,
|
||||
"description": "中高端消费级GPU",
|
||||
"subcategory_id": "gaming"
|
||||
"subcategory_id": "gaming",
|
||||
"publish_date": "2020-01-01"
|
||||
},
|
||||
{
|
||||
"id": "v100",
|
||||
@@ -148,9 +148,9 @@
|
||||
"fp16_tflops": 118,
|
||||
"int8_perf_tops": 236,
|
||||
"price_usd": 4000,
|
||||
"release_year": 2017,
|
||||
"description": "上一代数据中心GPU,仍有价值",
|
||||
"subcategory_id": "datacenter"
|
||||
"subcategory_id": "datacenter",
|
||||
"publish_date": "2017-01-01"
|
||||
},
|
||||
{
|
||||
"id": "mi300x",
|
||||
@@ -165,9 +165,9 @@
|
||||
"fp16_tflops": 1307,
|
||||
"int8_perf_tops": 2614,
|
||||
"price_usd": 15000,
|
||||
"release_year": 2023,
|
||||
"description": "AMD最强AI GPU,192GB显存",
|
||||
"subcategory_id": "datacenter"
|
||||
"subcategory_id": "datacenter",
|
||||
"publish_date": "2023-01-01"
|
||||
},
|
||||
{
|
||||
"name": "RTX 6000D",
|
||||
@@ -184,7 +184,8 @@
|
||||
"updated_at": "2026-04-28 11:56:48",
|
||||
"subcategory_id": "professional",
|
||||
"views": 0,
|
||||
"images": []
|
||||
"images": [],
|
||||
"publish_date": "2024-01-01"
|
||||
},
|
||||
{
|
||||
"name": "RTX PRO 6000",
|
||||
@@ -202,6 +203,7 @@
|
||||
"manufacturer": "NVIDIA",
|
||||
"subcategory_id": "professional",
|
||||
"views": 0,
|
||||
"images": []
|
||||
"images": [],
|
||||
"publish_date": "2020-01-01"
|
||||
}
|
||||
]
|
||||
@@ -10,7 +10,8 @@
|
||||
"subcategory_id": "suv",
|
||||
"views": 0,
|
||||
"images": [],
|
||||
"updated_at": "2026-04-28 12:32:13"
|
||||
"updated_at": "2026-04-28 12:32:13",
|
||||
"publish_date": "2021-01-01"
|
||||
},
|
||||
{
|
||||
"name": "秦PLUS",
|
||||
@@ -34,6 +35,7 @@
|
||||
"created_at": "2026-04-11 02:03:45",
|
||||
"visible": true,
|
||||
"raw_text": "秦PLUS的外观设计极具现代感和运动气息,前脸采用了家族化设计语言,标志性的大尺寸进气格栅占据了前脸的大部分空间,搭配锐利的LED大灯组,营造出强烈的视觉冲击力。车身线条流畅,腰线从车头贯穿至车尾,增强了整车的运动感。车尾部分,简洁大方的设计与前脸相呼应,整体风格时尚而不失稳重。\n\n上海:秦PLUS优惠促销,最新报价5.98万!轻松开新车\n\n秦PLUS拥有4780*1837*1515mm的长宽高尺寸和2718mm的轴距,赋予其宽敞的内部空间。车侧线条流畅且动感十足,从前轮距1580mm到后轮距1590mm,车轮布局合理,增强了车辆的稳定性和操控性。配备的225/60 R16轮胎规格,匹配独特风格的轮圈,为车辆增添了一抹动感与时尚的气息。\n\n上海:秦PLUS优惠促销,最新报价5.98万!轻松开新车\n\n秦PLUS的内饰风格简洁大气,给人以科技感和舒适感。中控台布局合理,配备了10.1英寸的中控屏幕,支持语音识别控制系统,可轻松操作多媒体系统、导航、电话和空调等功能。方向盘采用皮质材料,手感舒适,支持手动上下和前后调节,方便驾驶员调整到最佳驾驶姿势。座椅采用仿皮材质,主驾驶座椅具备前后调节、靠背调节和高低调节功能,而副驾驶座椅则支持前后调节和靠背调节,确保了乘客的舒适度。后排座椅可以按比例放倒,增加储物空间,同时,车内还配备了USB和Type-C接口,方便乘客为电子设备充电。\n\n上海:秦PLUS优惠促销,最新报价5.98万!轻松开新车\n\n秦PLUS搭载了一台1.5L 101马力的L4发动机,最大功率为74kW,最大扭矩为126N·m。与之匹配的是E-CVT无级变速器,这使得车辆在提供平稳的动力输出的同时,还能有效降低油耗。\n\n汽车之家车主@天艺风云 表示,外观设计是他当初选择秦PLUS的原因之一。他赞赏整体造型时尚大气,龙脸设计搭配犀利的大灯,辨识度极高。车身线条流畅,溜背式造型增添了几分运动感。全新的“龙鳞辉熠”格栅,精致又霸气,每次停车都有人问这是什么车,外观确实很吸引人。",
|
||||
"subcategory_id": "sedan"
|
||||
"subcategory_id": "sedan",
|
||||
"publish_date": "2023-01-01"
|
||||
}
|
||||
]
|
||||
@@ -10,7 +10,7 @@
|
||||
"visible": true,
|
||||
"raw_text": "",
|
||||
"images": [],
|
||||
"publish_date": "",
|
||||
"publish_date": "2023-01-01",
|
||||
"views": 0,
|
||||
"is_pinned": false,
|
||||
"subcategory_id": "90ce312b560d",
|
||||
@@ -27,7 +27,7 @@
|
||||
"visible": true,
|
||||
"raw_text": "",
|
||||
"images": [],
|
||||
"publish_date": "",
|
||||
"publish_date": "2023-01-01",
|
||||
"views": 0,
|
||||
"is_pinned": false,
|
||||
"subcategory_id": "90ce312b560d",
|
||||
@@ -44,7 +44,7 @@
|
||||
"visible": true,
|
||||
"raw_text": "",
|
||||
"images": [],
|
||||
"publish_date": "",
|
||||
"publish_date": "2023-01-01",
|
||||
"views": 0,
|
||||
"is_pinned": false,
|
||||
"subcategory_id": "90ce312b560d",
|
||||
@@ -95,7 +95,7 @@
|
||||
"images": [
|
||||
"/static/uploads/9703a1d16424_1777365365.png"
|
||||
],
|
||||
"publish_date": "",
|
||||
"publish_date": "2022-01-01",
|
||||
"views": 0,
|
||||
"is_pinned": false
|
||||
}
|
||||
|
||||
20
data/items_phones.json
Normal file
20
data/items_phones.json
Normal file
@@ -0,0 +1,20 @@
|
||||
[
|
||||
{
|
||||
"name": "华为Pura X Max",
|
||||
"brand": "华为",
|
||||
"processor": "麒麟9030 Pro",
|
||||
"screen_size": 7.6,
|
||||
"year": 2026,
|
||||
"description": "全球首款横向阔折叠屏手机,内屏7.6英寸(WQHD+分辨率),外屏5.5英寸,搭载麒麟9030 Pro芯片和鸿蒙6系统,支持AI眼动翻页和手写笔功能,素皮版重约210g",
|
||||
"id": "5ffe89899549",
|
||||
"category_id": "phones",
|
||||
"created_at": "2026-04-28 18:20:59",
|
||||
"visible": true,
|
||||
"raw_text": "华为Pura X Max:全球首款横向阔折叠屏手机,内屏7.6英寸(WQHD+分辨率),外屏5.5英寸,搭载麒麟9030 Pro芯片和鸿蒙6系统,支持AI眼动翻页和手写笔功能,素皮版重约210g,2026年4月20日上市。",
|
||||
"images": [],
|
||||
"subcategory_id": "",
|
||||
"publish_date": "2026-01-01",
|
||||
"views": 0,
|
||||
"is_pinned": false
|
||||
}
|
||||
]
|
||||
@@ -18,7 +18,8 @@
|
||||
"raw_text": "\nGPT-4 Turbo version with 128K context length, price is $10 per 1M input tokens",
|
||||
"subcategory_id": "chat",
|
||||
"views": 0,
|
||||
"images": []
|
||||
"images": [],
|
||||
"publish_date": "2023-03-14"
|
||||
},
|
||||
{
|
||||
"id": "gpt4turbo",
|
||||
@@ -35,7 +36,8 @@
|
||||
"license": "Proprietary",
|
||||
"description": "GPT-4增强版,128K上下文",
|
||||
"created_at": "2024-01-01",
|
||||
"subcategory_id": "chat"
|
||||
"subcategory_id": "chat",
|
||||
"publish_date": "2023-11-06"
|
||||
},
|
||||
{
|
||||
"id": "gpt35",
|
||||
@@ -52,7 +54,8 @@
|
||||
"license": "Proprietary",
|
||||
"description": "性价比高的通用模型",
|
||||
"created_at": "2024-01-01",
|
||||
"subcategory_id": "chat"
|
||||
"subcategory_id": "chat",
|
||||
"publish_date": "2023-03-01"
|
||||
},
|
||||
{
|
||||
"id": "claude3opus",
|
||||
@@ -69,7 +72,8 @@
|
||||
"license": "Proprietary",
|
||||
"description": "Anthropic最强模型,200K上下文",
|
||||
"created_at": "2024-01-01",
|
||||
"subcategory_id": "code"
|
||||
"subcategory_id": "code",
|
||||
"publish_date": "2024-03-04"
|
||||
},
|
||||
{
|
||||
"id": "claude3sonnet",
|
||||
@@ -86,7 +90,8 @@
|
||||
"license": "Proprietary",
|
||||
"description": "平衡性能与成本",
|
||||
"created_at": "2024-01-01",
|
||||
"subcategory_id": "chat"
|
||||
"subcategory_id": "chat",
|
||||
"publish_date": "2024-03-04"
|
||||
},
|
||||
{
|
||||
"id": "llama270b",
|
||||
@@ -103,7 +108,8 @@
|
||||
"license": "Llama 2 Community",
|
||||
"description": "Meta开源大模型,70B参数",
|
||||
"created_at": "2024-01-01",
|
||||
"subcategory_id": "chat"
|
||||
"subcategory_id": "chat",
|
||||
"publish_date": "2023-07-18"
|
||||
},
|
||||
{
|
||||
"id": "llama3",
|
||||
@@ -120,7 +126,8 @@
|
||||
"license": "Llama 3 Community",
|
||||
"description": "Meta最新开源模型,性能接近GPT-4",
|
||||
"created_at": "2024-01-01",
|
||||
"subcategory_id": "code"
|
||||
"subcategory_id": "code",
|
||||
"publish_date": "2024-04-18"
|
||||
},
|
||||
{
|
||||
"id": "mistral7b",
|
||||
@@ -137,7 +144,8 @@
|
||||
"license": "Apache 2.0",
|
||||
"description": "小巧高效的开源模型",
|
||||
"created_at": "2024-01-01",
|
||||
"subcategory_id": "chat"
|
||||
"subcategory_id": "chat",
|
||||
"publish_date": "2023-09-27"
|
||||
},
|
||||
{
|
||||
"id": "mixtral8x7b",
|
||||
@@ -154,7 +162,8 @@
|
||||
"license": "Apache 2.0",
|
||||
"description": "MoE架构,高效推理",
|
||||
"created_at": "2024-01-01",
|
||||
"subcategory_id": "chat"
|
||||
"subcategory_id": "chat",
|
||||
"publish_date": "2023-12-11"
|
||||
},
|
||||
{
|
||||
"id": "qwen72b",
|
||||
@@ -171,7 +180,8 @@
|
||||
"license": "Apache 2.0",
|
||||
"description": "阿里开源大模型,中文能力强",
|
||||
"created_at": "2024-01-01",
|
||||
"subcategory_id": "chat"
|
||||
"subcategory_id": "chat",
|
||||
"publish_date": "2024-02-05"
|
||||
},
|
||||
{
|
||||
"id": "deepseekv3",
|
||||
@@ -188,7 +198,8 @@
|
||||
"license": "MIT",
|
||||
"description": "DeepSeek最新模型,性价比极高",
|
||||
"created_at": "2024-01-01",
|
||||
"subcategory_id": "code"
|
||||
"subcategory_id": "code",
|
||||
"publish_date": "2024-12-26"
|
||||
},
|
||||
{
|
||||
"id": "glm4",
|
||||
@@ -206,6 +217,7 @@
|
||||
"description": "智谱AI大模型,中文能力强",
|
||||
"created_at": "2024-01-01",
|
||||
"visible": true,
|
||||
"subcategory_id": "chat"
|
||||
"subcategory_id": "chat",
|
||||
"publish_date": "2024-01-01"
|
||||
}
|
||||
]
|
||||
28607
logs/app.log
28607
logs/app.log
File diff suppressed because it is too large
Load Diff
@@ -185,23 +185,8 @@
|
||||
<div id="model-subcategory-filters" class="flex gap-2"></div>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl shadow-sm overflow-x-auto">
|
||||
<table class="w-full min-w-[1200px]">
|
||||
<thead class="bg-gray-50 border-b">
|
||||
<tr>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">置顶</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">名称</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">厂商</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">子类别</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">参数量</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">上下文</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">类型</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">发布日期</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">热度</th>
|
||||
<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">显示</th>
|
||||
<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="admin-models-table"><tr><td colspan="11" class="text-center text-gray-400 py-8">加载中...</td></tr></tbody>
|
||||
<table class="w-full" id="admin-models-table">
|
||||
<tbody><tr><td colspan="20" class="text-center text-gray-400 py-8">加载中...</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
@@ -221,23 +206,8 @@
|
||||
<div id="gpu-subcategory-filters" class="flex gap-2"></div>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl shadow-sm overflow-x-auto">
|
||||
<table class="w-full min-w-[1200px]">
|
||||
<thead class="bg-gray-50 border-b">
|
||||
<tr>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">置顶</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">名称</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">厂商</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">子类别</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">显存</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">架构</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">价格</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">发布日期</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">热度</th>
|
||||
<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">显示</th>
|
||||
<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="admin-gpus-table"><tr><td colspan="11" class="text-center text-gray-400 py-8">加载中...</td></tr></tbody>
|
||||
<table class="w-full" id="admin-gpus-table">
|
||||
<tbody><tr><td colspan="20" class="text-center text-gray-400 py-8">加载中...</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
@@ -257,23 +227,8 @@
|
||||
<div id="cpu-subcategory-filters" class="flex gap-2"></div>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl shadow-sm overflow-x-auto">
|
||||
<table class="w-full min-w-[1200px]">
|
||||
<thead class="bg-gray-50 border-b">
|
||||
<tr>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">置顶</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">名称</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">厂商</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">子类别</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">核心/线程</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">主频</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">价格</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">发布日期</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">热度</th>
|
||||
<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">显示</th>
|
||||
<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="admin-cpus-table"><tr><td colspan="11" class="text-center text-gray-400 py-8">加载中...</td></tr></tbody>
|
||||
<table class="w-full" id="admin-cpus-table">
|
||||
<tbody><tr><td colspan="20" class="text-center text-gray-400 py-8">加载中...</td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
@@ -676,8 +631,11 @@
|
||||
// 显示动态分类数据
|
||||
async function showDynamicCategory(categoryId) {
|
||||
dynamicCategoryId = categoryId;
|
||||
dynamicSubcategoryFilter = ''; // 重置筛选
|
||||
dynamicSubcategoryFilter = '';
|
||||
const cat = categories.find(c => c.id === categoryId);
|
||||
const fields = cat ? (cat.fields || []) : [];
|
||||
const fixedFields = ['id', 'created_at', 'updated_at', 'visible', 'raw_text', 'category_id', 'subcategory_id', 'is_pinned', 'images'];
|
||||
const displayFields = fields.filter(f => !fixedFields.includes(f.key));
|
||||
|
||||
document.querySelectorAll('section').forEach(s => s.classList.add('hidden'));
|
||||
document.getElementById('section-dynamic').classList.remove('hidden');
|
||||
@@ -694,7 +652,6 @@
|
||||
|
||||
document.getElementById('dynamic-title').textContent = cat.name + '管理';
|
||||
|
||||
// 渲染子类别筛选按钮
|
||||
if (cat.subcategories && cat.subcategories.length > 0) {
|
||||
document.getElementById('dynamic-filter-area').classList.remove('hidden');
|
||||
renderSubcategoryFilters(categoryId, 'dynamic-subcategory-filters', 'filterDynamicBySubcategory');
|
||||
@@ -702,42 +659,50 @@
|
||||
document.getElementById('dynamic-filter-area').classList.add('hidden');
|
||||
}
|
||||
|
||||
// 加载该分类的数据(后台显示全部,包括隐藏的)
|
||||
const res = await fetch(`/api/items/${categoryId}?all=1`);
|
||||
let items = await res.json();
|
||||
|
||||
// 子类别筛选
|
||||
if (dynamicSubcategoryFilter) {
|
||||
items = items.filter(i => i.subcategory_id === dynamicSubcategoryFilter);
|
||||
}
|
||||
|
||||
if (items.length === 0) {
|
||||
document.getElementById('admin-dynamic-table').innerHTML = '<tr><td class="text-center text-gray-400 py-8">暂无数据,点击上方"添加数据"按钮添加</td></tr>';
|
||||
document.getElementById('admin-dynamic-table').innerHTML = '<tr><td class="text-center text-gray-400 py-8">暂无数据</td></tr>';
|
||||
} else {
|
||||
const keys = Object.keys(items[0]).filter(k => !['id', 'created_at', 'updated_at', 'visible', 'raw_text', 'subcategory_id'].includes(k));
|
||||
let html = `<thead class="bg-gray-50 border-b"><tr>`;
|
||||
// 添加子类别列
|
||||
if (cat.subcategories && cat.subcategories.length > 0) {
|
||||
html += `<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">子类别</th>`;
|
||||
}
|
||||
keys.forEach(k => { html += `<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">${k}</th>`; });
|
||||
displayFields.forEach(f => {
|
||||
html += `<th class="px-4 py-3 text-left text-sm font-medium text-gray-600">${f.label}</th>`;
|
||||
});
|
||||
html += `<th class="px-4 py-3 text-center text-sm font-medium text-gray-600">显示</th>`;
|
||||
html += `<th class="px-4 py-3 text-center text-sm font-medium text-gray-600">操作</th></tr></thead><tbody>`;
|
||||
|
||||
items.forEach(item => {
|
||||
html += `<tr class="border-b hover:bg-gray-50 ${item.visible === false ? 'bg-gray-100 opacity-60' : ''}">`;
|
||||
// 子类别显示
|
||||
if (cat.subcategories && cat.subcategories.length > 0) {
|
||||
const subName = getSubcategoryName(categoryId, item.subcategory_id);
|
||||
const subIcon = getSubcategoryIcon(categoryId, item.subcategory_id);
|
||||
html += `<td class="px-4 py-3">${item.subcategory_id ? `<span class="px-2 py-1 bg-indigo-100 text-indigo-600 rounded text-xs"><i class="${subIcon} mr-1"></i>${subName}</span>` : '<span class="text-gray-400">-</span>'}</td>`;
|
||||
html += `<td class="px-4 py-3">${item.subcategory_id ? `<span class="px-2 py-1 bg-indigo-100 text-indigo-600 rounded text-xs"><i class="${getSubcategoryIcon(categoryId, item.subcategory_id)} mr-1"></i>${getSubcategoryName(categoryId, item.subcategory_id)}</span>` : '<span class="text-gray-400">-</span>'}</td>`;
|
||||
}
|
||||
keys.forEach(k => { html += `<td class="px-4 py-3 text-gray-600">${item[k] || '-'}</td>`; });
|
||||
displayFields.forEach(f => {
|
||||
const value = item[f.key];
|
||||
let displayValue = '-';
|
||||
if (value !== null && value !== undefined && value !== '') {
|
||||
if (f.type === 'boolean') {
|
||||
displayValue = value ? '<span class="text-green-600">是</span>' : '<span class="text-gray-400">否</span>';
|
||||
} else if (f.type === 'json') {
|
||||
displayValue = typeof value === 'object' ? JSON.stringify(value).substring(0, 30) + '...' : String(value).substring(0, 30);
|
||||
} else {
|
||||
displayValue = String(value).substring(0, 30);
|
||||
}
|
||||
}
|
||||
html += `<td class="px-4 py-3 text-gray-600">${displayValue}</td>`;
|
||||
});
|
||||
html += `<td class="px-4 py-3 text-center">
|
||||
<button onclick="toggleVisible('dynamic', '${item.id}')" class="${item.visible === false ? 'text-gray-400' : 'text-green-600'} hover:opacity-80" title="${item.visible === false ? '点击显示' : '点击隐藏'}">
|
||||
<button onclick="toggleVisible('dynamic', '${item.id}')" class="${item.visible === false ? 'text-gray-400' : 'text-green-600'} hover:opacity-80">
|
||||
<i class="${item.visible === false ? 'ri-eye-off-line' : 'ri-eye-line'}"></i>
|
||||
</button>
|
||||
${item.raw_text ? `<button onclick="showRawData('${item.id}', 'dynamic')" class="text-gray-400 hover:text-gray-600 ml-1" title="查看原始数据"><i class="ri-file-text-line"></i></button>` : ''}
|
||||
${item.raw_text ? `<button onclick="showRawData('${item.id}', 'dynamic')" class="text-gray-400 hover:text-gray-600 ml-1"><i class="ri-file-text-line"></i></button>` : ''}
|
||||
</td>`;
|
||||
html += `<td class="px-4 py-3 text-center">
|
||||
<button onclick="editDynamicItem('${item.id}')" class="text-blue-600 hover:text-blue-800 mr-2"><i class="ri-edit-line"></i></button>
|
||||
@@ -928,6 +893,12 @@
|
||||
// 加载模型列表
|
||||
async function loadAdminModels() {
|
||||
renderSubcategoryFilters('ai-models', 'model-subcategory-filters', 'filterModelsBySubcategory');
|
||||
|
||||
// 获取类别字段配置
|
||||
const cat = categories.find(c => c.id === 'ai-models');
|
||||
const fields = cat ? (cat.fields || []) : [];
|
||||
const subcats = cat ? (cat.subcategories || []) : [];
|
||||
|
||||
const res = await fetch('/api/models?all=1');
|
||||
let models = await res.json();
|
||||
|
||||
@@ -936,36 +907,80 @@
|
||||
models = models.filter(m => m.subcategory_id === modelSubcategoryFilter);
|
||||
}
|
||||
|
||||
if (models.length === 0) { document.getElementById('admin-models-table').innerHTML = '<tr><td colspan="11" class="text-center text-gray-400 py-8">暂无数据</td></tr>'; return; }
|
||||
document.getElementById('admin-models-table').innerHTML = models.map(m => `
|
||||
<tr class="border-b hover:bg-gray-50 ${m.visible === false ? 'bg-gray-100 opacity-60' : ''} ${m.is_pinned ? 'bg-yellow-50' : ''}">
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="togglePin('model', '${m.id}')" class="${m.is_pinned ? 'text-yellow-500' : 'text-gray-400'} hover:opacity-80" title="${m.is_pinned ? '取消置顶' : '置顶'}">
|
||||
<i class="${m.is_pinned ? 'ri-pushpin-fill' : 'ri-pushpin-line'}"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td class="px-3 py-3 font-medium text-gray-800">${m.name}</td>
|
||||
<td class="px-3 py-3 text-gray-600">${m.organization}</td>
|
||||
<td class="px-3 py-3">
|
||||
${m.subcategory_id ? `<span class="px-2 py-1 bg-blue-100 text-blue-600 rounded text-xs"><i class="${getSubcategoryIcon('ai-models', m.subcategory_id)} mr-1"></i>${getSubcategoryName('ai-models', m.subcategory_id)}</span>` : '<span class="text-gray-400">-</span>'}
|
||||
</td>
|
||||
<td class="px-3 py-3">${m.parameters}B</td>
|
||||
<td class="px-3 py-3 text-gray-600">${m.context_length || '-'}</td>
|
||||
<td class="px-3 py-3">${m.is_open_source ? '<span class="text-green-600">开源</span>' : '<span class="text-gray-600">商业</span>'}</td>
|
||||
<td class="px-3 py-3 text-gray-500 text-sm">${m.publish_date || '-'}</td>
|
||||
<td class="px-3 py-3 text-gray-500 text-sm">${m.views || 0}</td>
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="toggleVisible('model', '${m.id}')" class="${m.visible === false ? 'text-gray-400' : 'text-green-600'} hover:opacity-80" title="${m.visible === false ? '点击显示' : '点击隐藏'}">
|
||||
<i class="${m.visible === false ? 'ri-eye-off-line' : 'ri-eye-line'}"></i>
|
||||
</button>
|
||||
${m.raw_text ? `<button onclick="showRawData('${m.id}', 'model')" class="text-gray-400 hover:text-gray-600 ml-1" title="查看原始数据"><i class="ri-file-text-line"></i></button>` : ''}
|
||||
</td>
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="editItem('model', '${m.id}')" class="text-blue-600 hover:text-blue-800 mr-2"><i class="ri-edit-line"></i></button>
|
||||
<button onclick="deleteItem('model', '${m.id}')" class="text-red-600 hover:text-red-800"><i class="ri-delete-bin-line"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
if (models.length === 0) {
|
||||
document.getElementById('admin-models-table').innerHTML = '<tr><td colspan="20" class="text-center text-gray-400 py-8">暂无数据</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
// 动态生成表头
|
||||
const fixedFields = ['subcategory_id', 'id', 'images']; // 固定字段
|
||||
const displayFields = fields.filter(f => !fixedFields.includes(f.key));
|
||||
|
||||
let headerHtml = `
|
||||
<thead class="bg-gray-50 border-b">
|
||||
<tr>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">置顶</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">名称</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">子类别</th>`;
|
||||
|
||||
// 添加动态字段列(只显示前6个关键字段)
|
||||
displayFields.slice(0, 6).forEach(f => {
|
||||
headerHtml += `<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">${f.label}</th>`;
|
||||
});
|
||||
|
||||
headerHtml += `
|
||||
<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">显示</th>
|
||||
<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">操作</th>
|
||||
</tr>
|
||||
</thead>`;
|
||||
|
||||
// 动态生成表格内容
|
||||
let bodyHtml = '<tbody>';
|
||||
models.forEach(m => {
|
||||
bodyHtml += `
|
||||
<tr class="border-b hover:bg-gray-50 ${m.visible === false ? 'bg-gray-100 opacity-60' : ''} ${m.is_pinned ? 'bg-yellow-50' : ''}">
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="togglePin('model', '${m.id}')" class="${m.is_pinned ? 'text-yellow-500' : 'text-gray-400'} hover:opacity-80">
|
||||
<i class="${m.is_pinned ? 'ri-pushpin-fill' : 'ri-pushpin-line'}"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td class="px-3 py-3 font-medium text-gray-800">${m.name || '-'}</td>
|
||||
<td class="px-3 py-3">
|
||||
${m.subcategory_id ? `<span class="px-2 py-1 bg-blue-100 text-blue-600 rounded text-xs"><i class="${getSubcategoryIcon('ai-models', m.subcategory_id)} mr-1"></i>${getSubcategoryName('ai-models', m.subcategory_id)}</span>` : '<span class="text-gray-400">-</span>'}
|
||||
</td>`;
|
||||
|
||||
// 添加动态字段值
|
||||
displayFields.slice(0, 6).forEach(f => {
|
||||
const value = m[f.key];
|
||||
let displayValue = '-';
|
||||
if (value !== null && value !== undefined && value !== '') {
|
||||
if (f.type === 'boolean') {
|
||||
displayValue = value ? '<span class="text-green-600">是</span>' : '<span class="text-gray-400">否</span>';
|
||||
} else if (f.type === 'number') {
|
||||
displayValue = value;
|
||||
} else {
|
||||
displayValue = String(value).substring(0, 20);
|
||||
}
|
||||
}
|
||||
bodyHtml += `<td class="px-3 py-3 text-gray-600">${displayValue}</td>`;
|
||||
});
|
||||
|
||||
bodyHtml += `
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="toggleVisible('model', '${m.id}')" class="${m.visible === false ? 'text-gray-400' : 'text-green-600'} hover:opacity-80">
|
||||
<i class="${m.visible === false ? 'ri-eye-off-line' : 'ri-eye-line'}"></i>
|
||||
</button>
|
||||
${m.raw_text ? `<button onclick="showRawData('${m.id}', 'model')" class="text-gray-400 hover:text-gray-600 ml-1"><i class="ri-file-text-line"></i></button>` : ''}
|
||||
</td>
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="editItem('model', '${m.id}')" class="text-blue-600 hover:text-blue-800 mr-2"><i class="ri-edit-line"></i></button>
|
||||
<button onclick="deleteItem('model', '${m.id}')" class="text-red-600 hover:text-red-800"><i class="ri-delete-bin-line"></i></button>
|
||||
</td>
|
||||
</tr>`;
|
||||
});
|
||||
bodyHtml += '</tbody>';
|
||||
|
||||
document.getElementById('admin-models-table').innerHTML = headerHtml + bodyHtml;
|
||||
}
|
||||
|
||||
function filterModelsBySubcategory(subId) {
|
||||
@@ -976,44 +991,68 @@
|
||||
// 加载GPU列表
|
||||
async function loadAdminGpus() {
|
||||
renderSubcategoryFilters('gpus', 'gpu-subcategory-filters', 'filterGpusBySubcategory');
|
||||
|
||||
const cat = categories.find(c => c.id === 'gpus');
|
||||
const fields = cat ? (cat.fields || []) : [];
|
||||
const fixedFields = ['subcategory_id', 'id', 'images'];
|
||||
const displayFields = fields.filter(f => !fixedFields.includes(f.key));
|
||||
|
||||
const res = await fetch('/api/gpus?all=1');
|
||||
let gpus = await res.json();
|
||||
|
||||
// 子类别筛选
|
||||
if (gpuSubcategoryFilter) {
|
||||
gpus = gpus.filter(g => g.subcategory_id === gpuSubcategoryFilter);
|
||||
}
|
||||
|
||||
if (gpus.length === 0) {
|
||||
document.getElementById('admin-gpus-table').innerHTML = '<tr><td colspan="20" class="text-center text-gray-400 py-8">暂无数据</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
if (gpus.length === 0) { document.getElementById('admin-gpus-table').innerHTML = '<tr><td colspan="11" class="text-center text-gray-400 py-8">暂无数据</td></tr>'; return; }
|
||||
document.getElementById('admin-gpus-table').innerHTML = gpus.map(g => `
|
||||
<tr class="border-b hover:bg-gray-50 ${g.visible === false ? 'bg-gray-100 opacity-60' : ''} ${g.is_pinned ? 'bg-yellow-50' : ''}">
|
||||
let headerHtml = `<thead class="bg-gray-50 border-b"><tr>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">置顶</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">名称</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">子类别</th>`;
|
||||
displayFields.slice(0, 6).forEach(f => {
|
||||
headerHtml += `<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">${f.label}</th>`;
|
||||
});
|
||||
headerHtml += `<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">显示</th>
|
||||
<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">操作</th></tr></thead>`;
|
||||
|
||||
let bodyHtml = '<tbody>';
|
||||
gpus.forEach(g => {
|
||||
bodyHtml += `<tr class="border-b hover:bg-gray-50 ${g.visible === false ? 'bg-gray-100 opacity-60' : ''} ${g.is_pinned ? 'bg-yellow-50' : ''}">
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="togglePin('gpu', '${g.id}')" class="${g.is_pinned ? 'text-yellow-500' : 'text-gray-400'} hover:opacity-80" title="${g.is_pinned ? '取消置顶' : '置顶'}">
|
||||
<button onclick="togglePin('gpu', '${g.id}')" class="${g.is_pinned ? 'text-yellow-500' : 'text-gray-400'} hover:opacity-80">
|
||||
<i class="${g.is_pinned ? 'ri-pushpin-fill' : 'ri-pushpin-line'}"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td class="px-3 py-3 font-medium text-gray-800">${g.name}</td>
|
||||
<td class="px-3 py-3 text-gray-600">${g.manufacturer}</td>
|
||||
<td class="px-3 py-3 font-medium text-gray-800">${g.name || '-'}</td>
|
||||
<td class="px-3 py-3">
|
||||
${g.subcategory_id ? `<span class="px-2 py-1 bg-green-100 text-green-600 rounded text-xs"><i class="${getSubcategoryIcon('gpus', g.subcategory_id)} mr-1"></i>${getSubcategoryName('gpus', g.subcategory_id)}</span>` : '<span class="text-gray-400">-</span>'}
|
||||
</td>
|
||||
<td class="px-3 py-3">${g.memory_gb}GB</td>
|
||||
<td class="px-3 py-3 text-gray-600">${g.architecture || '-'}</td>
|
||||
<td class="px-3 py-3 text-gray-600">${formatPrice(g)}</td>
|
||||
<td class="px-3 py-3 text-gray-500 text-sm">${g.publish_date || '-'}</td>
|
||||
<td class="px-3 py-3 text-gray-500 text-sm">${g.views || 0}</td>
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="toggleVisible('gpu', '${g.id}')" class="${g.visible === false ? 'text-gray-400' : 'text-green-600'} hover:opacity-80" title="${g.visible === false ? '点击显示' : '点击隐藏'}">
|
||||
</td>`;
|
||||
displayFields.slice(0, 6).forEach(f => {
|
||||
const value = g[f.key];
|
||||
let displayValue = '-';
|
||||
if (value !== null && value !== undefined && value !== '') {
|
||||
displayValue = f.type === 'boolean' ? (value ? '<span class="text-green-600">是</span>' : '<span class="text-gray-400">否</span>') : value;
|
||||
}
|
||||
bodyHtml += `<td class="px-3 py-3 text-gray-600">${displayValue}</td>`;
|
||||
});
|
||||
bodyHtml += `<td class="px-3 py-3 text-center">
|
||||
<button onclick="toggleVisible('gpu', '${g.id}')" class="${g.visible === false ? 'text-gray-400' : 'text-green-600'} hover:opacity-80">
|
||||
<i class="${g.visible === false ? 'ri-eye-off-line' : 'ri-eye-line'}"></i>
|
||||
</button>
|
||||
${g.raw_text ? `<button onclick="showRawData('${g.id}', 'gpu')" class="text-gray-400 hover:text-gray-600 ml-1" title="查看原始数据"><i class="ri-file-text-line"></i></button>` : ''}
|
||||
${g.raw_text ? `<button onclick="showRawData('${g.id}', 'gpu')" class="text-gray-400 hover:text-gray-600 ml-1"><i class="ri-file-text-line"></i></button>` : ''}
|
||||
</td>
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="editItem('gpu', '${g.id}')" class="text-blue-600 hover:text-blue-800 mr-2"><i class="ri-edit-line"></i></button>
|
||||
<button onclick="deleteItem('gpu', '${g.id}')" class="text-red-600 hover:text-red-800"><i class="ri-delete-bin-line"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
</td></tr>`;
|
||||
});
|
||||
bodyHtml += '</tbody>';
|
||||
|
||||
document.getElementById('admin-gpus-table').innerHTML = headerHtml + bodyHtml;
|
||||
}
|
||||
|
||||
function filterGpusBySubcategory(subId) {
|
||||
@@ -1024,44 +1063,68 @@
|
||||
// 加载CPU列表
|
||||
async function loadAdminCpus() {
|
||||
renderSubcategoryFilters('cpus', 'cpu-subcategory-filters', 'filterCpusBySubcategory');
|
||||
|
||||
const cat = categories.find(c => c.id === 'cpus');
|
||||
const fields = cat ? (cat.fields || []) : [];
|
||||
const fixedFields = ['subcategory_id', 'id', 'images'];
|
||||
const displayFields = fields.filter(f => !fixedFields.includes(f.key));
|
||||
|
||||
const res = await fetch('/api/cpus?all=1');
|
||||
let cpus = await res.json();
|
||||
|
||||
// 子类别筛选
|
||||
if (cpuSubcategoryFilter) {
|
||||
cpus = cpus.filter(c => c.subcategory_id === cpuSubcategoryFilter);
|
||||
}
|
||||
|
||||
if (cpus.length === 0) { document.getElementById('admin-cpus-table').innerHTML = '<tr><td colspan="11" class="text-center text-gray-400 py-8">暂无数据</td></tr>'; return; }
|
||||
document.getElementById('admin-cpus-table').innerHTML = cpus.map(c => `
|
||||
<tr class="border-b hover:bg-gray-50 ${c.visible === false ? 'bg-gray-100 opacity-60' : ''} ${c.is_pinned ? 'bg-yellow-50' : ''}">
|
||||
if (cpus.length === 0) {
|
||||
document.getElementById('admin-cpus-table').innerHTML = '<tr><td colspan="20" class="text-center text-gray-400 py-8">暂无数据</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
let headerHtml = `<thead class="bg-gray-50 border-b"><tr>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">置顶</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">名称</th>
|
||||
<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">子类别</th>`;
|
||||
displayFields.slice(0, 6).forEach(f => {
|
||||
headerHtml += `<th class="px-3 py-3 text-left text-sm font-medium text-gray-600">${f.label}</th>`;
|
||||
});
|
||||
headerHtml += `<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">显示</th>
|
||||
<th class="px-3 py-3 text-center text-sm font-medium text-gray-600">操作</th></tr></thead>`;
|
||||
|
||||
let bodyHtml = '<tbody>';
|
||||
cpus.forEach(c => {
|
||||
bodyHtml += `<tr class="border-b hover:bg-gray-50 ${c.visible === false ? 'bg-gray-100 opacity-60' : ''} ${c.is_pinned ? 'bg-yellow-50' : ''}">
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="togglePin('cpu', '${c.id}')" class="${c.is_pinned ? 'text-yellow-500' : 'text-gray-400'} hover:opacity-80" title="${c.is_pinned ? '取消置顶' : '置顶'}">
|
||||
<button onclick="togglePin('cpu', '${c.id}')" class="${c.is_pinned ? 'text-yellow-500' : 'text-gray-400'} hover:opacity-80">
|
||||
<i class="${c.is_pinned ? 'ri-pushpin-fill' : 'ri-pushpin-line'}"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td class="px-3 py-3 font-medium text-gray-800">${c.name}</td>
|
||||
<td class="px-3 py-3 text-gray-600">${c.manufacturer}</td>
|
||||
<td class="px-3 py-3 font-medium text-gray-800">${c.name || '-'}</td>
|
||||
<td class="px-3 py-3">
|
||||
${c.subcategory_id ? `<span class="px-2 py-1 bg-purple-100 text-purple-600 rounded text-xs"><i class="${getSubcategoryIcon('cpus', c.subcategory_id)} mr-1"></i>${getSubcategoryName('cpus', c.subcategory_id)}</span>` : '<span class="text-gray-400">-</span>'}
|
||||
</td>
|
||||
<td class="px-3 py-3">${c.cores}/${c.threads}</td>
|
||||
<td class="px-3 py-3 text-gray-600">${c.base_clock_ghz || '-'}-${c.boost_clock_ghz || '-'}GHz</td>
|
||||
<td class="px-3 py-3 text-gray-600">${formatPrice(c)}</td>
|
||||
<td class="px-3 py-3 text-gray-500 text-sm">${c.publish_date || '-'}</td>
|
||||
<td class="px-3 py-3 text-gray-500 text-sm">${c.views || 0}</td>
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="toggleVisible('cpu', '${c.id}')" class="${c.visible === false ? 'text-gray-400' : 'text-green-600'} hover:opacity-80" title="${c.visible === false ? '点击显示' : '点击隐藏'}">
|
||||
</td>`;
|
||||
displayFields.slice(0, 6).forEach(f => {
|
||||
const value = c[f.key];
|
||||
let displayValue = '-';
|
||||
if (value !== null && value !== undefined && value !== '') {
|
||||
displayValue = f.type === 'boolean' ? (value ? '<span class="text-green-600">是</span>' : '<span class="text-gray-400">否</span>') : value;
|
||||
}
|
||||
bodyHtml += `<td class="px-3 py-3 text-gray-600">${displayValue}</td>`;
|
||||
});
|
||||
bodyHtml += `<td class="px-3 py-3 text-center">
|
||||
<button onclick="toggleVisible('cpu', '${c.id}')" class="${c.visible === false ? 'text-gray-400' : 'text-green-600'} hover:opacity-80">
|
||||
<i class="${c.visible === false ? 'ri-eye-off-line' : 'ri-eye-line'}"></i>
|
||||
</button>
|
||||
${c.raw_text ? `<button onclick="showRawData('${c.id}', 'cpu')" class="text-gray-400 hover:text-gray-600 ml-1" title="查看原始数据"><i class="ri-file-text-line"></i></button>` : ''}
|
||||
${c.raw_text ? `<button onclick="showRawData('${c.id}', 'cpu')" class="text-gray-400 hover:text-gray-600 ml-1"><i class="ri-file-text-line"></i></button>` : ''}
|
||||
</td>
|
||||
<td class="px-3 py-3 text-center">
|
||||
<button onclick="editItem('cpu', '${c.id}')" class="text-blue-600 hover:text-blue-800 mr-2"><i class="ri-edit-line"></i></button>
|
||||
<button onclick="deleteItem('cpu', '${c.id}')" class="text-red-600 hover:text-red-800"><i class="ri-delete-bin-line"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
</td></tr>`;
|
||||
});
|
||||
bodyHtml += '</tbody>';
|
||||
|
||||
document.getElementById('admin-cpus-table').innerHTML = headerHtml + bodyHtml;
|
||||
}
|
||||
|
||||
function filterCpusBySubcategory(subId) {
|
||||
@@ -1782,23 +1845,64 @@
|
||||
return `<div><label class="text-sm text-gray-600 mb-1 block">子类别</label><select name="subcategory_id" class="w-full px-3 py-2 border rounded-lg"><option value="">请选择</option>${options}</select></div>`;
|
||||
}
|
||||
|
||||
// 根据类别字段配置动态生成表单字段
|
||||
function generateFormFields(categoryId, data = {}, subcategoryId = '') {
|
||||
const cat = categories.find(c => c.id === categoryId);
|
||||
if (!cat) return '';
|
||||
|
||||
const fields = cat.fields || [];
|
||||
const fixedFields = ['id', 'subcategory_id', 'images', 'visible', 'created_at', 'updated_at', 'raw_text', 'is_pinned', 'views'];
|
||||
|
||||
// 合并子类别额外字段
|
||||
let allFields = fields;
|
||||
if (subcategoryId) {
|
||||
const subcat = cat.subcategories?.find(s => s.id === subcategoryId);
|
||||
if (subcat && subcat.extra_fields) {
|
||||
allFields = [...fields, ...subcat.extra_fields];
|
||||
}
|
||||
}
|
||||
|
||||
const formFields = allFields.filter(f => !fixedFields.includes(f.key));
|
||||
|
||||
return formFields.map(field => {
|
||||
const value = data[field.key] || '';
|
||||
const required = field.required ? 'required' : '';
|
||||
const requiredMark = field.required ? '<span class="text-red-500">*</span>' : '';
|
||||
const desc = field.description ? `<p class="text-xs text-gray-400 mt-1">${field.description}</p>` : '';
|
||||
|
||||
let inputHtml = '';
|
||||
if (field.type === 'boolean') {
|
||||
inputHtml = `<select name="${field.key}" class="w-full px-3 py-2 border rounded-lg" ${required}>
|
||||
<option value="true" ${value === true ? 'selected' : ''}>是</option>
|
||||
<option value="false" ${value === false || !value ? 'selected' : ''}>否</option>
|
||||
</select>`;
|
||||
} else if (field.type === 'number') {
|
||||
inputHtml = `<input type="number" name="${field.key}" value="${value}" step="any" class="w-full px-3 py-2 border rounded-lg" ${required}>`;
|
||||
} else if (field.type === 'date') {
|
||||
inputHtml = `<input type="date" name="${field.key}" value="${value}" class="w-full px-3 py-2 border rounded-lg" ${required}>`;
|
||||
} else if (field.type === 'json') {
|
||||
inputHtml = `<textarea name="${field.key}" rows="3" class="w-full px-3 py-2 border rounded-lg font-mono text-sm" ${required}>${typeof value === 'object' ? JSON.stringify(value, null, 2) : value}</textarea>`;
|
||||
} else if (field.type === 'url') {
|
||||
inputHtml = `<input type="url" name="${field.key}" value="${value}" class="w-full px-3 py-2 border rounded-lg" ${required}>`;
|
||||
} else {
|
||||
inputHtml = `<input type="text" name="${field.key}" value="${value}" class="w-full px-3 py-2 border rounded-lg" ${required}>`;
|
||||
}
|
||||
|
||||
return `<div><label class="text-sm text-gray-600 mb-1 block">${field.label}${requiredMark}</label>${inputHtml}${desc}</div>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function getDynamicForm(data = {}) {
|
||||
const cat = categories.find(c => c.id === dynamicCategoryId);
|
||||
currentImages = data.images || [];
|
||||
const subcategorySelect = getSubcategorySelect(dynamicCategoryId, data.subcategory_id);
|
||||
const formFields = generateFormFields(dynamicCategoryId, data, data.subcategory_id);
|
||||
|
||||
return `<form id="itemForm" class="space-y-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
${subcategorySelect}
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">名称 *</label><input type="text" name="name" value="${data.name || ''}" required class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">品牌</label><input type="text" name="brand" value="${data.brand || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">价格</label><input type="number" name="price" value="${data.price || ''}" step="0.01" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">年份</label><input type="number" name="year" value="${data.year || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">发布日期</label><input type="date" name="publish_date" value="${data.publish_date || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">热度</label><input type="number" name="views" value="${data.views || 0}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
${formFields}
|
||||
</div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">参数(JSON格式)</label><textarea name="specs" rows="4" class="w-full px-3 py-2 border rounded-lg font-mono text-sm" placeholder='{"key": "value"}'>${data.specs || ''}</textarea></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">描述</label><textarea name="description" rows="2" class="w-full px-3 py-2 border rounded-lg">${data.description || ''}</textarea></div>
|
||||
${getImageUploadComponent(currentImages, 'dynamic')}
|
||||
</form>`;
|
||||
}
|
||||
@@ -1806,25 +1910,13 @@
|
||||
function getModelForm(data = {}) {
|
||||
currentImages = data.images || [];
|
||||
const subcategorySelect = getSubcategorySelect('ai-models', data.subcategory_id);
|
||||
const formFields = generateFormFields('ai-models', data, data.subcategory_id);
|
||||
|
||||
return `<form id="itemForm" class="space-y-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
${subcategorySelect}
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">名称 *</label><input type="text" name="name" value="${data.name || ''}" required class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">厂商 *</label><input type="text" name="organization" value="${data.organization || ''}" required class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">参数量(B) *</label><input type="number" name="parameters" value="${data.parameters || ''}" required class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">架构</label><input type="text" name="architecture" value="${data.architecture || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">上下文长度</label><input type="number" name="context_length" value="${data.context_length || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">类型</label><select name="is_open_source" class="w-full px-3 py-2 border rounded-lg"><option value="false" ${!data.is_open_source ? 'selected' : ''}>商业</option><option value="true" ${data.is_open_source ? 'selected' : ''}>开源</option></select></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">MMLU分数</label><input type="number" name="mmlu" value="${data.mmlu || ''}" step="0.1" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">HumanEval分数</label><input type="number" name="humaneval" value="${data.humaneval || ''}" step="0.1" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">输入价格($/1K)</label><input type="number" name="input_price" value="${data.input_price || ''}" step="0.001" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">输出价格($/1K)</label><input type="number" name="output_price" value="${data.output_price || ''}" step="0.001" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">许可证</label><input type="text" name="license" value="${data.license || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">发布日期</label><input type="date" name="publish_date" value="${data.publish_date || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">热度</label><input type="number" name="views" value="${data.views || 0}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
${formFields}
|
||||
</div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">描述</label><textarea name="description" rows="3" class="w-full px-3 py-2 border rounded-lg">${data.description || ''}</textarea></div>
|
||||
${getImageUploadComponent(currentImages, 'model')}
|
||||
</form>`;
|
||||
}
|
||||
@@ -1832,31 +1924,13 @@
|
||||
function getGpuForm(data = {}) {
|
||||
currentImages = data.images || [];
|
||||
const subcategorySelect = getSubcategorySelect('gpus', data.subcategory_id);
|
||||
const formFields = generateFormFields('gpus', data, data.subcategory_id);
|
||||
|
||||
return `<form id="itemForm" class="space-y-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
${subcategorySelect}
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">名称 *</label><input type="text" name="name" value="${data.name || ''}" required class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">厂商 *</label><input type="text" name="manufacturer" value="${data.manufacturer || ''}" required class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">架构</label><input type="text" name="architecture" value="${data.architecture || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">显存(GB) *</label><input type="number" name="memory_gb" value="${data.memory_gb || ''}" required class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">CUDA核心</label><input type="number" name="cuda_cores" value="${data.cuda_cores || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">Tensor核心</label><input type="number" name="tensor_cores" value="${data.tensor_cores || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">显存带宽(GB/s)</label><input type="number" name="memory_bandwidth_gbs" value="${data.memory_bandwidth_gbs || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">FP16性能(TF)</label><input type="number" name="fp16_tflops" value="${data.fp16_tflops || ''}" step="0.1" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">币种</label><select name="currency" class="w-full px-3 py-2 border rounded-lg">
|
||||
<option value="USD" ${data.currency === 'USD' || !data.currency ? 'selected' : ''}>美元 (USD)</option>
|
||||
<option value="CNY" ${data.currency === 'CNY' ? 'selected' : ''}>人民币 (CNY)</option>
|
||||
<option value="EUR" ${data.currency === 'EUR' ? 'selected' : ''}>欧元 (EUR)</option>
|
||||
</select></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">价格</label><input type="number" name="price_usd" value="${data.price_usd || ''}" step="0.01" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">最低价</label><input type="number" name="min_price" value="${data.min_price || ''}" step="0.01" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">最高价</label><input type="number" name="max_price" value="${data.max_price || ''}" step="0.01" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">价格单位</label><input type="text" name="price_unit" value="${data.price_unit || ''}" placeholder="如: 万" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">发布日期</label><input type="date" name="publish_date" value="${data.publish_date || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">热度</label><input type="number" name="views" value="${data.views || 0}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
${formFields}
|
||||
</div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">描述</label><textarea name="description" rows="3" class="w-full px-3 py-2 border rounded-lg">${data.description || ''}</textarea></div>
|
||||
${getImageUploadComponent(currentImages, 'gpu')}
|
||||
</form>`;
|
||||
}
|
||||
@@ -1864,32 +1938,13 @@
|
||||
function getCpuForm(data = {}) {
|
||||
currentImages = data.images || [];
|
||||
const subcategorySelect = getSubcategorySelect('cpus', data.subcategory_id);
|
||||
const formFields = generateFormFields('cpus', data, data.subcategory_id);
|
||||
|
||||
return `<form id="itemForm" class="space-y-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
${subcategorySelect}
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">名称 *</label><input type="text" name="name" value="${data.name || ''}" required class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">厂商 *</label><input type="text" name="manufacturer" value="${data.manufacturer || ''}" required class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">架构</label><input type="text" name="architecture" value="${data.architecture || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">核心数 *</label><input type="number" name="cores" value="${data.cores || ''}" required class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">线程数 *</label><input type="number" name="threads" value="${data.threads || ''}" required class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">基础频率(GHz)</label><input type="number" name="base_clock_ghz" value="${data.base_clock_ghz || ''}" step="0.1" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">加速频率(GHz)</label><input type="number" name="boost_clock_ghz" value="${data.boost_clock_ghz || ''}" step="0.1" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">L3缓存(MB)</label><input type="number" name="l3_cache_mb" value="${data.l3_cache_mb || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">TDP功耗(W)</label><input type="number" name="tdp_watts" value="${data.tdp_watts || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">币种</label><select name="currency" class="w-full px-3 py-2 border rounded-lg">
|
||||
<option value="USD" ${data.currency === 'USD' || !data.currency ? 'selected' : ''}>美元 (USD)</option>
|
||||
<option value="CNY" ${data.currency === 'CNY' ? 'selected' : ''}>人民币 (CNY)</option>
|
||||
<option value="EUR" ${data.currency === 'EUR' ? 'selected' : ''}>欧元 (EUR)</option>
|
||||
</select></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">价格</label><input type="number" name="price_usd" value="${data.price_usd || ''}" step="0.01" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">最低价</label><input type="number" name="min_price" value="${data.min_price || ''}" step="0.01" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">最高价</label><input type="number" name="max_price" value="${data.max_price || ''}" step="0.01" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">价格单位</label><input type="text" name="price_unit" value="${data.price_unit || ''}" placeholder="如: 万" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">发布日期</label><input type="date" name="publish_date" value="${data.publish_date || ''}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">热度</label><input type="number" name="views" value="${data.views || 0}" class="w-full px-3 py-2 border rounded-lg"></div>
|
||||
${formFields}
|
||||
</div>
|
||||
<div><label class="text-sm text-gray-600 mb-1 block">描述</label><textarea name="description" rows="3" class="w-full px-3 py-2 border rounded-lg">${data.description || ''}</textarea></div>
|
||||
${getImageUploadComponent(currentImages, 'cpu')}
|
||||
</form>`;
|
||||
}
|
||||
@@ -2137,7 +2192,6 @@
|
||||
text: text,
|
||||
images: smartAddImages,
|
||||
subcategory_id: subcategoryId
|
||||
images: smartAddImages
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user