--- name: new-page description: 根据设计截图和菜单入口名称,在 AirLogistics 项目中创建新的业务页面。自动分析截图判断页面类型(6种典型类型之一),规划所需文件,然后完整实现(Kotlin + XML + 路由注册 + 菜单接入)。当用户说"创建页面"、"新建页面"、"实现这个页面"、"做这个页面"或提供设计截图要求开发时触发。 --- # 新建业务页面 根据设计截图和菜单入口名称,在 AirLogistics 项目中完整创建一个新的业务页面。 ## 前置要求 用户需要提供: 1. **设计截图**(必须)— 页面 UI 设计图 2. **菜单入口名称**(必须)— 页面在首页菜单中显示的名称 3. **所属模块**(可选)— 如 module_gjj(国际进港)、module_gjc(国际出港)等,可从截图标题推断 ## 执行步骤 ### 第 1 步:分析截图,判定页面类型 仔细阅读截图,提取以下信息: 1. **页面标题**(标题栏文字) 2. **搜索区字段**(每个搜索控件的 hint 文本、类型:日期/输入/下拉/扫码) 3. **列表项字段**(每个数据字段的标签名和显示格式) 4. **底部操作栏**(统计项 + 操作按钮) 5. **特殊交互**(全选、展开/收起、右箭头、子列表等) 然后对照 CLAUDE.md 中的 **6 种典型页面类型**判定: | 类型 | 关键特征 | 判定依据 | |------|----------|----------| | **类型 1:列表查询页** | 搜索 + 分页列表 + 底部统计 | 无全选、无勾选,纯查看 | | **类型 2:多选列表 + 批量操作页** | 类型 1 + 全选按钮 + 飞机图标选中态 + 操作按钮 | 有全选、有批量操作按钮(如"清除提货") | | **类型 3:嵌套多选列表页** | 类型 2 + 子列表(展开/收起)+ 主子联动全选 | 有展开按钮、列表项内含子 RecyclerView | | **类型 4:Tab 详情页** | 自定义 Tab 栏 + ViewPager2 + 多 Fragment | 有 Tab 切换、无列表搜索 | | **类型 5:编辑表单页** | ScrollView + PadDataLayoutNew 表单 + 保存/取消 | 有可编辑字段、有保存按钮 | | **类型 6:添加表单页** | 类型 5 + 输入回调 + 实时计算 | 有 setRefreshCallBack 联动 | **向用户确认**判定结果,格式: ``` 📋 页面分析结果: 页面标题:XXX 页面类型:类型 N — XXXX 所属模块:module_xxx 搜索条件: 1. XXX(DATE) 2. XXX(SPINNER) 3. XXX(INPUT + 扫码) 列表字段(第一行):XXX | XXX | XXX 列表字段(第二行):XXX | XXX | XXX 底部操作:全选 + 统计(合计/总件数/总重量) + [操作按钮名称] 是否正确?确认后开始实现。 ``` ### 第 2 步:查找参考模板并提取 UI 设计规范 根据判定的页面类型,在项目中找到**同类型的最新参考实现**,并严格提取 UI 设计规范。 **查找策略**(优先级从高到低): 1. 优先查找**最近提交的同类型页面**(最新的页面代表最新的 UI 规范) 2. 其次在**同模块**内查找同类型页面 3. 最后在 **module_gjc**(国际出港)查找 **最新典型参考页面**(2024年后新增,代表当前 UI 规范): | 页面类型 | 参考页面 | 布局文件 | |----------|----------|----------| | 列表查询页 | 航班查询列表 | `activity_flight_query_list.xml` / `item_flight_query_list.xml` | | 列表查询页 | 日志查询页 | `activity_log_query.xml` / `item_log_query.xml` | | 详情页 | 航班查询详情 | `activity_flight_query_details.xml` | | 详情页 | 日志详情 | `activity_log_detail.xml` | **必须读取的参考文件**: - 上述最新典型参考页面中**与当前页面类型匹配的布局 XML**(Activity 布局 + Item 布局) - 对应的 Activity、ViewModel、ViewHolder Kotlin 代码 - Dialog(如有批量操作弹窗) **UI 设计规范提取(必做)**: 读取参考布局后,必须逐一确认以下规范项,并在开发计划中明确列出: | 规范项 | 必须确认的内容 | |--------|---------------| | 页面背景色 | 根容器 `background` 属性(新规范:`@color/color_f2`) | | 搜索区样式 | 使用的搜索控件类型、间距、布局方式 | | 搜索按钮样式 | 图标资源、尺寸、style(新规范:`@drawable/img_search`,36dp) | | 底部栏背景色 | 背景色 + 文字颜色(新规范有两种变体) | | 底部栏文字样式 | 字号、粗细、颜色 | | 列表项背景 | 背景、间距、padding | | 详情页卡片样式 | 背景、圆角、padding、行间距 | | 表单控件 | 使用 PadDataLayoutNew(非旧版 PadDataLayout) | **同时检查**: - 该页面需要的**下拉列表数据源 API** 是否已存在(代理人、特码等) - 该页面需要的 **Bean 类**是否已存在,或需要新建 - `ARouterConstants` 中是否已有对应路由常量 - `Constant.AuthName` 中是否已有对应权限名 ### 第 3 步:制定文件清单 列出所有需要**新建**和**修改**的文件。 **新建文件清单**(根据页面类型调整): | 类别 | 文件 | 路径 | |------|------|------| | Bean | `XxxBean.kt`(如需) | `module_base/.../bean/` | | Activity | `XxxActivity.kt` | `module_xxx/.../activity/` | | ViewModel | `XxxViewModel.kt` | `module_xxx/.../viewModel/` | | ViewHolder | `XxxViewHolder.kt` | `module_xxx/.../holder/` | | Dialog | `XxxDialogModel.kt`(如需) | `module_xxx/.../dialog/` | | Activity 布局 | `activity_xxx.xml` | `module_xxx/.../res/layout/` | | Item 布局 | `item_xxx.xml` | `module_xxx/.../res/layout/` | | Dialog 布局 | `dialog_xxx.xml`(如需) | `module_xxx/.../res/layout/` | **修改文件清单**(固定): | 文件 | 修改内容 | |------|----------| | `Api.kt` | 添加 API 接口方法 + import | | `ARouterConstants.kt` | 添加路由常量(如不存在) | | `Constant.kt` | 添加 AuthName 常量(如不存在) | | `AndroidManifest.xml` | 注册 Activity | | `HomeFragment.kt` | 添加菜单项 + 点击路由处理 | | 旧版 Activity(如有) | 注释掉 `@Route` 注解避免冲突 | ### 第 4 步:创建 Bean(如需) 如果截图中的列表字段与现有 Bean 不匹配,创建新的 Bean 类。 **规则**: - 放在 `module_base/.../bean/` 目录下 - 如果是类型 2/3(多选),必须包含 `ObservableBoolean` 选中状态: ```kotlin val checked: ObservableBoolean = ObservableBoolean(false) var isSelected: Boolean get() = checked.get() set(value) = checked.set(value) ``` - 字段类型映射:数字用 `Int/Long/Double`,文本用 `String = ""`,时间用 `String = ""` - 在 `Api.kt` 的 import 区按字母顺序添加 import ### 第 5 步:添加 API 接口 在 `Api.kt` 中添加 API 方法。 **标准 API 组合**(根据页面需要选取): - `getXxxList(@Body)` — 分页查询,返回 `PageInfo` - `getXxxTotal(@Body)` — 分页合计,返回 `BaseResultBean` - 批量操作 API — 返回 `BaseResultBean` - 下拉列表 API(代理人、特码等)— 如不存在则添加 **API 路径命名**:先使用 `ModuleName/methodName` 格式占位(如 `IntImpPickUpRecord/pageQuery`),后续由第 13 步替换为真实接口路径 ### 第 6 步:添加路由和权限常量 1. 在 `ARouterConstants.kt` 添加路由(如不存在): ```kotlin const val ACTIVITY_URL_XXX = "/module/XxxActivity" ``` 2. 在 `Constant.kt` 的 `AuthName` 中添加权限名(如不存在): ```kotlin const val XxxPage = "AppXxxPage" ``` ### 第 7 步:创建 ViewHolder 根据 item 布局创建 ViewHolder。 **类型 1**:基础绑定 **类型 2**:增加图标点击切换 `checked` 状态 **类型 3**:增加子列表 `setCommonAdapter` + 展开按钮 + 父子联动 ### 第 8 步:创建 ViewModel **必须包含的元素**(根据截图): - 搜索条件 `MutableLiveData`(与搜索区对应) - 下拉列表数据源 `MutableLiveData>` - 统计字段 `MutableLiveData` - 适配器配置:`itemViewHolder` + `itemLayoutId` - `searchClick()` 方法 - `getData()` override:调用列表 API + 统计 API **类型 2 额外**:`isAllChecked` + `checkAllClick()` + 批量操作方法 **类型 3 额外**:`isAllExpanded` + `toggleAllExpand()` + 联动全选逻辑 **下拉列表初始化**: - 代理人:`DictUtils.getAgentList()` / `NetApply.api.getIntImpAgentList()` / `getIntExpAgentList()` - 特码:`DictUtils.getSpecialCodeList(flag, ieFlag, parentcode)` - 其他字典:`DictUtils` 或自定义 API ### 第 9 步:创建布局文件 **⚠️ 重要:所有布局必须严格遵循最新 UI 设计规范,参照第 2 步中提取的规范项。** --- #### 新版 UI 设计规范(强制执行) **1. 页面背景色**: ```xml ``` **2. 搜索区规范**: ```xml ``` **3. 底部统计栏规范**(两种变体,根据截图选择): **变体 A — 深蓝色底部栏**(多数列表页使用): ```xml ``` **变体 B — 白色底部栏**: ```xml ``` **4. 详情页/表单页规范**: - 必须使用 **PadDataLayoutNew**(非旧版 PadDataLayout) - 卡片背景:`@drawable/bg_white_radius_8`,padding `15dp` - 行间距:`marginTop="8dp"` - 三列标准布局,每列 `layout_weight="1"` ```xml ``` --- #### Activity 布局完整结构 ```xml PadSearchLayout × N + 搜索按钮(img_search, 36dp) ``` #### Item 布局(从截图精确还原每一行每一列) - 逐行对照截图中的字段顺序和标签文本 - 使用 `completeSpace` 对齐 Key 文本 - 运单号等关键字段用 `@color/colorPrimary` - 类型 2/3 左侧有飞机图标:`loadImage="@{bean.checked.get() ? @drawable/img_plane_s : @drawable/img_plane}"` - 列表项背景统一使用 `@drawable/bg_item` - 间距统一:`marginHorizontal="15dp"`, `marginVertical="5dp"`, `padding="10dp"` **关键原则:务必尽可能还原截图上的页面设计,不推测不假想。** ### 第 10 步:创建 Activity **固定结构**: ```kotlin @Route(path = ARouterConstants.ACTIVITY_URL_XXX) class XxxActivity : BaseBindingActivity() { override fun layoutId() = R.layout.activity_xxx override fun viewModelClass() = XxxViewModel::class.java override fun initOnCreate(savedInstanceState: Bundle?) { setBackArrow("页面标题") // 与截图标题一致 binding.viewModel = viewModel binding.activity = this // 类型 3 或有 Dialog 时 // 类型 2/3:观察全选状态 viewModel.isAllChecked.observe(this) { binding.checkIcon.alpha = if (it) 1.0f else 0.5f } // 绑定分页 viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this) // 监听刷新事件 FlowBus.with(ConstantEvent.EVENT_REFRESH).observe(this) { viewModel.refresh() } // 初始化下拉列表(如有) viewModel.initAgentList() viewModel.initSpecialCodeList() viewModel.refresh() } } ``` ### 第 11 步:注册 Activity + 菜单入口 1. **AndroidManifest.xml**:在其他 gjj Activity 注册附近添加: ```xml ``` 2. **HomeFragment.kt**: - 在对应模块的菜单列表区添加 `RightMenu` 项(图标 + 标题) - 在 onClick 处理区添加路由跳转 3. **旧版 Activity**(如有):注释掉 `@Route` 注解 ### 第 12 步:编译验证 ```bash ./gradlew assembleDebug ``` 编译必须通过(0 errors)。如有错误,立即修复后重新编译。 ### 第 13 步:查找并对接 API 接口 页面创建并编译通过后,通过"空港集团 - API 文档"Apifox MCP 工具查找真实接口,替换第 5 步中的占位路径。 **A. 基础接口查找(每次必查):** 1. 根据页面所属业务路径(如"国际进港 → 原始舱单"),在 Apifox MCP 中按模块目录搜索 2. 查找以下基础接口: - **列表接口**(分页查询,如 `pageQuery`、`list`) - **合计接口**(统计,如 `total`、`count`、`statistics`) - **修改/保存接口**(如 `update`、`save`、`edit`) - **删除接口**(如 `delete`、`remove`) **B. 智能接口匹配(根据页面分析):** 3. 根据**页面类型特性**查找对应接口: - 类型 2(多选批量操作)→ 查找批量操作接口(如批量删除、批量确认等) - 类型 3(嵌套列表)→ 查找子列表相关接口 - 类型 5/6(表单页)→ 查找详情查询接口、下拉选项字典接口 - 类型 4(Tab 详情)→ 查找各 Tab 对应的数据接口 4. 根据**页面中的按钮和文案**,逐一匹配对应接口: - 例如页面有"审核"按钮 → 查找审核接口 - 例如页面有"导出"按钮 → 查找导出接口 - 例如页面有"打印"按钮 → 查找打印相关接口 - 例如底部栏有"清除提货"按钮 → 查找清除提货接口 - 例如搜索区有下拉框(代理人、状态等)→ 查找对应的字典/下拉数据接口 5. 根据**截图中可见的交互元素**,推断可能需要的接口: - 列表项有右箭头 → 可能需要详情接口 - 列表项有编辑图标 → 可能需要编辑/更新接口 - 有扫码图标 → 可能需要扫码查询接口 **C. 对接与校准:** 6. 找到接口后,更新 `Api.kt` 中的占位路径为真实路径 7. 根据接口的请求参数和返回字段结构,校准 Bean 类的字段名和类型 8. 遵循 memory 中的 API 搜索原则:不跨模块混用接口,遇到不确定的接口询问用户确认 ### 第 14 步:重新编译验证 对接真实 API 后重新编译,确保无错误: ```bash ./gradlew assembleDebug ``` 编译必须通过(0 errors)。如有错误,立即修复后重新编译。 ## 注意事项 ### UI 设计规范(强制) - **必须使用最新 UI 规范**:不管是新增页面、覆盖旧页面还是修改旧页面,都必须完全采用最新典型参考页面的 UI 设计规范 - **页面背景色**:根容器必须使用 `@color/color_f2`(`#F2F2F2`),禁止使用旧的白色或其他背景 - **搜索按钮**:使用 `@drawable/img_search` 图标(36x36dp + padding 2dp),不使用旧的 `iv_search_action` style - **底部栏**:高度 50dp,文字 18sp bold,根据截图选择深蓝色(`@color/color_bottom_layout` + 白字)或白色(`@color/white` + `@color/bottom_tool_tips_text_color`) - **详情页/表单页**:必须使用 **PadDataLayoutNew**(非旧版 PadDataLayout),卡片用 `bg_white_radius_8` - **严格匹配典型页面**:在写开发计划前,必须先读取最新典型参考页面(如航班查询列表、日志查询页等),总结并列出 UI 设计规范要点 ### 通用规则 - **资源引用必须存在**:使用 drawable/color/mipmap 前确认资源存在,不存在则换用已有资源 - **import 路径查阅 CLAUDE.md**:基类和扩展函数的正确 import 路径参见开发指南的 Import 速查表 - **不创建不需要的文件**:如果截图中没有 Dialog 弹窗,不要创建 Dialog 文件 - **Bean 复用优先**:如果现有 Bean 的字段足以覆盖截图需求,直接复用 - **API 接口对接**:页面创建完成后,通过空港集团 API 文档 MCP 查找真实接口并替换占位路径。遵循 API 搜索原则,按业务模块目录查找,不跨模块混用 - **DataBinding 规则**:遵循 CLAUDE.md 中的 DataBinding 关键规则(双向绑定、字符串拼接、View 导入等)