Files
Navius/docs/submit-site-form.md
T
CNWei 1c98340fc5 feat: 实现导航页基础功能
- 添加导航条目和分类数据模型
- 实现导航卡片网格展示
- 支持点击卡片打开链接
- 添加主题样式(渐变色、卡片阴影)
- 区分系统默认和自定义条目
- 添加分类统计信息"
2026-09-19 21:53:15 +08:00

6.5 KiB
Raw Blame History

提交网站表单设计

已按本文实现(含「错误色 / 可点建议 / 提交后刷新」三条确认)。代码在 frontend/lib/features/home/presentation/widgets/submit_site_dialog.dart。 实现与本文有几处按实际取舍收敛,差异记在第 8 节。

1. 目标与约束

  • 入口:侧栏底部的「提交网站」按钮(现在是个空按钮)。原型里没有这个表单, 所以这里定完之后再动手写。
  • 只管用户提交这一条路(POST /api/sites)。接口推送是给第三方用的, 走令牌,不在页面上暴露。
  • 表单里没有「选择分组」这个动作:后端不接受 categoryId,只接受分组名, 而且提交的内容永远不会落进内置分组。表单要顺着这个规则设计, 不能让用户以为可以把站点塞进「常用推荐」「素材资源」这些内置分组。
  • 视觉只能用现有设计令牌(index3.html 那套),不引入新的配色和圆角体系。

2. 交互流程

点侧栏「提交网站」
   │
   ▼
弹出对话框(遮罩 + 白底卡片,居中)
   │  填写(改动某个字段时清掉它上一次的错误)
   ▼
点「提交」
   ├─ 有字段不合格 → 定位到第一个不合格的字段并提示,不发请求
   └─ 都合格 → 按钮进入「提交中…」,禁用整张表单
         ├─ 201 → 关掉对话框 + 顶部提示「已提交,感谢」+ 重新拉一次 /api/nav
         └─ 其它 → 留在对话框里,顶部显示后端返回的原因,可以改了再提交

关闭方式:右上角 ×、点遮罩、「取消」按钮、Esc 键。提交中不允许关闭(避免请求还没回来 就把界面收了)。

3. 字段定义

字段与后端 POST /api/sites 的入参一一对应,校验规则也和后端保持一致—— 前端先拦一遍是为了即时反馈,后端那一遍才是权威。

字段 控件 必填 限制 不合格时的提示 后端字段
网站名称 单行输入 是 ≤ 60 字 请填写网站名称 / 网站名称最多 60 个字 title
网站地址 单行输入 是 可解析的 http(s),不能是本机或内网地址 请填写网站地址 / 地址要以 http:// 或 https:// 开头 / 不能填本机或内网地址 url
一句话描述 多行输入(3 行) 否 ≤ 120 字 描述最多 120 个字 description
分组 单行输入 是 ≤ 30 字 请填写分组名称 group
子分组 单行输入 否 ≤ 30 字 子分组名称最多 30 个字 subGroup
你的称呼或邮箱 单行输入 否 ≤ 120 字 最多 120 个字 submittedBy

3.1 分组与子分组怎么填

  • 两个都是填名字,不是选内置分类。placeholder 分别写: 「例如:AI 工具(会创建你自己的分组)」「例如:模型社区(可不填)」。
  • 分组下面给一行浅色说明:「提交的网站会放在你自己的分组里,不会进内置分类。」 这句话必须留着,否则用户会以为能提交到「常用推荐」。
  • 名字和已有的用户分组重名时会复用那个分组,不会重复创建—— 所以两个输入框下面给一排可点的建议:分组建议列出现有用户分组, 子分组建议列出所选分组下已有的用户子分组(数据来自 /api/nav 里 editable == true 的分组)。点一下即填入,不想用就直接手打新名字。
  • 子分组留空表示直接放在一级分组下。

4. 布局与视觉

沿用现有令牌,不新增尺寸:

部分 取值
遮罩 rgba(17, 24, 39, .45)
卡片 白底 + 1px #e2e8f0 描边 + 12px 圆角 + cardShadowHover
卡片宽度 480px,两侧留 24px(窄屏时自适应)
卡片内边距 24px
标题 「提交网站」,AppTextStyles.sectionTitle,右侧一个 × 关闭按钮
字段标签 13px,--text-sub,与输入框间隔 6px
输入框 复用搜索框那套:44px 高、1px 描边、12px 圆角、聚焦时主色边框 + 3px 光晕
多行框 同上,高度 88px(3 行),垂直内边距 10px
字段间距 16px
底部按钮 右侧并排:取消(描边次级)+ 提交(主色实底,8px 圆角——和侧栏「提交网站」一致)
字段错误文案 12px,紧随输入框下方,间隔 4px

5. 状态

状态 表现
初始 所有输入为空,「提交」可点
校验失败 不合格的字段旁显示提示,输入框边框变错误色;不发请求
提交中 「提交」文案变「提交中…」并禁用,整张表单只读,× / 遮罩 / Esc 都不响应
提交失败 卡片顶部一条错误条,显示后端 {"error": "…"} 里的原话;表单恢复可编辑
提交成功 关闭卡片,弹一条「已提交,感谢」提示,并静默重新拉一次 /api/nav(不闪加载页)

6. 三点确认结果

  1. 错误色:已新增 AppColors.danger = #E5484D 与它 8% 的叠加色 dangerFaint,只用在错误提示和错误边框上。
  2. 分组建议:保留,做成可点胶囊;只列 editable == true 的分组, 内置分组不出现(点了也进不去)。
  3. 提交成功后刷新:保留,用静默刷新——页面继续显示旧内容, 拉到新数据再整体替换,不会闪一下「正在加载」。

7. 实现落点

文件 职责
features/home/presentation/widgets/submit_site_dialog.dart 对话框本体:字段、校验提示、提交按钮
features/home/data/home_repository.dart 契约加一个 submitSite(...)
features/home/data/http_home_repository.dart 实现:POST /api/sites,把后端的中文错误原样抛给界面
features/home/data/mock_home_repository.dart 测试用:记录调用,不真的发请求
features/home/presentation/pages/home_page.dart 「提交网站」按钮改为打开对话框;成功后静默重新取数并提示

8. 实现与本文的差异

本文原写法 实际实现 原因
失焦时校验 提交时统一校验,改动字段时清掉该字段的错误 少一套焦点状态,行为对用户更可预期
底部按钮是「主色胶囊」 主色实底 + 8px 圆角 index3.html 的调色板里没有胶囊圆角,侧栏「提交网站」也是 8px
成功提示在页面顶部 底部提示条(SnackBar) 复用主题里已经配好的提示条,不新增一套浮层