(null)
+
+access.initializeAfterLogin()
+
+async function replaceAndFocus(path: string) {
+ if (route.fullPath !== path) await router.replace(path)
+ await nextTick()
+ pageHeading.value?.focus()
+}
+
+async function requestRoleSwitch(roleId: string) {
+ if (roleId === access.currentRole?.id) return
+ const candidate = access.previewRole(roleId)
+ const target = resolvePreviewTarget({
+ currentPath: route.path,
+ currentPermission: route.meta.permission,
+ candidateCodes: candidate.codes,
+ firstPath: candidate.firstPath,
+ })
+ const blockers = unsaved.findBlocking(candidate.codes, Boolean(target && target !== route.fullPath))
+
+ if (blockers.length) {
+ try {
+ await ElMessageBox.confirm(
+ `切换后将离开或无法保存“${blockers.map((item) => item.label).join('、')}”,是否继续?`,
+ '切换权限预览角色',
+ { confirmButtonText: '继续切换', cancelButtonText: '保留当前编辑', type: 'warning' },
+ )
+ } catch {
+ return
+ }
+ }
+
+ correctingRoute.value = true
+ try {
+ access.commitRole(roleId)
+ if (target) await replaceAndFocus(target)
+ } finally {
+ correctingRoute.value = false
+ }
+ const roleName = access.currentRole?.name || '无可用角色'
+ announcement.value = target
+ ? `已切换至${roleName},当前页面为${String(route.meta.title || '无访问权限')}`
+ : `已切换至${roleName}`
+ ElMessage.success(`已切换至“${roleName}”,当前仅为静态权限预览`)
+}
+
+watch(
+ () => `${access.currentRole?.id || ''}:${access.permissionSignature}`,
+ async () => {
+ if (correctingRoute.value) return
+ const target = resolvePreviewTarget({
+ currentPath: route.path,
+ currentPermission: route.meta.permission,
+ candidateCodes: access.permissionCodes,
+ firstPath: access.firstAccessiblePath,
+ })
+ if (!target || target === route.fullPath) return
+ correctingRoute.value = true
+ try {
+ await replaceAndFocus(target)
+ } finally {
+ correctingRoute.value = false
+ }
+ announcement.value = `权限已更新,当前页面为${String(route.meta.title || '无访问权限')}`
+ },
+)
+```
+
+现有 `handleLogout` 的确认分支改为:
+
+```ts
+access.reset()
+unsaved.clear()
+auth.logout()
+await router.replace('/login')
+```
+
+模板中完成四项替换:
+
+1. 侧栏传入 `:items="access.filteredNavigation"`。
+2. `h1` 增加 `ref="pageHeading" tabindex="-1"`。
+3. 用户信息替换为以下明确结构:
+
+```vue
+
+ 登录身份:{{ auth.user?.name }}
+ {{ auth.user?.account }}
+
+```
+4. 用户信息前插入:
+
+```vue
+
+{{ announcement }}
+```
+
+- [ ] **Step 6:登录成功初始化权限预览**
+
+`LoginView.vue` 导入并创建 `const access = useAccessPreviewStore()`,在 `await auth.login(...)` 后、跳转前调用:
+
+```ts
+access.initializeAfterLogin()
+```
+
+路由守卫中的相同调用是刷新登录态的幂等兜底,不会在未登录时持久化角色。
+
+- [ ] **Step 7:运行组件和布局测试**
+
+Run:
+
+```bash
+cd apps/admin-web
+pnpm test -- src/components/RolePreviewSwitcher.test.ts src/layouts/AppLayout.test.ts
+```
+
+Expected: 两个测试文件全部 PASS。
+
+- [ ] **Step 8:记录验证检查点**
+
+确认角色取消切换时没有先写 Store;确认 403 切换到有菜单角色后恢复;确认退出先清预览再清认证。
+
+## Task 6:客户与头程订单操作权限和脏状态
+
+**Files:**
+
+- Modify: `apps/admin-web/src/views/CustomersView.vue`
+- Modify: `apps/admin-web/src/views/FirstLegOrdersView.vue`
+- Create: `apps/admin-web/src/views/AccessControlledActions.test.ts`
+
+- [ ] **Step 1:先写业务操作权限失败测试**
+
+在 `AccessControlledActions.test.ts` 使用真实 Element Plus 组件挂载页面;先加入完整测试基线:
+
+```ts
+import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
+import { createPinia, setActivePinia, type Pinia } from 'pinia'
+import { enableAutoUnmount, mount } from '@vue/test-utils'
+import { nextTick } from 'vue'
+import ElementPlus from 'element-plus'
+import CustomersView from './CustomersView.vue'
+import FirstLegOrdersView from './FirstLegOrdersView.vue'
+import InternalUsersView from './InternalUsersView.vue'
+import RolesView from './RolesView.vue'
+import PermissionsView from './PermissionsView.vue'
+import { useAccessPreviewStore } from '@/stores/accessPreview'
+
+class ResizeObserverStub {
+ observe() {}
+ unobserve() {}
+ disconnect() {}
+}
+
+let pinia: Pinia
+
+beforeAll(() => vi.stubGlobal('ResizeObserver', ResizeObserverStub))
+afterAll(() => vi.unstubAllGlobals())
+enableAutoUnmount(afterEach)
+beforeEach(() => {
+ localStorage.clear()
+ pinia = createPinia()
+ setActivePinia(pinia)
+})
+
+const mountOptions = () => ({
+ attachTo: document.body,
+ global: { plugins: [pinia, ElementPlus] },
+})
+```
+
+在该基线上加入:
+
+```ts
+describe('access-controlled business actions', () => {
+ it('shows audit but hides customer creation for the operations manager', async () => {
+ const access = useAccessPreviewStore()
+ access.initializeAfterLogin()
+ access.commitRole('R002')
+ const customers = mount(CustomersView, mountOptions())
+ await nextTick()
+
+ expect(customers.text()).not.toContain('新增客户')
+ expect(customers.text()).toContain('审核')
+ })
+
+ it('hides order creation and status actions for finance', async () => {
+ const access = useAccessPreviewStore()
+ access.initializeAfterLogin()
+ access.commitRole('R004')
+ const orders = mount(FirstLegOrdersView, mountOptions())
+ await nextTick()
+
+ expect(orders.text()).not.toContain('创建订单')
+ expect(orders.text()).not.toContain('批量更新')
+ expect(orders.text()).not.toContain('处理')
+ })
+
+ it('shows customer creation without granting order status updates to sales', async () => {
+ const access = useAccessPreviewStore()
+ access.initializeAfterLogin()
+ access.commitRole('R005')
+ const customers = mount(CustomersView, mountOptions())
+ const orders = mount(FirstLegOrdersView, mountOptions())
+ await nextTick()
+
+ expect(customers.text()).toContain('新增客户')
+ expect(orders.text()).not.toContain('更新状态')
+ })
+})
+```
+
+- [ ] **Step 2:运行测试确认按钮尚未受控**
+
+Run:
+
+```bash
+cd apps/admin-web
+pnpm test -- src/views/AccessControlledActions.test.ts
+```
+
+Expected: FAIL,当前角色无权限时仍能看到创建或状态按钮。
+
+- [ ] **Step 3:接入客户权限和表单登记**
+
+`CustomersView.vue` 增加:
+
+```ts
+const access = useAccessPreviewStore()
+const customerEditorLabel = computed(() => form.id ? '编辑客户' : '新增客户')
+const customerEditorPermission = computed(() => form.id ? null : 'customer:create')
+const { captureBaseline: captureCustomerBaseline } = useUnsavedWorkRegistration({
+ key: 'customer-editor',
+ label: customerEditorLabel,
+ isOpen: editorOpen,
+ model: form,
+ requiredPermission: customerEditorPermission,
+})
+```
+
+`openCreate` 和 `openEdit` 在 `Object.assign` 后、打开抽屉前调用 `captureCustomerBaseline()`。模板加入以下准确条件:
+
+同时监听创建权限;用户确认角色切换后如果同一路由仍可访问但创建权限消失,关闭新增抽屉并丢弃未保存的新客户:
+
+```ts
+watch(() => access.can('customer:create'), (allowed) => {
+ if (!allowed && editorOpen.value && !form.id) editorOpen.value = false
+})
+```
+
+```vue
+
+ 新增客户
+
+
+
+ 审核
+
+
+
+ 保存客户
+
+```
+
+详情抽屉中的“通过审核”增加 `access.can('customer:audit')`;客户编辑与启停保持规格约定,不增加新权限编码。
+
+- [ ] **Step 4:接入订单权限和表单登记**
+
+`FirstLegOrdersView.vue` 增加:
+
+```ts
+const access = useAccessPreviewStore()
+const orderEditorLabel = computed(() => form.id ? '编辑头程订单' : '创建头程订单')
+const orderEditorPermission = computed(() => form.id ? null : 'first-leg:create')
+const { captureBaseline: captureOrderBaseline } = useUnsavedWorkRegistration({
+ key: 'first-leg-order-editor',
+ label: orderEditorLabel,
+ isOpen: editorOpen,
+ model: form,
+ requiredPermission: orderEditorPermission,
+})
+```
+
+`openCreate` 和 `openEdit` 捕获表单基线。模板规则固定为:
+
+同时监听创建权限并在确认切换后关闭失去保存权限的新订单抽屉:
+
+```ts
+watch(() => access.can('first-leg:create'), (allowed) => {
+ if (!allowed && editorOpen.value && !form.id) editorOpen.value = false
+})
+```
+
+```vue
+
+ 批量更新
+
+
+
+ 创建订单
+
+
+
+ 保存草稿
+
+
+
+ {{ form.id ? '保存修改' : '创建并提交' }}
+
+```
+
+表格“处理”、详情“更新状态”和状态对话框“确认更新”均增加 `access.can('first-leg:status')`;订单编辑保持无新增编码的现状。
+
+- [ ] **Step 5:运行业务操作和协调器测试**
+
+Run:
+
+```bash
+cd apps/admin-web
+pnpm test -- src/views/AccessControlledActions.test.ts src/composables/useUnsavedWorkRegistration.test.ts
+```
+
+Expected: 两个测试文件全部 PASS。
+
+- [ ] **Step 6:记录验证检查点**
+
+确认“创建”受控但既有记录编辑未被错误隐藏;确认审核和状态更新使用各自稳定编码。
+
+## Task 7:系统管理操作权限、目录语义与脏状态
+
+**Files:**
+
+- Modify: `apps/admin-web/src/views/InternalUsersView.vue`
+- Modify: `apps/admin-web/src/views/RolesView.vue`
+- Modify: `apps/admin-web/src/views/PermissionsView.vue`
+- Modify: `apps/admin-web/src/views/AccessControlledActions.test.ts`
+
+- [ ] **Step 1:扩展系统操作失败测试**
+
+在 `AccessControlledActions.test.ts` 加入:
+
+```ts
+describe('access-controlled system actions', () => {
+ it('hides system maintenance actions from a business role', async () => {
+ const access = useAccessPreviewStore()
+ access.initializeAfterLogin()
+ access.commitRole('R002')
+ const users = mount(InternalUsersView, mountOptions())
+ const roles = mount(RolesView, mountOptions())
+ const permissions = mount(PermissionsView, mountOptions())
+ await nextTick()
+
+ expect(users.text()).not.toContain('新增用户')
+ expect(users.text()).not.toContain('重置密码')
+ expect(roles.text()).not.toContain('新增角色')
+ expect(roles.text()).not.toContain('配置')
+ expect(permissions.text()).not.toContain('新增权限')
+ expect(permissions.text()).not.toContain('添加下级')
+ })
+
+ it('shows all system maintenance domains to the super administrator', async () => {
+ const access = useAccessPreviewStore()
+ access.initializeAfterLogin()
+ const users = mount(InternalUsersView, mountOptions())
+ const roles = mount(RolesView, mountOptions())
+ const permissions = mount(PermissionsView, mountOptions())
+ await nextTick()
+
+ expect(users.text()).toContain('新增用户')
+ expect(users.text()).toContain('重置密码')
+ expect(roles.text()).toContain('新增角色')
+ expect(roles.text()).toContain('配置')
+ expect(permissions.text()).toContain('新增权限')
+ expect(permissions.text()).toContain('添加下级')
+ })
+})
+```
+
+- [ ] **Step 2:运行测试确认系统按钮尚未受控**
+
+Run:
+
+```bash
+cd apps/admin-web
+pnpm test -- src/views/AccessControlledActions.test.ts
+```
+
+Expected: FAIL,R002 仍能看到系统维护操作。
+
+- [ ] **Step 3:内部用户页统一使用 `system:user:write`**
+
+增加 access Store 和以下登记:
+
+```ts
+const userEditorLabel = computed(() => form.id ? '编辑内部用户' : '新增内部用户')
+const userEditorPermission = computed(() => 'system:user:write')
+const { captureBaseline: captureUserBaseline } = useUnsavedWorkRegistration({
+ key: 'internal-user-editor',
+ label: userEditorLabel,
+ isOpen: editorOpen,
+ model: form,
+ requiredPermission: userEditorPermission,
+})
+```
+
+在新增、编辑、重置密码、启停和保存按钮上增加:
+
+```vue
+v-if="access.can('system:user:write')"
+```
+
+`openCreate` 和 `openEdit` 捕获基线。
+
+- [ ] **Step 4:角色页统一使用 `system:role:grant`**
+
+增加 access Store 和角色表单登记,requiredPermission 固定返回 `system:role:grant`。新增、配置、启停、删除和保存按钮均增加:
+
+```vue
+v-if="access.can('system:role:grant')"
+```
+
+把权限树说明替换为:
+
+```vue
+目录仅用于组织结构且独立授权;停用目录不会级联停用已启用的菜单和操作。
+```
+
+保留内置角色禁止删除和停用的既有约束。
+
+- [ ] **Step 5:权限页统一使用 `system:permission:write`**
+
+增加 access Store 和权限表单登记,requiredPermission 固定返回 `system:permission:write`。新增、编辑、添加下级、启停和保存按钮均增加:
+
+```vue
+v-if="access.can('system:permission:write')"
+```
+
+`toggleStatus` 的确认文案按目录类型分支:
+
+```ts
+const directoryNotice = row.type === '目录' && target === '停用'
+ ? '目录仅用于组织结构,停用不会级联影响已启用的下级菜单和操作。'
+ : ''
+await ElMessageBox.confirm(
+ `确认${target}“${row.name}”吗?${directoryNotice}`,
+ '权限状态',
+ { confirmButtonText: `确认${target}`, cancelButtonText: '取消', type: 'warning' },
+)
+```
+
+- [ ] **Step 6:运行系统操作、角色树和权限树测试**
+
+Run:
+
+```bash
+cd apps/admin-web
+pnpm test -- src/views/AccessControlledActions.test.ts src/views/RolesView.test.ts src/utils/permissionTree.test.ts
+```
+
+Expected: 三个测试文件全部 PASS。
+
+- [ ] **Step 7:记录验证检查点**
+
+确认目录停用不改变后代记录状态;确认页面只隐藏已映射操作,没有创造新的权限编码。
+
+## Task 8:样式、响应式、文档与完整验收
+
+**Files:**
+
+- Modify: `apps/admin-web/src/styles/index.css`
+- Modify: `apps/admin-web/README.md`
+- Verify: `apps/admin-web/src/**/*.test.ts`
+
+- [ ] **Step 1:补充顶栏、403 和辅助样式**
+
+在 `styles/index.css` 增加:
+
+```css
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
+}
+
+.role-preview-control {
+ display: flex;
+ min-width: 0;
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 2px;
+}
+
+.role-preview-trigger {
+ display: flex;
+ min-width: 0;
+ min-height: 44px;
+ max-width: 240px;
+ align-items: center;
+ gap: 6px;
+ padding: 0 10px;
+ border: 1px solid var(--cc-border);
+ border-radius: 8px;
+ background: #fff;
+ color: #344054;
+ cursor: pointer;
+}
+
+.role-preview-trigger:focus-visible {
+ outline: 2px solid var(--cc-primary);
+ outline-offset: 2px;
+}
+
+.role-preview-name {
+ min-width: 0;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.role-preview-scope {
+ max-width: 260px;
+ color: var(--cc-muted);
+ font-size: 10px;
+ text-align: right;
+}
+
+.forbidden-state {
+ display: flex;
+ min-height: 480px;
+ align-items: center;
+ justify-content: center;
+ flex-direction: column;
+ padding: 36px 20px;
+ border: 1px solid var(--cc-border);
+ border-radius: 8px;
+ background: #fff;
+ text-align: center;
+}
+
+.forbidden-icon {
+ display: grid;
+ width: 56px;
+ height: 56px;
+ place-items: center;
+ margin-bottom: 16px;
+ border-radius: 12px;
+ background: #fef3f2;
+ color: #b42318;
+}
+
+.forbidden-source {
+ max-width: 100%;
+ overflow-wrap: anywhere;
+ color: var(--cc-muted);
+ font-size: 12px;
+}
+```
+
+在现有移动端 media query 中加入:
+
+```css
+@media (max-width: 720px) {
+ .role-preview-control { margin-left: auto; }
+ .role-preview-label, .role-preview-scope { display: none; }
+ .role-preview-trigger { width: 44px; padding: 0; justify-content: center; }
+ .role-preview-name { position: absolute; width: 1px; height: 1px; overflow: hidden; }
+}
+
+@media (max-width: 360px) {
+ .app-header { gap: 6px; padding-inline: 8px; }
+ .header-user { gap: 4px; }
+ .page-heading h1 { max-width: 96px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+}
+```
+
+- [ ] **Step 2:更新 Admin README**
+
+增加“静态权限预览”小节:
+
+```markdown
+## 静态权限预览
+
+登录后可在顶栏切换启用的模拟角色,菜单、页面和已映射操作会按本地 Pinia 权限数据更新。该能力仅用于前端原型验收,不模拟数据范围,也不替代 Java 服务端鉴权。
+
+刷新会保留当前演示角色;退出登录会清除预览角色。当前实现不会调用尚未确定的 Java 业务接口。
+```
+
+- [ ] **Step 3:运行全部自动化验证**
+
+Run:
+
+```bash
+cd apps/admin-web
+pnpm test
+pnpm typecheck
+pnpm build
+```
+
+Expected:
+
+- Vitest 所有测试文件 PASS,0 failed。
+- `vue-tsc --noEmit` 退出码 0。
+- Vite build 退出码 0,产物仍只写入 `apps/admin-web/dist`。
+
+- [ ] **Step 4:启动 Admin 并完成一次成组浏览器验收**
+
+Run:
+
+```bash
+cd apps/admin-web
+pnpm dev
+```
+
+在同一批验收中检查桌面、390px、320px 和 200% 缩放:
+
+1. 登录后默认超级管理员,顶栏分别显示登录身份和权限预览。
+2. R002 隐藏新增客户但保留审核;R003 只保留工作台和订单;R004 无订单状态按钮;R005 有新增客户。
+3. 直接访问无权限地址进入 `/403?from=%2Fsystem%2Fusers`,来源只显示文本。
+4. 在 `/403` 切换到有权限角色后进入配置顺序中的第一个叶子。
+5. 修改表单后切换到会离开页面或失去保存权限的角色:取消保持内容,确认后 replace 跳转。
+6. 使用 Tab、Enter/Space、方向键和 Escape 完成角色选择;焦点可见。
+7. 自动跳转后焦点位于页面主标题,读屏可获得 polite 状态播报。
+8. 320px 下角色入口、菜单按钮和退出按钮不重叠;长角色名不撑破顶栏。
+9. DevTools Network 中没有因权限预览产生的业务 API 请求,控制台无错误。
+
+- [ ] **Step 5:执行一次 Impeccable 检测和最终确认**
+
+对最终 Admin 页面运行一次 Impeccable 检测;把有效告警与桌面/窄屏实测合并成一次修复批次,然后只做一次确认回归。不要把 Markdown 规格扫描结果当作页面验收证据。
+
+- [ ] **Step 6:记录最终检查点**
+
+记录测试数量、typecheck/build 退出码、四种视口结果、Impeccable 结果和剩余风险。明确当前仍是 Pinia 静态数据,Java API 与服务端 RBAC 不在本计划交付范围。
diff --git a/superpowers/specs/2026-07-27-admin-navigation-api-design.md b/superpowers/specs/2026-07-27-admin-navigation-api-design.md
new file mode 100644
index 0000000..91aed2e
--- /dev/null
+++ b/superpowers/specs/2026-07-27-admin-navigation-api-design.md
@@ -0,0 +1,95 @@
+# Admin 导航分组与静态交互设计
+
+## 目标
+
+将 admin 当前全部平铺的一级菜单改为可扩展的二级分组导航,同时保留现有静态页面和 Pinia 交互。Java 接口及响应结构尚未确定,本阶段不提前设计领域 API 契约。
+
+## 范围
+
+本次只处理 `apps/admin-web`:
+
+- 调整侧边栏信息架构与折叠交互。
+- 保留现有页面、路由地址和模拟数据行为。
+- 增加 admin 项目内部测试,不在仓库根目录增加 Node 配置或依赖。
+
+不处理 client、小程序、APP、PDA 或 Java 服务;不猜测最终后端 URL、响应信封、业务错误码或分页格式。
+
+## 导航结构
+
+采用两级分组,工作台保留为直接入口:
+
+```text
+工作台
+
+业务管理
+├── 客户管理
+└── 头程订单
+
+系统管理
+├── 内部用户
+├── 角色管理
+└── 菜单权限
+```
+
+侧边栏使用 Element Plus 的菜单和子菜单能力,以获得稳定的展开、折叠、当前路由高亮和折叠态浮层。页面路由地址保持不变。
+
+菜单配置放在 `src/navigation/adminNavigation.ts`,使用 admin 本地的 `AdminNavigationNode` 类型,避免修改共享包中的单层 `NavigationItem` 并影响 client。节点包含唯一标识、标题、图标、路径、权限编码和可选子节点。图标跟随节点配置,不再依赖 `iconMap[index]` 的数组位置。
+
+当前静态阶段显示全部菜单,不根据模拟角色执行权限过滤,因为现有登录用户没有后端返回的权限编码集合。节点保留权限编码字段;后端权限契约确定后,再以叶子菜单为单位过滤,并只显示至少包含一个可访问子菜单的分组。
+
+移动端继续使用现有抽屉式侧栏:选择页面后自动关闭,点击右侧遮罩关闭。桌面折叠时由 Element Plus 展示子菜单浮层,避免二级入口丢失。
+
+## 静态数据与交互
+
+客户、订单、内部用户、角色和权限页面继续使用 `useAdminDataStore`:
+
+- 查询、筛选和分页在前端执行。
+- 新增、编辑、审核、启停和状态流转直接修改 Pinia 内存数据。
+- 刷新页面后恢复初始模拟数据,不增加持久化。
+- 页面不发起真实业务网络请求。
+
+该策略用于先验收页面结构和操作流程,不伪装成已完成后端联调。
+
+## API 当前边界
+
+保留现有 `src/api/http.ts` 作为 Axios 基础实例,仅包含基础地址、超时和 admin Token 注入。当前不新增客户、订单、用户、角色或权限领域 API,不定义响应信封解包,不实现业务错误转换,也不在 401 拦截器中直接引用 Router 或 Pinia Store。
+
+后端提供接口文档后,再单独确定以下内容:
+
+- URL 前缀和版本规则。
+- 统一响应信封及成功业务码。
+- 分页参数和分页结果结构。
+- 业务错误码与用户提示映射。
+- 401 处理方式;若需要全局退出,使用应用启动层注册的 `onUnauthorized` 回调,避免请求层与 Router、Store 循环依赖。
+- 按认证、客户、头程订单、内部用户、角色和权限拆分领域模块。
+
+真实接口接入后,由 Store 调用领域 API,并负责加载状态、错误状态和数据缓存。页面继续读取 Store,不直接调用 Axios。
+
+## 测试与验收
+
+在 `apps/admin-web` 内增加 Vitest,不影响其他项目。测试覆盖:
+
+- 导航只有工作台是直接一级入口,业务管理和系统管理拥有预期子菜单。
+- 每个叶子菜单的路径和权限编码唯一。
+- 菜单图标由节点自身定义,不依赖数组下标。
+- 静态阶段不因权限字段存在而隐藏任何菜单。
+
+完成后执行:
+
+```bash
+cd apps/admin-web
+pnpm test
+pnpm typecheck
+pnpm build
+```
+
+浏览器验收桌面展开态、桌面折叠态和 390px 移动端,确认二级菜单可访问、当前页面正确高亮、移动侧栏可关闭,并且原有业务交互不回归。
+
+## 完成标准
+
+- admin 菜单不再全部平铺在一级。
+- 新增业务模块时可以放入既有分组或新增分组,不需要改写侧栏组件。
+- 当前六个页面入口全部可达且路由不变。
+- 静态页面的筛选、表单、详情和状态操作继续可用。
+- 页面不会请求不存在的 Java 业务接口,也不会固化未经确认的响应结构。
+- admin 的测试、类型检查和生产构建全部通过。
diff --git a/superpowers/specs/2026-07-27-admin-permission-tree-design.md b/superpowers/specs/2026-07-27-admin-permission-tree-design.md
new file mode 100644
index 0000000..d9e32bc
--- /dev/null
+++ b/superpowers/specs/2026-07-27-admin-permission-tree-design.md
@@ -0,0 +1,100 @@
+# Admin 权限树分组同步设计
+
+## 目标
+
+让权限管理和角色授权中的资源层级与已完成的 admin 侧边栏一致,并支持后续继续增加更深层级,而不需要修改页面的树构建逻辑。
+
+## 方案选择
+
+有三种可选方式:
+
+1. 在权限页面和角色页面分别编写递归逻辑。改动直接,但会产生两份容易漂移的实现。
+2. 使用共享的权限树构建器。两个页面消费同一棵树,筛选、排序和层级行为一致,作为本次采用方案。
+3. 直接从侧边栏导航生成权限树。可以保证菜单一致,但导航不包含按钮和接口权限,且未来后端动态权限尚未确定,不适合当前阶段。
+
+## 权限层级
+
+静态权限数据调整为:
+
+```text
+工作台
+
+业务管理
+├── 客户管理
+│ ├── 新增客户
+│ └── 审核客户
+└── 头程订单
+ ├── 创建订单
+ └── 更新状态
+
+系统管理
+├── 内部用户
+│ └── 维护用户
+├── 角色管理
+│ └── 角色授权
+└── 菜单权限
+ └── 维护权限
+```
+
+“业务管理”和“系统管理”是目录;“工作台、客户管理、头程订单、内部用户、角色管理、菜单权限”是菜单;具体操作是按钮权限。菜单本身使用现有路由权限编码,例如 `customer:list` 和 `system:role:list`,不再额外保留同义的“查看客户”“查看角色”节点。
+
+接口权限待 Java 接口契约确定后再补充。本次不根据静态 URL 猜测接口资源;现有按钮权限上的临时 `/api/...` 路径和 HTTP 方法一并清空,按钮只保留稳定的权限编码。
+
+## 共享树构建器
+
+在 `src/utils/permissionTree.ts` 提供纯函数:
+
+- 根据 `parentId` 递归构建任意深度的权限树。
+- 同级按 `sort` 排序。
+- 接收可选匹配函数;子节点匹配时保留完整祖先链。
+- 防止异常循环引用造成无限递归。
+- 提供后代 ID 查询,编辑上级资源时排除自身及全部后代,避免创建循环。
+
+权限管理页面使用完整 `Permission` 节点,以便编辑、启停和添加下级。角色页面将同一结果映射为 Element Plus 树需要的 `id`、`label`、`code` 和 `children`。
+
+## 静态角色授权
+
+同步更新五个模拟角色的 `permissionIds`:
+
+- 超级管理员拥有全部资源。
+- 运营主管拥有工作台、业务管理、客户审核、订单查看和状态处理。
+- 操作员拥有工作台及头程订单创建、处理权限。
+- 财务拥有工作台及头程订单查看权限。
+- 销售拥有工作台、客户维护及头程订单查看权限。
+
+分组目录 ID 一并保留在角色授权中,以确保回显和父子半选状态明确。
+
+## 页面行为
+
+权限管理:
+
+- 默认展开完整三级树。
+- 搜索命中按钮时仍显示所属菜单及目录。
+- 新增下级、编辑、启停继续使用现有静态交互。
+- 编辑上级资源时不能选择自身或自己的后代。
+
+角色管理:
+
+- 授权抽屉展示相同的目录、菜单和按钮层级。
+- 保存时继续合并已选和半选节点。
+- 权限摘要按菜单与操作分别计数,不把目录计入菜单数量。
+
+## 测试与验收
+
+使用 admin 现有 Vitest:
+
+- 先写失败测试固定三级结构和同级排序。
+- 验证搜索命中深层节点时保留祖先链。
+- 验证循环引用不会导致递归失控。
+- 验证后代 ID 查询能阻止把节点移动到自己的后代下。
+- 验证静态权限编码与导航叶子权限编码一致。
+
+最后执行 `pnpm test`、`pnpm typecheck`、`pnpm build`,并在浏览器检查权限管理页面和角色授权抽屉的桌面及移动端层级展示。UI 改动完成后运行一次 Impeccable 检测。
+
+## 完成标准
+
+- 权限管理和角色授权不再显示五个独立一级业务目录。
+- 两个页面使用同一个递归树构建器。
+- 搜索、排序、授权回显和静态编辑交互保持可用。
+- 不新增真实 API 调用或猜测后端响应格式。
+- 测试、类型检查、构建及浏览器验收通过。
diff --git a/superpowers/specs/2026-07-27-client-navigation-design.md b/superpowers/specs/2026-07-27-client-navigation-design.md
new file mode 100644
index 0000000..d77e8ce
--- /dev/null
+++ b/superpowers/specs/2026-07-27-client-navigation-design.md
@@ -0,0 +1,168 @@
+# Client Web 导航分级与移动侧栏设计
+
+## 背景
+
+`apps/client-web` 当前把业务总览、企业资料、企业成员、角色管理、菜单权限和头程订单全部渲染为同级侧栏链接。权威原型 `docs/悦/头程下单/柏悦客户端.html` 采用“一级业务域 + 二级具体任务”的导航结构,现有实现没有延续这一信息架构,也无法承接后续业务扩展。
+
+Impeccable 验收还发现一个阻断性问题:720px 以下侧栏被隐藏,但页面上的菜单按钮没有打开移动导航的行为,导致移动端无法切换模块。
+
+## 目标
+
+- 将客户工作台的平铺菜单改为可扩展的两级分组导航。
+- 保留现有路由、页面、文案、品牌颜色与 Element Plus 技术体系。
+- 修复移动端导航不可用的问题。
+- 让菜单节点显式携带图标与权限信息,避免依赖数组下标。
+- 为后续真实权限集合接入保留清晰边界,不在本次伪造授权数据。
+
+## 非目标
+
+- 不新增原型中尚未实现的一键导入、快速下单、海外仓或财务结算入口。
+- 不改变现有路由地址,不拆分当前 `ModuleView.vue` 页面。
+- 不照搬原型的紫色渐变视觉,不重做登录、注册或业务内容页。
+- 不实现服务端权限校验,也不把前端菜单隐藏当作安全控制。
+- 不新增测试框架;当前项目尚未声明测试脚本。
+
+## 导航信息架构
+
+采用两级分组,业务总览保留直接入口:
+
+```text
+业务总览 /
+
+头程业务 可展开分组
+└── 头程订单 /orders/first-leg
+
+企业管理 可展开分组
+├── 企业资料 /company/profile
+├── 企业成员 /organization/members
+├── 角色管理 /organization/roles
+└── 菜单权限 /organization/permissions
+```
+
+分组遵循原型的结构原则,但只呈现当前真实存在的客户端路由。后续功能只有在页面与路由实现后,才加入对应业务分组。
+
+## 组件与数据结构
+
+### 导航配置
+
+新增客户端本地导航配置 `src/navigation/clientNavigation.ts`。定义客户端专用的 `ClientNavigationNode`,包含:
+
+- 稳定 `key`;
+- 用户可见 `title`;
+- Lucide 图标组件;
+- 可选 `path`;
+- 可选 `permission`;
+- 可选 `children`。
+
+共享包中的 `NavigationItem` 仍保持单层公共模型,避免为了单个应用的壳层结构扩大跨项目契约。
+
+### 侧栏菜单组件
+
+新增独立的客户端侧栏菜单组件,使用 Element Plus 的 `el-menu`、`el-sub-menu` 与 `el-menu-item`:
+
+- `active-path` 由当前路由提供;
+- 父分组可展开和收起;
+- 当前路由所在分组默认展开;
+- 叶子菜单负责实际路由跳转;
+- 图标来自节点配置,不依赖渲染顺序;
+- 桌面与移动端复用同一组件和同一份导航数据。
+
+本轮不额外实现展开状态持久化;Element Plus 在当前会话中维护用户开合状态,且当前路由所在分组始终可识别。持久化不是修复平铺结构与移动阻断所必需的能力。
+
+### 应用壳层
+
+`AppLayout.vue` 继续负责品牌、租户、用户和页面标题,同时增加:
+
+- `mobileMenuOpen` 状态;
+- 移动菜单按钮的 `aria-expanded`;
+- 遮罩关闭;
+- 路由切换后自动关闭;
+- Escape 键关闭;
+- 打开时阻止背景页面滚动;
+- 退出确认取消时不产生未处理异常。
+
+桌面侧栏保持固定宽度和现有绿色服务型视觉,不引入后台的深色侧栏,也不增加桌面折叠模式。
+
+## 交互与状态流
+
+### 桌面端
+
+1. 路由加载后,菜单以 `route.path` 高亮对应叶子。
+2. “业务总览”为直接入口。
+3. “头程业务”和“企业管理”为分组触发器。
+4. 当前页面属于某分组时,该分组保持展开并显示父级激活语义。
+5. 用户可以独立展开或收起其他分组。
+
+### 移动端
+
+1. 720px 以下侧栏移出视口,而不是使用 `display: none` 永久移除。
+2. 点击页面标题前的菜单按钮打开抽屉并显示遮罩。
+3. 点击遮罩、按 Escape 或选择任一叶子路由后关闭抽屉。
+4. 抽屉打开时禁止背景滚动,关闭或组件卸载时恢复。
+5. 抽屉沿用完整租户导航,不维护第二份移动菜单。
+
+### 权限
+
+导航节点继续携带权限编码。当前模拟用户没有可靠的权限集合,因此静态阶段显示全部已实现菜单。真实认证接口返回权限集合后,再增加叶子过滤;父分组没有可访问子项时隐藏。服务端必须继续执行租户与权限校验。
+
+## 视觉与可访问性
+
+- 保留现有 `--primary`、`--navy`、`--border` 和 `--muted` 设计令牌。
+- 一级分组与二级叶子通过缩进、字号、颜色和激活背景形成清晰层级。
+- 分组触发器与移动菜单按钮使用真实可聚焦控件。
+- 保持可见 `:focus-visible` 状态,不只依赖 hover 或颜色表达当前状态。
+- 菜单触控目标不低于约 44px。
+- 二级菜单文本允许单行省略,避免长租户业务名称破坏侧栏宽度。
+- 侧栏导航区域允许纵向滚动;底部帮助区保持可达。
+- 320px、720px 与桌面宽度均不能依赖水平滚动完成导航。
+
+## 错误与边界处理
+
+- 用户取消退出确认时保持当前页面,不产生控制台未处理异常。
+- 移动抽屉在快速路由切换、浏览器后退和组件卸载后不得残留锁定滚动状态。
+- 不存在或被移除的路由继续走现有兜底重定向。
+- 当前不虚构客户经理电话、微信或帮助中心链接;帮助区保留为信息提示,后续有真实渠道后再做可执行入口。
+- 权限为空或数据尚未加载时,本轮不提前隐藏菜单,避免模拟阶段出现无法恢复的空侧栏。
+
+## 实施范围
+
+预计修改或新增:
+
+- `apps/client-web/src/navigation/clientNavigation.ts`
+- `apps/client-web/src/components/ClientSidebarMenu.vue`
+- `apps/client-web/src/layouts/AppLayout.vue`
+- `apps/client-web/src/router/index.ts`
+- `apps/client-web/src/styles/index.css`
+
+仅当实现需要声明自动导入组件时,依赖现有插件自动生成声明,不手工编辑 `auto-imports.d.ts` 或 `components.d.ts`。
+
+## 验收与验证
+
+### 自动验证
+
+在 `apps/client-web` 执行:
+
+```bash
+pnpm typecheck
+pnpm build
+```
+
+项目当前没有 test 或 lint 脚本,因此不声称相应检查通过,也不为本次导航改动引入整套测试设施。
+
+### Impeccable 验收
+
+- 运行一次机械检测,目标覆盖本次变更的 Vue 文件。
+- 桌面检查:一级分组、二级缩进、当前路由高亮、可见焦点和侧栏滚动。
+- 720px 检查:断点切换时导航仍可达。
+- 320px 检查:抽屉、遮罩、触控目标与页面内容不发生水平溢出。
+- 浏览器可用时检查菜单打开、选择路由、遮罩关闭和 Escape 关闭;若浏览器不可用,明确记录回退证据,不伪装成已完成视觉实测。
+
+## 完成标准
+
+- 侧栏不再把全部功能放在一级菜单。
+- 当前六个页面入口全部可达,路由地址不变。
+- 桌面端当前页面与父分组状态清晰。
+- 720px 以下菜单按钮能够打开和关闭真实导航抽屉。
+- 导航图标不会因菜单调序或新增分组而错位。
+- 未实现的原型功能不会作为无效入口出现。
+- 类型检查、生产构建与 Impeccable 检测无未解释失败。
diff --git a/superpowers/specs/2026-07-27-pda-picking-static-pages-design.md b/superpowers/specs/2026-07-27-pda-picking-static-pages-design.md
new file mode 100644
index 0000000..aee85a7
--- /dev/null
+++ b/superpowers/specs/2026-07-27-pda-picking-static-pages-design.md
@@ -0,0 +1,105 @@
+# PDA 拣货静态页面设计
+
+## 目标
+
+在 `apps/pda-uniapp` 中将 `docs/悦/PDA拣货/pda-picking.html` 转换为可运行在 Android PDA 上的 uni-app 页面。原型是唯一视觉和交互依据;实现保留原型文案、布局、颜色、页面密度、演示数据和本地状态流。
+
+本次不接后端、不实现真实鉴权、不接厂商扫描 SDK、不实现持久化或离线队列。
+
+## 实现方案
+
+采用单页面作业流:登录态与拣货态均由 `pages/index/index.vue` 承载,使用 Vue 本地响应式状态切换,而不拆成多个路由。原因如下:
+
+- 原型本身是连续的单页状态机,登录后立即进入同一作业上下文。
+- 本阶段没有后端、深链、权限路由或跨页面数据恢复需求。
+- 单页面可避免箱号、货品状态和弹层状态在路由之间同步,保持改动小而聚焦。
+
+为避免页面文件承担过多重复结构,可将货品卡片和通用弹层拆成局部业务组件;演示数据与状态转换仍由页面统一管理。当前不引入状态管理库或新依赖。
+
+## 页面结构
+
+### 登录态
+
+- 蓝色渐变背景、系统标识、`柏悦物流 · PDA拣货` 标题和副标题。
+- 工号、密码、作业仓库三个字段。
+- 普通登录按钮和三个演示账号快捷登录按钮。
+- 空工号、空密码和账号密码错误使用原型文案提示。
+- 登录成功后显示欢迎提示并进入拣货态;退出后清空登录表单与作业状态。
+
+### 拣货态
+
+- 顶部蓝色作业栏:页面标题、仓库、退出、当前箱号、订单号和人员身份。
+- `pages.json` 将首页设置为 `navigationStyle: "custom"`,不显示当前标题为 `uni-app` 的原生导航栏,避免与原型作业栏重复;页面自行处理状态栏安全区。
+- 箱号选择器:显示全部演示箱号与订单号,切换时重置当前箱的未提交本地操作。
+- 扫码区:输入或扫描 SKU 后回车确认;匹配当前箱中待拣 SKU 时标记已拣,错误码显示失败提示。登录进入拣货态、成功或失败扫码、确认拣出、撤销以及关闭任一弹层后,都应把焦点恢复到扫码输入框;打开需要输入数量的部分拣货弹层时,焦点临时交给数量输入框。成功扫码后清空输入值,无效码和重复扫描已处理 SKU 时保留明确错误反馈,并在反馈后继续接收下一次扫描。
+- 箱号与订单信息卡。
+- 拣货进度、货品列表、集装箱完成/待拣统计和底部提交栏。
+- 底部提交栏固定在可视区域底部,并避让 Android 导航栏安全区。
+- 提交按钮初始禁用;当所有货品均已处理时启用并显示“提交拣货完成”;当至少存在一件已拣或部分拣货、同时仍有待拣货品时启用并显示“提交拣货完成(N件待拣将视为未拣)”;仅发生部分跳拣且仍有待拣货品时保持禁用。
+
+### 货品状态
+
+每个货品使用以下本地状态之一:
+
+- `pending`:待拣,提供确认拣出、部分拣货、跳拣。
+- `picked`:已拣,显示完成标签与撤销入口。
+- `partial`:部分拣货,显示实际数量、目标数量与撤销入口。
+- `skipped`:跳拣或提交时自动未拣,显示原因与撤销入口。
+
+待拣货品排在已处理货品之前。进度按已拣、部分拣和跳拣的已处理数量计算。
+
+## 弹层与反馈
+
+- 跳拣弹层:单选原型中的五个原因,未选择时禁止确认并提示。
+- 部分拣货弹层:显示 SKU、描述、总量、单位、快捷比例和数量输入;数量必须大于 0 且小于需求总量。
+- 集装箱列表弹层:分别展示已完成与待拣箱,允许从待拣列表切换箱号。
+- 完成弹层:展示已拣、部分拣、跳拣/未拣统计,并提供返回查看和下一箱。
+- 短反馈沿用原型顶部提示条及成功、警告、错误配色。
+
+Android 系统返回键按以下优先级处理:关闭当前弹层,关闭箱号下拉;若处于拣货态且无覆盖层,则调用与“退出”按钮相同的重置流程返回登录态;登录态交由系统退出页面。
+
+## 本地数据与状态
+
+保留原型中的三个箱号、订单号、货品、库位、单位、演示账号和跳拣原因。页面维护:
+
+- 当前用户与仓库;
+- 当前箱号索引;
+- 当前箱内各 SKU 状态;
+- 部分拣货数量;
+- 已完成箱号集合;
+- 当前下拉、弹层、目标货品和提示条状态;
+- 扫码输入值。
+
+提交时,未处理货品按原型标记为“未拣出(提交时自动标记)”,保存当前箱的最终演示状态并更新集装箱统计。刷新、退出或重启应用后允许数据重置,因为本阶段没有持久化要求。
+
+## 视觉与响应式
+
+- 颜色遵循原型:主色 `#1a73e8`、成功 `#0d9488`、危险 `#dc2626`、警告 `#f59e0b`、页面背景 `#f5f7fa`。
+- 保留 12px 圆角、浅阴影、蓝色当前货品边线、状态色和卡片密度。
+- 使用 uni-app 支持的 `rpx`、百分比和安全区变量适配 Android PDA,以 `360 × 640 dp` 为主要检查尺寸,兼容约 `320–480 dp` 宽度。
+- 不引入新字体、图片生成素材、第三方图标库或新的视觉语言。
+- 图标优先使用简单 CSS/文本符号或现有静态资源,避免依赖网页专属 SVG 注入方式。
+- 本阶段不使用网络、震动、相机或存储能力,因此实现时移除 `manifest.json` 中手工声明的 `VIBRATE` 和 `ACCESS_NETWORK_STATE` 权限;未来接入对应能力时再按明确用途恢复最小权限。
+
+## 边界状态
+
+- 登录加载态:当前纯本地操作无需异步加载,不添加虚假等待动画。
+- 空态:保留“该箱号暂无拣货任务”“暂无已拣完成的集装箱”“所有集装箱已拣完成”等原型语义。
+- 错误态:覆盖登录校验、空扫码、无效 SKU、未选跳拣原因、无效部分数量和最后一箱提示。
+- 重复操作:已处理货品不再匹配扫码;撤销后恢复为待拣。
+- 权限态:本阶段没有服务端权限;人员角色仅作演示展示,不据此隐藏功能。
+- 软键盘:输入区与部分拣货输入不得被键盘永久遮挡,关闭弹层后恢复扫码输入上下文。
+
+## 验证
+
+仓库当前没有项目根级依赖清单、可核实的构建脚本或自动化测试设施,因此不新增或编造测试命令。实现后进行以下可核实检查:
+
+1. 静态检查 `pages.json`、Vue 模板、脚本和样式是否符合现有 uni-app 结构。
+2. 若当前环境可用 HBuilderX/uni-app 运行能力,则以 Android App 方式运行;否则明确记录未执行构建。
+3. 在常见 PDA 尺寸核对登录、主作业、弹层、底部固定栏和软键盘遮挡。
+4. 手工走通快捷登录、箱号切换、有效/无效/重复扫码、确认拣出、部分拣货、跳拣、撤销、提前提交、完整提交和下一箱,并核对每次关键操作后的扫码焦点。
+5. 检查提交按钮在初始、仅部分跳拣、存在已拣且仍有待拣、全部处理四种状态下的启用状态和文案。
+6. 检查系统返回对弹层、下拉、拣货态和登录态的处理,并确认返回登录态时执行完整状态重置。
+7. 检查首页未出现重复原生导航栏,并确认 Android 配置不再手工声明当前未使用的网络与震动权限。
+
+真实扫描速度、连续扫描、低电量、断网、前后台切换、厂商扫描头和正式打包发布不属于本次静态实现的可验证范围,需在设备与工具链确定后补测。
diff --git a/superpowers/specs/2026-07-28-admin-static-rbac-preview-design.md b/superpowers/specs/2026-07-28-admin-static-rbac-preview-design.md
new file mode 100644
index 0000000..2604b0b
--- /dev/null
+++ b/superpowers/specs/2026-07-28-admin-static-rbac-preview-design.md
@@ -0,0 +1,217 @@
+# Admin 静态 RBAC 权限预览设计
+
+## 背景
+
+管理后台已经具备内部用户、角色、权限资源和分组菜单的静态交互,但角色授权结果尚未作用到登录后的菜单、路由和操作按钮。路由中的 `meta.permission` 目前只是元数据,无法演示角色权限是否真正生效。
+
+本阶段建立一个可操作的静态 RBAC 演示闭环,用于前端原型验收。它不代表真实服务端鉴权,也不定义 Java API、Token 内容、权限响应结构或错误码。
+
+## 目标
+
+- 在管理后台顶部切换初始模拟数据中的五个启用角色,并继续支持后续新增或停用角色后的动态列表。
+- 根据角色授权实时过滤侧边栏菜单。
+- 阻止静态原型访问无权限路由,并提供清晰的无权限页面。
+- 对已经存在稳定权限编码的操作按钮进行显示控制。
+- 角色授权数据发生变化时,权限预览同步更新。
+- 保留现有登录、页面交互、响应式布局和独立前端工程结构。
+
+## 不在本次范围
+
+- 不调用真实登录、用户、角色、菜单或权限接口。
+- 不修改 `src/api/http.ts` 的请求或响应约定。
+- 不新增或猜测 Java API 路径、响应包络、分页结构和错误码。
+- 不把前端菜单隐藏或路由跳转描述为安全边界;服务端仍需在后续接口阶段执行最终鉴权。
+- 不为当前静态权限模型中没有定义的操作擅自增加权限编码。
+- 不模拟角色的 `dataScope` 数据范围,不因切换“全部数据”“本部门数据”或“本人数据”角色而过滤客户、订单等模拟记录。
+- 不处理企业客户端、官网、小程序、APP 或 PDA 的权限体系。
+
+## 方案选择
+
+### 采用方案:顶部切换演示角色
+
+在后台顶栏提供“演示角色”切换入口,角色变化后菜单、路由和明确映射的操作按钮立即更新。该方式不要求反复退出登录,适合静态原型展示和权限配置验收。
+
+### 未采用方案
+
+- 使用不同账号重新登录:更接近真实登录流程,但重复退出登录会降低原型验收效率,且当前没有服务端身份契约。
+- 只控制菜单和路由:改动较少,但无法验证现有按钮权限是否产生可见效果。
+
+## 架构边界
+
+### 权限预览状态
+
+新增 admin 专属 Pinia 状态层,职责仅限静态权限预览:
+
+- 保存当前演示角色 ID。
+- 从 `useAdminDataStore` 中读取当前启用角色和权限资源。
+- 根据角色的 `permissionIds` 计算权限编码集合,但只纳入 `status === '启用'` 的权限资源;角色仍保留已停用权限 ID 时,不授予对应访问权。
+- 提供 `can(permissionCode)` 判断。
+- 提供当前角色、可选角色及第一个可访问菜单。
+- 提供登录成功后的初始化、退出时重置和两阶段角色切换动作;页面和布局不直接写入持久化角色 ID。
+
+认证状态仍由 `src/stores/auth.ts` 管理。权限预览状态不写入 Token,不修改 `CurrentUser` 的稳定共享模型,也不在页面中复制认证逻辑。
+
+演示角色 ID 使用 admin 项目专属的 `localStorage` 键保存,以便刷新后保留预览上下文。保存值失效、角色被删除或角色被停用时,回退到启用的超级管理员;如果超级管理员不可用,则回退到第一个启用角色。此回退只服务静态原型,不代表后端策略。
+
+预览状态与认证状态采用明确的生命周期边界:
+
+- 页面刷新保留当前演示角色。
+- 退出操作先调用权限预览 Store 的重置动作,清除内存状态与持久化演示角色 ID,再调用 `auth.logout()`;认证 Store 不承担预览状态职责。
+- 登录成功后由登录流程调用权限预览 Store 的初始化动作,默认选择启用的超级管理员;超级管理员不可用时选择第一个启用角色。未登录阶段不自动初始化或重新持久化默认角色。
+- 顶栏固定区分两个来源:`登录身份:{auth.user.name}({auth.user.account})` 与 `权限预览:{previewRole.name}`。认证角色 `auth.user.roles` 不作为无标签副标题展示,也不被预览状态读取或改写。
+- `localStorage` 在同源标签页之间共享,但本期不监听 `storage` 事件做实时跨标签同步;其他标签页刷新后读取最新持久化角色。
+
+### 权限数据流
+
+```text
+adminData.roles + adminData.permissions
+ ↓
+ 静态权限预览 Store
+ ↓ ↓ ↓
+ 侧边栏 路由决策 页面操作
+ ↓
+ 未保存内容保护
+```
+
+角色授权编辑保存到 `adminData.roles` 后,权限编码集合通过计算属性立即更新,不复制第二份角色或权限数据。
+
+## 菜单与路由行为
+
+### 菜单过滤
+
+在现有 `adminNavigation` 基础上增加纯函数过滤:
+
+- 叶子菜单只在其 `permission` 存在于当前权限编码集合时保留。
+- 目录仅作为导航组织节点,其自身启停状态不级联授予或撤销后代权限;叶子菜单只判断自身对应的启用权限资源。
+- 任意层级目录在递归过滤后没有任何子菜单时隐藏。
+- 菜单原始配置保持不可变,过滤函数返回新节点。
+- 工作台继续使用 `dashboard:view`,与其他菜单采用相同规则。
+- “第一个可访问菜单”固定为过滤后 `adminNavigation` 配置顺序中的第一个叶子,采用深度优先遍历,不使用权限资源的 `sort` 决定回退目标。
+
+工作台路由必须显式声明 `meta.permission: 'dashboard:view'`。所有受导航权限控制的叶子页面都应同时具有对应路由权限元数据,不能只过滤菜单而遗漏直接地址访问。
+
+`AdminSidebarMenu` 接收过滤后的导航数据,不直接读取 Pinia,并通过递归菜单节点支持后续新增更深层级;权限来源与具体渲染层级不耦合。
+
+### 路由守卫
+
+登录校验继续先于权限校验执行:
+
+1. 未登录访问受保护页面时跳转登录页。
+2. 已登录且目标路由声明 `meta.permission` 时,使用静态权限预览判断访问权。
+3. 无权限的直接访问跳转到静态 `/403` 页面,使用 `query.from` 保留经过校验的站内来源路径用于纯文本提示;只接受以单个 `/` 开头的内部路径,不把该值作为外部跳转地址。
+4. `/403` 本身需要登录,但不要求业务权限,避免重定向循环。
+5. 404 重定向保持现状。
+
+为便于单元测试,路由权限决策下沉为不依赖浏览器导航的纯函数;Vue Router 守卫只负责读取状态并执行决策结果。
+
+除导航守卫外,登录态布局还需要响应式监听当前有效权限集合、当前演示角色有效性和当前路由。当角色授权被修改、当前角色被停用或删除、权限资源被停用等变化导致当前页面失去访问权时,立即重新校验当前路由:优先跳转到回退后角色的第一个可访问叶子菜单;没有可访问菜单时进入 `/403`。
+
+导航守卫负责首次进入和显式导航,登录态布局只负责已渲染页面上的响应式权限变化;两者调用同一个纯路由决策函数。布局执行修正前比较目标与当前 `fullPath`,使用单次导航锁避免并发修正,并统一调用 `router.replace`,使浏览器后退不会再次回到刚被拒绝的地址。目标已经相同或当前已处于无菜单可恢复的 `/403` 时不重复导航。
+
+### 主动切换角色
+
+用户从顶栏切换角色采用“请求—确认—提交”两阶段流程,不在下拉选择事件中直接覆盖当前角色:
+
+- 先根据候选角色计算候选权限、当前页面可访问性和回退目标。
+- 当前页面的新增/编辑抽屉或对话框存在已修改但未保存的内容,且切换会离开当前路由或撤销该表单保存所需的操作权限时,显示确认框,明确候选角色和将离开的页面;取消后角色、路由和表单内容均保持不变。
+- 各业务页面通过 admin 专属的轻量离开保护协调器登记 `{ dirty, requiredPermission, label }`;只在字段实际变化后标记 dirty,关闭或成功保存时注销,不把业务表单数据复制到全局 Store。
+- 用户确认或没有受影响的未保存内容后,才提交演示角色 ID;需要修正路由时统一使用 `router.replace`。
+- 顶栏随后显示新的演示角色名称,并显示 `已切换至“{角色名}”,当前仅为静态权限预览`。
+- 当前页面仍可访问时保持原路由。
+- 当前页面不再可访问时,跳转到该角色第一个可访问菜单。
+- 如果切换角色时当前页面是 `/403`,只要新角色存在可访问菜单,就始终跳转到第一个可访问叶子菜单,不把 `/403` 视为应继续停留的业务页面。
+- 如果角色没有任何菜单权限,进入 `/403`,显示“当前演示角色暂无可访问菜单”。
+- 自动跳转完成后将焦点移到新页面主标题,并通过 `aria-live="polite"` 播报当前预览角色与目标页面;仅停留原页面时也播报角色变化。
+
+## 操作权限映射
+
+本次只控制现有静态模型中已有明确编码的操作:
+
+| 页面 | 操作 | 权限编码 |
+|---|---|---|
+| 客户管理 | 新增客户 | `customer:create` |
+| 客户管理 | 审核客户、详情中的通过审核 | `customer:audit` |
+| 头程订单 | 创建订单、创建并提交、保存新草稿 | `first-leg:create` |
+| 头程订单 | 单笔处理、批量更新、更新状态 | `first-leg:status` |
+| 内部用户 | 新增、编辑、重置密码、启停、保存 | `system:user:write` |
+| 角色管理 | 新增、配置、启停、删除、保存 | `system:role:grant` |
+| 菜单权限 | 新增、编辑、添加下级、启停、保存 | `system:permission:write` |
+
+详情、查询、筛选和已有页面级导出继续由对应菜单权限覆盖。客户编辑/启停、订单编辑等没有独立稳定操作编码的功能暂不额外限制;待 Java 权限契约确定后再细分,避免静态原型创造错误的长期编码。
+
+页面通过同一个权限预览 Store 的 `can` 方法控制明确映射的操作,不创建页面私有权限判断逻辑。无权限操作不渲染,避免用户误以为按钮可用后才收到拒绝。
+
+## 顶栏交互
+
+- 在现有用户信息和退出按钮之间增加“演示角色”下拉入口。
+- 使用 Lucide 图标和 Element Plus 现有组件,不引入新依赖。
+- 下拉只展示启用角色,并标记当前角色。
+- 桌面端持续显示 `权限预览:{角色名}`,并提供“仅预览菜单、页面和操作;数据范围未模拟”的可聚焦说明;登录用户区域显示 `登录身份:{姓名}({账号})`,两者不共用“角色”副标题。
+- 窄屏至少保留可识别图标、`权限预览:{角色名},数据范围未模拟` 的可访问名称和 44px 触控区域;长角色名称使用省略与完整 tooltip,不挤压退出按钮。
+- 角色下拉支持 Tab 聚焦、Enter/Space 打开、方向键移动、Enter 选择和 Escape 关闭,并保持可见焦点。
+- 入口和反馈文案始终包含“演示”或“预览”,避免被理解为真实用户换号或数据范围切换。
+
+## 无权限页面
+
+新增轻量静态 403 页面:
+
+- 说明当前演示角色无权访问目标页面。
+- 显示当前演示角色名称。
+- 来源路径只作为经过校验、可截断换行的纯文本显示,不生成“返回来源地址”链接。
+- 当前角色存在可访问菜单时,提供“返回可访问首页”操作。
+- 当前角色没有任何可访问菜单时,提示用户使用顶栏入口切换演示角色。
+- 不使用夸张插画或与现有后台不一致的视觉语言。
+- 页面作为登录态布局的子路由呈现,使顶栏角色切换始终可用。
+
+## 状态与边界处理
+
+- 角色切换只修改本地预览状态,不修改内部用户的真实 `roleIds`。
+- 停用或删除当前演示角色时自动执行回退,不保留悬空角色 ID。
+- 停用权限资源会立即从当前角色的有效权限编码集合中移除,即使该权限 ID 仍存在于角色授权数据中。
+- 停用目录资源只改变该目录资源自身的有效编码,不级联改变启用后代的菜单、路由或操作权限;权限管理页的停用确认明确说明这一点。
+- 超级管理员通过角色现有的全部 `permissionIds` 获得权限,不在代码中使用绕过所有检查的特殊布尔值。
+- 角色拥有目录权限但没有任何叶子菜单权限时,不显示空目录。
+- 如果异常模拟数据中不存在任何启用角色,当前角色为空、有效权限集合为空并进入 `/403`;正常页面继续保护内置超级管理员,避免产生该状态。
+- 多角色合并不在本次预览范围;预览入口一次选择一个角色,真实用户多角色合并规则等待后端契约。
+- 静态权限预览不静默回退到远程数据,也不发起网络请求。
+
+## 测试策略
+
+使用 admin 现有 Vitest,按测试驱动方式实现:
+
+- 权限预览 Store:两阶段角色选择、权限编码派生、停用权限资源不授予访问权、失效角色回退、零启用角色、角色授权变更实时生效、退出登录重置且刷新保留、未登录时不重新初始化默认角色。
+- 导航过滤:隐藏无权限叶子、目录停用不级联后代、递归移除空目录、保持原配置不可变、按 `adminNavigation` 深度优先顺序确定第一个可访问菜单。
+- 路由配置与决策:工作台显式声明 `dashboard:view`;覆盖未登录、已登录有权限、已登录无权限、403 免业务权限四种分支。
+- 当前路由再校验:角色授权减少、角色停用或删除、权限资源停用后,当前无权限页面通过 `router.replace` 跳转到第一个可访问叶子或 `/403`;覆盖目标相同、导航锁和浏览器后退不返回被拒页面。
+- 侧边栏组件:只渲染传入的过滤结果,并覆盖三层导航数据以证明递归渲染不受当前两层结构限制。
+- 顶栏角色切换:当前角色回显、准确的登录身份/权限预览标签、窄屏可访问名称、键盘操作、长角色名,以及从 `/403` 切换到有权限角色后恢复到第一个可访问菜单。
+- 未保存内容保护:覆盖无修改直接切换、有修改但权限不受影响、有修改且将离开或失去保存权限、取消保持全部状态、确认后提交角色并 replace 跳转。
+- 无障碍动态状态:覆盖成功切换和自动跳转的 polite 播报、跳转后主标题焦点与 Escape 关闭角色菜单。
+- 状态来源与生命周期:用户姓名/账号来自认证 Store,演示角色来自权限预览 Store;退出清除预览角色,重新登录使用默认启用角色。
+- 页面操作:至少覆盖每个操作权限域的一项代表按钮,确认无权限时不渲染。
+- 数据范围边界:角色切换不改变模拟记录集合,界面持续说明 `dataScope` 未模拟。
+
+交付前运行:
+
+```bash
+pnpm test
+pnpm typecheck
+pnpm build
+```
+
+浏览器验收覆盖桌面、390px 和项目约定的 320px 最小宽度,并检查 200% 浏览器缩放:角色切换、菜单变化、未保存内容确认/取消、自动跳转、直接访问 403、代表性按钮显示与隐藏、键盘完整操作、可见焦点、动态播报、顶栏不重叠或裁切以及控制台错误。UI 修改完成后运行一次 Impeccable 检测。
+
+## 完成标准
+
+- 初始模拟数据中的五个启用角色可在顶栏切换,后续角色新增、停用或删除后列表与回退实时更新。
+- 菜单、路由和已映射操作与当前角色的启用权限资源一致,停用权限不产生访问权。
+- 权限预览明确不包含 `dataScope`,角色切换不改变模拟记录,桌面和窄屏均持续提供这一说明。
+- 无权限直接访问有明确 403 反馈,不出现循环跳转。
+- 角色授权、角色有效性或权限资源状态变化能即时影响当前预览;当前路由失去权限时立即修正到第一个可访问叶子或 `/403`。
+- 目录停用语义固定为不级联后代;递归菜单过滤与渲染支持后续增加更深菜单层级。
+- 角色切换不会静默丢失已修改表单;取消保持原角色、路由和内容,确认后使用 replace 完成必要跳转。
+- 从 `/403` 切换到具有菜单权限的角色后能恢复到可访问页面。
+- 刷新保留演示角色,退出登录清除预览状态,重新登录采用默认启用角色;`登录身份` 与 `权限预览` 的标签、数据来源和视觉层级清晰分离。
+- 键盘、读屏播报、焦点管理、320px/390px、200% 缩放与长角色名称均通过验收。
+- 不产生任何真实 API 请求或新的后端契约假设。
+- admin 项目测试、类型检查、构建、桌面/移动端浏览器验收及 Impeccable 检测通过。
diff --git a/一期/README.md b/一期/README.md
new file mode 100644
index 0000000..f2d358a
--- /dev/null
+++ b/一期/README.md
@@ -0,0 +1,23 @@
+# 一期文档
+
+一期目标是完成平台后台与企业客户端的真实业务基础,以及头程订单最小闭环。
+
+## 文档
+
+- [一期开发进度表](一期开发进度表.md)
+- [一期头程订单闭环设计](一期头程订单闭环设计.md)
+- `虫虫出海一期开发进度表.xlsx`:面向团队日常维护的 Excel 进度表。
+
+## 原型来源
+
+- 产品原型统一位于 `docs/悦/`。
+- 企业登录与注册分别参考 `docs/悦/合并/login.html`、`docs/悦/合并/register.html`;一期只默认包含中文账号密码登录和基础企业注册闭环。
+- 快递公司和往来单位参考 `docs/悦/货代SAAS平台后台/货代SaaS平台原型.html` 中“通用”菜单下的对应页面。
+- 原型用于确认信息架构、字段和视觉方向;是否已进入当前 Vue 应用、是否具备完整交互与数据持久化,以一期开发进度表为准。
+
+## 当前边界
+
+- 平台后台:内部账号登录、客户及企业资料审核、内部用户、角色权限、平台收货仓、快递公司、往来单位和头程订单;工作台不作为一期交付项。
+- 企业客户端:中文邮箱/手机号加密码登录、免审核企业注册、企业资料、成员角色权限、头程下单、订单列表和详情;企业资料经平台人工审核通过后才允许提交订单,一期不接短信/邮箱验证码及微信、企业微信登录。
+- 服务端:认证、租户隔离、权限、文件、基础资料、订单状态机、幂等和审计。
+- 不包含工作台、部门/组织架构、完整 WMS、FBA/海外目的仓服务、在线报价、财务结算、完整报关清关、外部物流接口、多语言及微信/企业微信登录;快递公司和往来单位一期支持批量导入,不提供导出。
diff --git a/一期/一期头程订单闭环设计.md b/一期/一期头程订单闭环设计.md
new file mode 100644
index 0000000..32f050f
--- /dev/null
+++ b/一期/一期头程订单闭环设计.md
@@ -0,0 +1,376 @@
+# 一期头程订单闭环设计
+
+> 状态:产品决策已确认,前端静态闭环实施中
+> 创建日期:2026-07-28
+> 适用范围:`apps/client-web`、`apps/admin-web`、`packages/shared`、`services/api`
+
+## 一、目标
+
+一期形成可验收的最小订单闭环:
+
+1. 企业注册成功后可直接登录,不经过注册审核。
+2. 企业提交资料,由平台人员人工点击审核通过;只有审核通过的企业才可提交头程订单。
+3. 企业客户创建头程订单并保存草稿,提交后平台后台收到待审核任务。
+4. 平台人员审核订单;信息有误时由后台人工修改,或联系客户修改,不设置驳回操作。
+5. 平台人员受理、订舱并更新运输状态,企业客户查看订单详情和处理进度。
+6. 企业客户在允许的状态下取消订单。
+
+本设计先统一业务契约,不预先绑定尚未确认的 Java 框架、数据库、中间件或微服务拆分方式。
+
+## 原型依据与迁移原则
+
+一期原型统一以 `docs/悦/` 为依据。快递公司、往来单位的直接参考页面位于 `docs/悦/货代SAAS平台后台/货代SaaS平台原型.html` 的“通用”菜单:
+
+| 原型页面 | 已有内容 | 一期迁移说明 |
+|---|---|---|
+| 快递公司 | 公司名称、编码、官网、客服电话、合作状态;名称/编码和状态筛选;新增、导入、导出、编辑入口 | 保留核心字段与列表方向;状态统一映射为 `ACTIVE` / `INACTIVE`;一期实现标准模板导入,不实现导出 |
+| 往来单位 | 单位名称、类型、联系人、电话、启停状态;名称、类型和状态筛选;新增、导入、导出、编辑、详情入口 | 补充稳定编码、邮箱和完整地址;类型与一期订单的发货方/收货方角色统一;一期实现标准模板导入,不实现导出 |
+
+现有 HTML 原型已完成菜单、静态列表、演示数据和表格渲染,但多数按钮没有完整的数据提交、校验、失败反馈和持久化流程。因此迁移到 `apps/admin-web`、`apps/client-web` 时,必须按当前项目的 Vue、Pinia、RBAC、响应式和测试约定重新实现,不能把原型存在等同于当前工程已经完成。
+
+原型负责提供信息架构、字段和视觉参考;一期范围、数据隔离、权限和历史快照规则以本设计及开发进度表为准。原型中的 FBA、海外仓、库位、货架、托盘、船期价格和完整 WMS 菜单不因复用同一页面而进入一期。
+
+## 二、一期边界
+
+### 纳入一期
+
+- 客户端:订单列表、组合筛选、创建、编辑草稿、提交、详情、取消。
+- 管理后台:企业资料审核通过、订单列表、详情、待审核订单人工修改、受理、负责人分配和状态更新。
+- 服务端:真实租户隔离、权限校验、状态机、幂等提交、并发控制和操作时间线。
+- 公共契约:订单状态、运输方式、优先级、列表摘要和详情模型。
+- 平台收货仓:后台维护国内收货仓档案和启停状态;客户端新建订单只选择已启用仓库。
+- 快递公司:后台人员统一维护快递公司档案和启停状态;企业客户端不维护,订单详情只读展示履约快递信息。
+- 往来单位:后台人员维护发货单位、收货单位、供应商和服务商;企业客户端只读选择当前可用的发货方和收货方。
+- 货物信息:一期至少支持一条货物明细,并允许同一订单包含多条明细。
+
+### 暂不纳入一期
+
+- 在线询价、自动报价和费率计算。
+- 应收应付、对账、结算和利润核算。
+- 报关、清关、保险和完整单证中心。
+- 船期自动同步、承运商接口和实时物流轨迹。
+- Excel 批量下单、快速下单和复制订单。
+- 客户端批量取消或批量修改。
+- FBA/海外目的仓、库存、库位、货架及入出库等 WMS 作业。
+- 将旧架构文档中的 11 个微服务直接作为一期落地方案。
+
+原型中的 FBA 批量下单、渠道、商检、退税和复杂货物属性作为后续扩展依据,不进入一期最小闭环的必填字段。
+
+## 三、参与者与数据边界
+
+| 参与者 | 数据范围 | 主要操作 |
+|---|---|---|
+| 企业成员 | 当前租户订单 | 查看列表与详情 |
+| 企业订单操作员 | 当前租户订单 | 创建、编辑草稿、提交、取消 |
+| 企业管理员 | 当前租户订单 | 拥有企业端全部订单权限 |
+| 平台运营 | 获授权数据范围内订单 | 审核、人工修改、受理、分配负责人 |
+| 平台操作员 | 获授权数据范围内订单 | 订舱、更新运输状态与处理说明 |
+| 平台超级管理员 | 全部订单 | 平台端全部订单操作 |
+
+服务端必须从已验证身份中取得租户上下文。客户端传入的 `tenantId`、`customerId` 或查询参数不能作为授权依据。
+
+企业客户端菜单和操作权限由企业管理员为本企业角色分配。一个成员可拥有多个角色,权限取角色权限并集;一期不引入部门或组织架构,成员直接归属企业。企业管理员不能配置平台后台菜单,也不能跨企业授权。
+
+客户读取、更新、提交和取消订单时,服务端必须同时匹配订单 ID、当前租户 ID 和删除标记;不允许先按全局 ID 查出订单后再仅依赖前端隐藏。
+
+平台国内收货仓由后台统一维护,企业客户只读选择。停用仓库不得用于新建或重新提交订单,但不能破坏历史订单已经保存的仓库名称;一期首批覆盖义乌、深圳、青岛、上海、宁波和厦门,不将其与 FBA/海外目的仓混为同一模型。
+
+快递公司和往来单位均由当前平台后台人员维护。企业客户端不提供对应的新增、编辑、启停菜单和写接口:快递公司只通过订单详情展示,往来单位只用于下单时只读查询和选择。服务端必须按后台人员权限和数据范围校验写操作,并按当前企业可见范围过滤客户端往来单位查询,不能依赖前端隐藏按钮实现边界。
+
+## 四、一期订单状态
+
+### 已确认的统一状态
+
+| 稳定编码 | 中文名称 | 含义 |
+|---|---|---|
+| `DRAFT` | 草稿 | 客户尚未提交,可继续编辑 |
+| `PENDING_REVIEW` | 待审核 | 客户已提交,等待平台审核 |
+| `ACCEPTED` | 已受理 | 平台审核通过并进入履约准备 |
+| `BOOKED` | 已订舱 | 已完成舱位或对应运输资源确认 |
+| `IN_TRANSIT` | 运输中 | 货物已进入运输过程 |
+| `COMPLETED` | 已完成 | 一期订单履约结束 |
+| `CANCELLED` | 已取消 | 客户或平台按规则取消 |
+
+该方案与当前管理后台实现最接近。`packages/shared` 现有“处理中”以及旧架构文档中的“已确认、已报关、到港待提”不作为一期并存状态;产品确认后统一迁移。
+
+### 允许的状态转换
+
+```text
+草稿 ──客户提交──> 待审核 ──平台受理──> 已受理 ──平台订舱──> 已订舱
+ │ │ │
+ └──客户取消──> 已取消 ├──后台人工修改/联系客户修改──> 待审核 │
+ └──客户取消申请/平台取消──> 已取消 └──发运──> 运输中 ──完成──> 已完成
+```
+
+- 草稿可由客户编辑、提交或取消。
+- 待审核订单允许获授权的后台人员人工修改;平台无法直接确认的信息由平台联系客户修改。客户和后台修改后订单仍保持待审核,修改前后值、操作者和时间必须写入审计记录。
+- 已受理后取消可能已经产生成本,一期默认仅平台可执行;客户只能联系平台处理。
+- 已订舱、运输中和已完成不允许客户取消。
+- 已取消和已完成为终态,不允许直接恢复。
+- 所有状态变更必须校验当前状态,不能由前端提交任意目标状态。
+
+## 五、一期数据模型
+
+### 企业资料审核状态
+
+企业账号状态与企业资料审核状态分离:注册成功即可创建账号和登录,不能用禁用账号或注册待审核状态代替下单资格。企业资料至少保存 `verificationStatus`(`UNSUBMITTED`、`PENDING`、`APPROVED`)、`submittedAt`、`approvedAt`、`approvedBy` 和资料版本;只有 `APPROVED` 可提交订单。资料提交、修改和审核通过均写入审计记录。
+
+### 订单主信息
+
+| 字段 | 必填阶段 | 说明 |
+|---|---|---|
+| `id` | 服务端生成 | 内部稳定 ID,不承载租户信息 |
+| `orderNo` | 提交时生成 | 客户可见业务单号;租户内和平台范围均应唯一 |
+| `tenantId` | 服务端注入 | 不接受客户指定 |
+| `referenceNo` | 可选 | 客户内部参考号;建议租户内非强制唯一 |
+| `receivingWarehouseId` | 提交必填 | 平台国内收货仓 ID;提交时必须存在且处于启用状态 |
+| `receivingWarehouseName` | 服务端保存 | 下单时仓库名称冗余,兼容列表和旧消费者 |
+| `receivingWarehouseSnapshot` | 服务端保存 | 下单时仓库展示快照,至少包含 ID、编码、名称、省、市和详细地址 |
+| `shipperCounterpartyId` | 提交必填 | 后台维护的启用发货单位 ID;服务端按当前数据范围校验 |
+| `shipperSnapshot` | 服务端保存 | 下单时发货单位名称、联系人、电话和地址快照 |
+| `consigneeCounterpartyId` | 提交必填 | 后台维护的启用收货单位 ID;服务端按当前数据范围校验 |
+| `consigneeSnapshot` | 服务端保存 | 下单时收货单位名称、联系人、电话和地址快照 |
+| `deliveryInfo` | 平台维护 | 可选履约信息,包含快递公司 ID/快照和快递单号;企业客户端只读 |
+| `transportMode` | 提交必填 | FCL、LCL、AIR、ROAD |
+| `businessType` | 提交必填 | 一期支持 EXPORT、IMPORT |
+| `origin` | 提交必填 | 起运地或起运港 |
+| `destination` | 提交必填 | 目的地或目的港 |
+| `expectedDepartureDate` | 可选 | 客户期望出发日期,不等同于平台确认 ETD |
+| `etd`、`eta` | 平台维护 | 平台受理后的预计节点 |
+| `priority` | 可选 | NORMAL、URGENT、EXPEDITED,默认 NORMAL |
+| `customerRemark` | 可选 | 客户和平台均可见 |
+| `internalRemark` | 可选 | 仅平台可见,不得返回客户接口 |
+| `operatorId` | 平台维护 | 负责人内部用户 ID |
+| `status` | 服务端维护 | 使用稳定英文编码 |
+| `version` | 服务端维护 | 乐观锁版本,防止覆盖并发修改 |
+| `createdBy`、`createdAt`、`updatedAt` | 服务端维护 | 审计信息 |
+
+订单金额不由客户创建接口提交。一期若后台继续展示金额,应标记为平台估算字段,并在报价/结算范围确认后单独设计。
+
+### 平台收货仓
+
+| 字段 | 说明 |
+|---|---|
+| `id` | 服务端稳定 ID |
+| `code` | 平台内唯一仓库编码,统一大写 |
+| `name` | 客户可见仓库名称 |
+| `province`、`city`、`address` | 国内收货地址 |
+| `contactName`、`contactPhone` | 收货联系信息 |
+| `businessHours` | 收货时间说明 |
+| `status` | `ACTIVE` 或 `INACTIVE` |
+| `remark`、`updatedAt` | 运营说明和更新时间 |
+
+订单只持有仓库 ID 与不可编辑的必要展示快照,不复制联系人、电话、营业时间、运营备注等会持续维护的完整仓库档案。快照字段为 `id`、`code`、`name`、`province`、`city`、`address`;订单详情优先读取快照,不能回查当前仓库主数据覆盖历史值。真实服务端接入后,创建和提交均需重新校验仓库可用性,并在同一事务中持久化快照,不能只依赖客户端下拉选项。
+
+### 快递公司
+
+| 字段 | 说明 |
+|---|---|
+| `id` | 服务端稳定 ID |
+| `code` | 平台内唯一稳定编码 |
+| `name` | 快递公司名称 |
+| `customerServicePhone` | 客服电话,可选 |
+| `trackingUrl` | 官方查询网址,可选 |
+| `status` | `ACTIVE` 或 `INACTIVE` |
+| `remark`、`updatedAt` | 后台说明和更新时间 |
+
+快递公司只能由获授权的后台人员维护。停用后不得新增到订单履约信息,但历史订单继续展示保存的快递公司名称和编码。企业客户端不直接查询快递公司主数据,只通过订单详情响应读取后台已保存的履约信息。一期不接快递轨迹订阅和自动回传;一个订单只支持一组快递公司与快递单号,多包裹和多段运输后续扩展。
+
+### 往来单位
+
+| 字段 | 说明 |
+|---|---|
+| `id` | 服务端稳定 ID |
+| `code` | 所属数据范围内唯一编码 |
+| `name` | 单位名称 |
+| `types` | 可多选的稳定单位类型集合;一期覆盖供应商、客户、承运商、报关行、发货单位和收货单位 |
+| `contactName`、`contactPhone`、`email` | 主要联系人信息 |
+| `country`、`province`、`city`、`postalCode`、`address` | 主要地址信息 |
+| `status` | `ACTIVE` 或 `INACTIVE` |
+| `dataScopeId` | 所属业务数据范围,由服务端维护 |
+| `remark`、`updatedAt` | 后台说明和更新时间 |
+
+往来单位只能由获授权的后台人员维护,企业客户端只读查询当前可见且已启用的发货单位和收货单位。单位类型使用稳定编码,同一单位允许拥有供应商、客户、承运商、报关行、发货单位、收货单位中的多个类型。数据按所属业务主体隔离,后台人员只能在授权范围维护和查看。订单提交时服务端重新校验单位类型、启用状态和数据范围,并保存发货方、收货方快照;主数据后续改名、改地址或停用不得覆盖历史订单。订单内允许调整本单快照,但不得反向修改往来单位档案。
+
+### 基础资料批量导入
+
+一期确认支持后台批量导入快递公司和往来单位,企业客户端不提供导入入口。平台提供版本化的 `.xlsx` 标准模板;后台人员上传后,服务端先完成整批校验,存在任一错误时不写入业务表,并返回包含行号、字段和原因的错误报告。
+
+导入至少校验必填字段、稳定编码、名称、单位类型、联系方式、地址、数据范围和启停值;同一文件内重复、与现有档案重复或越过操作人数据范围的记录必须拒绝,不得静默覆盖已有档案。一期批量导入只新增,不更新或覆盖已有档案;任一记录失败时整批不写入。每次导入记录操作人、原始文件名、总行数、成功/失败数量、失败原因摘要和服务端时间。文件大小和最大行数使用服务端可配置上限;快递公司和往来单位导出不纳入一期。
+
+### 货物明细
+
+| 字段 | 必填 | 说明 |
+|---|---|---|
+| `id` | 服务端生成 | 明细 ID |
+| `lineNo` | 是 | 订单内序号 |
+| `sku` | 否 | 客户 SKU |
+| `cargoNameCn` | 是 | 中文品名 |
+| `cargoNameEn` | 否 | 英文品名 |
+| `pieces` | 是 | 件数,正整数 |
+| `packageCount` | 否 | 箱数/包装数,非负整数 |
+| `grossWeightKg` | 是 | 毛重,必须大于 0 |
+| `volumeCbm` | 是 | 体积,必须大于 0 |
+| `containerType` | FCL 时必填 | 20GP、40GP、40HQ 等 |
+| `containerCount` | FCL 时必填 | 柜量,正整数 |
+| `remark` | 否 | 客户可见备注 |
+
+主表中的总件数、总重量、总体积应由服务端根据明细汇总,不接受客户端独立提交两套可能冲突的合计。
+
+### 时间线
+
+每次提交、待审核订单修改、受理、状态变化、取消和负责人变化均写入不可由客户端编辑的时间线:
+
+- 事件类型和事件标题;
+- 变更前后状态;
+- 操作说明、修改摘要或取消原因;
+- 操作者 ID、名称和操作者类型;
+- 服务端发生时间;
+- 请求关联 ID,便于审计和排错。
+
+## 六、接口草案
+
+统一前缀暂用 `/api/v1`。具体服务拆分不影响浏览器端契约。
+
+### 客户端接口
+
+| 方法 | 路径 | 权限编码 | 说明 |
+|---|---|---|---|
+| `GET` | `/api/v1/client/first-leg-orders` | `order:first-leg:list` | 当前租户订单分页列表 |
+| `POST` | `/api/v1/client/first-leg-orders` | `order:first-leg:create` | 创建草稿 |
+| `GET` | `/api/v1/client/first-leg-orders/{id}` | `order:first-leg:view` | 当前租户订单详情 |
+| `PUT` | `/api/v1/client/first-leg-orders/{id}` | `order:first-leg:update` | 编辑草稿;平台联系客户后可修改本企业待审核订单,状态保持待审核并记录审计 |
+| `POST` | `/api/v1/client/first-leg-orders/{id}/submit` | `order:first-leg:submit` | 幂等提交草稿;提交前强制校验企业资料审核已通过 |
+| `POST` | `/api/v1/client/first-leg-orders/{id}/cancel` | `order:first-leg:cancel` | 按状态规则取消 |
+| `GET` | `/api/v1/client/platform-receiving-warehouses` | 登录用户 | 查询客户端可选择的启用收货仓 |
+| `GET` | `/api/v1/client/counterparties` | 登录用户 | 按当前数据范围只读查询已启用的发货单位和收货单位 |
+| `GET` | `/api/v1/client/me` | 登录用户 | 查询当前成员的用户名、姓名、手机、邮箱、微信和所属公司 |
+| `PUT` | `/api/v1/client/me` | 登录用户 | 更新真实姓名、手机、邮箱和微信;用户名与所属公司不可修改 |
+| `POST` | `/api/v1/client/me/password` | 登录用户 | 校验当前密码后修改密码并记录安全审计 |
+| `GET` | `/api/v1/client/company-profile` | `company:profile:view` | 查询当前企业基本信息、法人信息、联系信息和地址 |
+| `PUT` | `/api/v1/client/company-profile` | `company:profile:write` | 按企业权限更新允许维护的公司信息 |
+| `GET` | `/api/v1/client/company-qualifications` | `company:qualification:view` | 查询资质文件类型、状态、有效期和安全访问地址 |
+| `POST` | `/api/v1/client/company-qualifications` | `company:qualification:write` | 上传或更新企业资质文件 |
+
+### 管理后台接口
+
+| 方法 | 路径 | 权限编码 | 说明 |
+|---|---|---|---|
+| `GET` | `/api/v1/admin/first-leg-orders` | `first-leg:list` | 按平台数据范围查询 |
+| `POST` | `/api/v1/admin/first-leg-orders` | `first-leg:create` | 平台代客创建订单 |
+| `GET` | `/api/v1/admin/first-leg-orders/{id}` | `first-leg:list` | 订单完整详情,含内部信息 |
+| `PUT` | `/api/v1/admin/first-leg-orders/{id}` | `first-leg:update` | 按状态规则维护订单 |
+| `POST` | `/api/v1/admin/first-leg-orders/{id}/accept` | `first-leg:status` | 受理并可分配负责人 |
+| `POST` | `/api/v1/admin/first-leg-orders/{id}/assign` | `first-leg:assign` | 分配负责人 |
+| `POST` | `/api/v1/admin/first-leg-orders/{id}/transition` | `first-leg:status` | 执行服务端允许的后续状态转换 |
+| `POST` | `/api/v1/admin/first-leg-orders/{id}/cancel` | `first-leg:status` | 平台取消,原因必填 |
+| `GET` | `/api/v1/admin/company-verifications` | `company:verification:list` | 查询企业资料审核状态和待审核企业 |
+| `GET` | `/api/v1/admin/company-verifications/{companyId}` | `company:verification:list` | 查看企业资料与资质详情 |
+| `POST` | `/api/v1/admin/company-verifications/{companyId}/approve` | `company:verification:approve` | 人工点击审核通过并开通下单资格;一期无驳回动作 |
+| `GET` | `/api/v1/admin/platform-receiving-warehouses` | `warehouse:list` | 分页查询全部平台收货仓 |
+| `POST` | `/api/v1/admin/platform-receiving-warehouses` | `warehouse:write` | 新增平台收货仓 |
+| `PUT` | `/api/v1/admin/platform-receiving-warehouses/{id}` | `warehouse:write` | 编辑平台收货仓 |
+| `POST` | `/api/v1/admin/platform-receiving-warehouses/{id}/status` | `warehouse:write` | 启用或停用收货仓 |
+| `GET` | `/api/v1/admin/express-companies` | `express-company:list` | 分页查询快递公司 |
+| `POST` | `/api/v1/admin/express-companies` | `express-company:write` | 新增快递公司 |
+| `PUT` | `/api/v1/admin/express-companies/{id}` | `express-company:write` | 编辑快递公司 |
+| `POST` | `/api/v1/admin/express-companies/{id}/status` | `express-company:write` | 启用或停用快递公司 |
+| `POST` | `/api/v1/admin/express-companies/import` | `express-company:import` | 使用标准模板批量导入快递公司,整批校验后提交 |
+| `GET` | `/api/v1/admin/counterparties` | `counterparty:list` | 按授权数据范围分页查询往来单位 |
+| `POST` | `/api/v1/admin/counterparties` | `counterparty:write` | 在授权数据范围内新增往来单位 |
+| `PUT` | `/api/v1/admin/counterparties/{id}` | `counterparty:write` | 编辑往来单位 |
+| `POST` | `/api/v1/admin/counterparties/{id}/status` | `counterparty:write` | 启用或停用往来单位 |
+| `POST` | `/api/v1/admin/counterparties/import` | `counterparty:import` | 在授权数据范围内使用标准模板批量导入往来单位 |
+| `PUT` | `/api/v1/admin/first-leg-orders/{id}/delivery-info` | `first-leg:update` | 后台维护快递公司和快递单号 |
+
+一期不使用通用的“传任意目标状态”接口替代状态动作。服务端根据当前状态、动作、操作者和权限决定目标状态。
+
+### 请求一致性
+
+- 创建和提交接口接受 `Idempotency-Key`,服务端按租户、用户、接口和键去重。
+- 更新请求携带 `version`;版本不一致返回冲突,不静默覆盖。
+- 提交和状态动作在同一事务内更新订单、版本和时间线。
+- 分页参数统一为 `page`、`pageSize`,并设置服务端最大页容量。
+- API 响应继续采用仓库已有 `ApiResponse` 外层结构;错误码需在后端设计时统一补充。
+
+## 七、页面范围
+
+### 我的信息
+
+按客户端原型提供“基本信息”和“修改密码”两个页签。基本信息展示用户名、真实姓名、手机号、邮箱、微信和所属公司,支持进入编辑、保存与取消;用户名和所属公司始终只读,真实姓名、手机号、邮箱和微信允许按权限编辑。修改密码要求当前密码、新密码和确认密码,覆盖强度校验、两次输入不一致、错误反馈、重复提交防护及成功后的会话处理。
+
+### 公司信息
+
+按客户端原型提供“企业基本信息、联系信息、资质文件”三个页签。基本信息覆盖公司名称、统一信用代码、企业类型、注册地、成立日期、注册资本、法人姓名和法人电话;联系信息覆盖联系人、手机、邮箱、微信和地址;资质文件展示文件类型、验证状态、有效期、上传时间,并支持查看、下载及获授权用户更新。企业数据只能读取当前企业,服务端根据企业角色控制可编辑字段和资质操作。注册不审核;企业资料未审核通过时可继续登录、查看和补充资料,但创建页必须显示下单资格提示,提交订单接口必须拒绝并返回可识别错误码。
+
+### 客户工作台
+
+订单列表包含订单号、参考号、运输方式、起运地、目的地、状态、负责人、预计时间和更新时间;支持关键词、状态、运输方式和创建日期筛选。
+
+创建页按以下顺序组织:
+
+1. 运输信息和平台收货仓;
+2. 从后台维护的往来单位中选择发货方和收货方;
+3. 货物明细;
+4. 客户备注;
+5. 保存草稿或提交审核;提交前校验企业资料已经平台人工审核通过。
+
+详情页展示订单摘要、发货方/收货方快照、货物明细、服务端时间线、履约快递公司、快递单号和当前可用操作。内部备注、成本和平台内部操作信息不得进入客户响应;企业客户端不能修改快递信息或往来单位档案。
+
+### 管理后台
+
+新增企业资料审核、平台收货仓、快递公司和往来单位管理。企业资料审核只有“审核通过”,资料不正确时由平台联系客户修改;基础资料页面支持列表筛选、新增、编辑和启停,并由 RBAC 与数据范围控制。快递公司、往来单位页面沿用 `docs/悦` 原型的信息层级和主要字段,但使用当前后台视觉体系和交互组件重新实现;一期实现标准模板下载、文件上传、校验结果和错误报告,不提供导出入口。保留当前订单列表和详情方向,将自由状态下拉改为服务端返回的可用动作;补充待审核订单人工修改、受理、分配、订舱、发运、完成、取消和履约快递信息维护动作,不提供驳回入口。
+
+## 八、测试与验收
+
+- 租户 A 无法读取、更新、提交或取消租户 B 的订单。
+- 草稿可以反复保存,提交请求重复发送只产生一次状态变化。
+- 待审核订单仅允许当前企业获授权成员或获授权平台人员修改核心业务字段,修改后状态保持待审核且必须完整留痕;其他非草稿状态禁止修改。
+- 服务端拒绝非法状态跳转和缺少权限的状态动作。
+- 并发修改返回明确冲突,客户端保留用户输入并支持重新加载。
+- 客户接口永不返回内部备注、成本或不必要的人员信息。
+- 列表覆盖加载、空数据、失败、无权限和分页边界。
+- 创建页覆盖校验错误、提交中、重复点击、失败恢复和离开未保存提示。
+- 管理后台覆盖待审核订单人工修改、联系客户修改后的并发冲突、受理、负责人失效及状态变更失败,并确认无驳回入口和接口。
+- 仓库编码必须唯一;停用仓库不出现在客户新建订单选项中,仓库改名、改地址或停用后,历史订单仍展示下单时的编码、名称和地址快照。
+- 企业客户端无法调用快递公司或往来单位写接口,也不显示维护入口;伪造请求必须由服务端拒绝。
+- 往来单位查询只返回当前企业可见且已启用的发货单位和收货单位;跨数据范围 ID 在保存草稿和提交时均被拒绝。
+- 往来单位改名、改地址或停用后,历史订单继续展示下单时快照;停用单位不能用于新订单提交。
+- 快递公司编码和名称满足唯一规则;停用公司不能新增到履约信息,历史订单继续展示已保存快照。
+- 客户端订单详情只读展示快递公司和快递单号,接口不得接受客户修改履约快递信息。
+- 我的信息只能读取当前登录成员;修改所属公司或其他成员资料的伪造请求必须拒绝,修改密码必须校验当前密码并写入安全审计。
+- 注册成功后无需审核即可登录;公司信息只返回当前企业数据,未通过企业资料审核时服务端拒绝提交订单,审核通过后允许提交。普通成员无写权限时仍可按授权查看,资质文件下载使用受控地址并覆盖过期、缺失、上传失败和无权限状态。
+- 快递公司和往来单位批量导入仅允许具备对应导入权限的后台人员调用;企业客户端和普通写权限不能绕过独立导入权限。
+- 导入文件覆盖模板版本、空文件、超限文件、缺列、类型错误、重复编码、跨数据范围和恶意文件名;任一行失败时业务数据不发生部分写入,并可下载逐行错误报告。
+
+## 九、实施顺序
+
+1. 将已确认的注册、企业资料审核、订单修改和基础资料规则冻结为接口契约。
+2. 将稳定订单状态、企业资料审核状态、运输方式、基础资料和订单快照模型统一到 `packages/shared`。
+3. 在 `services/api` 初始化后定义企业资料审核、订单、收货仓、快递公司和往来单位 OpenAPI,并以服务端状态机和权限校验作为唯一业务规则来源。
+4. 实现后台基础资料维护、快递公司/往来单位批量导入和企业客户端往来单位只读查询。
+5. 实现客户工作台订单列表、创建和详情页面,静态阶段通过 API 适配层提供可替换数据源。
+6. 将管理后台订单 Pinia 模拟操作迁移到同一 API 契约,并接入履约快递信息。
+7. 增加跨租户、状态机、幂等、基础资料越权和前端业务流程测试。
+
+## 十、已确认实施决策
+
+以下决策于 2026-07-28 至 2026-07-29 确认:
+
+1. 采用“草稿、待审核、已受理、已订舱、运输中、已完成、已取消”七个一期状态,不设置“已驳回”。
+2. 待审核订单无驳回操作;信息有误时由后台人工修改,或由平台联系客户修改,订单保持待审核并完整记录修改审计。
+3. 已受理后客户不能直接取消,一期由客户联系平台并由平台执行取消。
+4. 保留平台代客户创建订单的能力。
+5. 一期使用本设计的精简必填字段;FBA 批量下单、渠道、商检和退税后续扩展。
+6. 快递公司和往来单位均由当前平台后台人员维护;企业客户端不提供维护入口和写接口,仅按权限只读使用。
+7. 一期包含快递公司、往来单位标准模板批量导入,不包含对应导出功能。
+8. 一期客户端包含我的信息和公司信息,范围以 `docs/悦/头程下单/柏悦客户端.html` 原型为基准并接入真实权限与接口。
+9. 企业注册不需要审核,注册成功即可登录;提交订单前必须提交企业资料并由平台人工点击审核通过。
+10. 一期支持一个用户拥有多个角色,权限取角色权限并集。
+11. 往来单位按所属业务主体隔离并支持一个单位拥有多个稳定编码类型;一期类型覆盖供应商、客户、承运商、报关行、发货单位和收货单位。
+12. 一个订单一期只支持一组快递公司和快递单号。
+13. 快递公司、往来单位批量导入一期只新增,不更新或覆盖已有档案;重复或任一行错误时整批失败。
+14. “我的信息”中的用户名只读,不允许修改。
+15. 企业客户端菜单和操作权限由企业管理员为本企业角色分配,一期不做部门/组织架构。
+16. 企业注册一期不接短信或邮箱验证码,只做基础字段、密码和账号重复校验。
+17. 一期仅支持中文账号密码登录,不做多语言、微信和企业微信登录。
diff --git a/一期/一期开发进度表.md b/一期/一期开发进度表.md
new file mode 100644
index 0000000..dea8952
--- /dev/null
+++ b/一期/一期开发进度表.md
@@ -0,0 +1,312 @@
+# 虫虫出海一期开发进度表
+
+> 创建日期:2026-07-27
+> 更新日期:2026-07-30
+> 当前阶段:一期双端持续浏览器联调;Client 一期核心静态页面与路由已完成(静态完成度 100%)。后端 2026-07-30 业务成熟度回归已确认认证、个人资料、成员、角色、仓库、往来单位、订单草稿和履约快递能力通过真实 API 检查;前端已继续接入个人资料、修改密码、成员完整维护、角色权限回显/保存和商户往来单位候选,仍需完成关键写操作、资质图片及 Admin 目标租户订单的人工浏览器验收
+> 总体状态:开发中
+
+头程订单一期闭环范围与接口草案见 `一期头程订单闭环设计.md`。
+
+## 原型依据与进度口径
+
+- 一期产品原型统一以 `docs/悦/` 为依据;企业登录、注册页面分别来源于 `docs/悦/合并/login.html`、`docs/悦/合并/register.html`,快递公司、往来单位页面来源为 `docs/悦/货代SAAS平台后台/货代SaaS平台原型.html`。
+- 登录原型包含邮箱/手机号、密码、记住我、忘记密码提示和其他登录方式占位;注册原型包含企业名称、联系人、邮箱、手机号、8–20 位密码及服务协议/隐私政策确认。
+- 一期只做中文账号密码登录和基础企业注册闭环,不接短信/邮箱验证码、微信/企业微信登录及多语言;独立找回密码和工作台也不纳入一期。
+- 原型已经包含“通用 → 快递公司 / 往来单位”菜单、列表、筛选、状态、操作按钮和演示数据,可作为字段、布局和交互方向参考。
+- 原型中的新增、编辑、详情、查询、导入和导出多数仅有静态入口或表格渲染,不等同于 `apps/admin-web`、`apps/client-web` 已完成开发。
+- 进度表将“原型核对”和“Vue 工程实现”分开统计:原型核对可标记完成,未进入当前 Vue 应用的页面、状态管理、权限和测试仍按待开始或 0% 记录。
+- Client 静态页面完成度与接口联调完成度分开统计:当前一期客户端路由均已落到正式页面,无在用占位页,静态页面完成度为 100%;各任务百分比继续反映真实接口、数据和验收进度。
+- 一期权限与业务边界以本目录文档为准;旧原型中的租户角色、FBA、海外仓和 WMS 菜单不自动纳入一期。
+
+## 一、一期目标
+
+一期完成两个端的基础业务闭环:
+
+- 平台后台:内部账号登录、客户与企业资料审核、内部用户、角色、权限和头程订单管理;工作台不作为一期交付项。
+- 企业客户端:用户名加密码登录、免审核企业注册、企业资料、企业成员、角色、菜单及权限管理;企业资料审核通过后才可提交订单。
+- 头程订单:提供客户端下单和订单查询能力,形成前后台业务闭环。
+- 平台收货仓:平台统一维护国内收货仓,客户端下单时选择已启用仓库并保存仓库 ID、编码、名称和地址快照。
+- 快递公司:当前平台后台人员统一维护快递公司档案,企业客户端不维护;订单履约时记录快递公司与快递单号。
+- 往来单位:当前平台后台人员维护发货单位、收货单位、供应商和服务商,企业客户端只读选择并在头程订单中保存快照。
+
+一期基础资料范围包括平台收货仓、快递公司和往来单位。仓库能力限定为义乌、深圳、青岛、上海、宁波、厦门等国内收货仓的档案、启停、查询和订单关联,不包含 FBA/海外目的仓、库存、库位、货架、入库、出库、盘点等 WMS 作业;快递能力不包含轨迹订阅和自动回传。
+
+权限边界暂按以下模型设计:
+
+- 平台后台 RBAC:平台内部员工使用,管理所有企业和订单。
+- 企业客户端 RBAC:企业管理员使用,只管理本企业的成员、角色和权限。
+- 企业之间按 `tenant_id` 隔离,客户端用户不能访问其他企业数据。
+- 快递公司和往来单位的新增、编辑、启停仅开放给获授权的后台人员;企业客户端不提供维护入口和写接口。
+
+## 二、总体进度
+
+| 模块 | 范围 | 状态 | 进度 | 计划开始 | 计划完成 | 负责人 | 备注 |
+|---|---|---|---:|---|---|---|---|
+| 基础工程 | 前后端工程、数据库、环境、接口规范 | 进行中 | 55% | 2026-07-27 | 待排期 | 待分配 | 双端统一响应、Token 会话和 Gateway 代理已接入;订单与基础资料契约仍待补齐 |
+| 后台客户管理 | 客户档案、企业资料审核、启停和资料维护 | 联调中 | 82% | 2026-07-27 | 待排期 | 待分配 | 客户档案仍使用 Pinia 模拟数据;企业审核已接真实待审、租户资质、鉴权文件预览及审核接口 |
+| 后台管理 | 内部用户、角色、权限 | 进行中 | 70% | 2026-07-27 | 待排期 | 待分配 | RBAC 前端交互已完成,等待接口与真实鉴权 |
+| 后台头程订单 | 订单列表、详情、处理和状态流转 | 进行中 | 70% | 2026-07-27 | 待排期 | 待分配 | 前端创建、查询、详情、指派及状态处理已完成 |
+| 平台收货仓 | 平台维护国内收货仓;客户端选择启用仓库 | 联调中 | 80% | 2026-07-28 | 待排期 | 待分配 | 客户端仓库分页、启用过滤、空态禁建和订单快照已接真实 API;当前返回 0 条,后台维护接口与持久化仍待联调 |
+| 快递公司维护 | 平台后台维护快递公司档案、启停、批量导入及订单履约信息关联 | 进行中 | 75% | 2026-07-28 | 待排期 | 待分配 | 原型字段核对与 Vue 静态实现均已完成;维护、权限、标准模板、整批校验和订单单组履约信息可验收,等待业务 API |
+| 往来单位维护 | 平台后台维护发货单位、收货单位、供应商、服务商档案、批量导入及订单引用 | 进行中 | 75% | 2026-07-28 | 待排期 | 待分配 | 原型核对与 Vue 静态实现分别完成;六类多选、联系人、完整地址、启停、模板下载和文件基础检查可验收,工作表解析与整批导入等待后端 API |
+| 登录注册与客户入驻 | Admin 登录、企业端免审核注册、我的信息、公司信息及企业资料审核 | 联调中 | 85% | 2026-07-27 | 待排期 | 待分配 | Client 已接真实注册登录、退出、刷新令牌、企业资料编辑与营业执照鉴权预览;接口曾完成基础实测,当前局域网 Gateway 请求超时,待恢复后完成浏览器验收 |
+| 客户端权限体系 | 企业成员、菜单、角色、权限 | 联调中 | 82% | 2026-07-28 | 待排期 | 待分配 | 已接角色列表/新增和成员列表;授权写接口为全量替换,但缺少已有权限 ID 与已有角色 ID 回显,暂保持只读 |
+| 客户端头程订单 | 下单、列表、详情、平台收货仓及往来单位只读选择 | 联调中 | 85% | 2026-07-28 | 待排期 | 待分配 | 列表、详情、创建/编辑草稿和提交已接真实 API;待审核企业可存草稿但不能提交,往来单位接口、有效仓库种子数据、真实写入和服务端重验仍待完成 |
+| 联调与上线 | 测试、验收、部署、初始化数据 | 待开始 | 0% | 待排期 | 待排期 | 待分配 | 一期发布 |
+
+## 三、详细任务表
+
+| ID | 端 | 模块 | 功能/交付内容 | 优先级 | 状态 | 进度 | 依赖 | 负责人 | 备注 |
+|---|---|---|---|---|---|---:|---|---|---|
+| BASE-01 | 公共 | 工程初始化 | 创建后台前端、客户端前端和后端工程,区分开发/测试/生产环境 | P0 | 进行中 | 70% | - | 待分配 | admin/client 已独立安装与构建,API 工程待初始化 |
+| BASE-02 | 公共 | 数据库 | 用户、企业、企业资料审核、成员、角色、菜单、权限、订单、仓库等核心表设计 | P0 | 待开始 | 0% | BASE-01 | 待分配 | 企业资料审核状态与注册账号状态分离;仓库主数据与订单仓库快照分离 |
+| BASE-03 | 公共 | 认证 | Admin 与企业端登录、退出、Token、密码加密、登录状态和接口鉴权 | P0 | 联调中 | 55% | BASE-02 | 待分配 | Client 已接真实登录/退出、Access/Refresh Token、MERCHANT 身份校验、并发 401 单次刷新;2026-07-30 Gateway/Auth 登录均出现 503,待后端恢复服务发现后验收 |
+| BASE-04 | 公共 | 通用能力 | 统一响应、错误码、分页、操作日志、文件上传 | P0 | 进行中 | 25% | BASE-01 | 待分配 | Client 已实现 code 字符串响应解包、字段错误模型、常见网络错误和 multipart 营业执照上传;分页与日志待接入 |
+| BASE-05 | 公共 | 接口文档 | 输出并维护一期 API 文档 | P0 | 待开始 | 0% | BASE-01 | 待分配 | 建议使用 OpenAPI;同步企业资料审核、下单资格、仓库、快递公司、往来单位与订单快照契约 |
+| ADM-AUTH-01 | 后台 | 登录认证 | 平台内部员工账号密码登录、退出、登录回跳、路由守卫和无权限跳转 | P0 | 进行中 | 70% | BASE-03 | 待分配 | 已接 `/api/auth/**` 与 `/api/platform/v1/iam/permissions`,校验 PLATFORM 身份并按 JWT 与启用权限资源交集授权;等待 Gateway/Nacos 路由恢复后完成真实环境验收 |
+| ADM-CUSTOMER-01 | 后台 | 客户管理 | 客户列表、搜索、分页、详情、新增、编辑和启停 | P0 | 进行中 | 70% | BASE-03 | 待分配 | 前端已完成并通过浏览器验收,等待接口联调 |
+| ADM-CUSTOMER-02 | 后台 | 客户管理 | 查看企业资料和资质,人工点击审核通过并维护下单资格 | P0 | 联调中 | 82% | ADM-CUSTOMER-01、CLI-PROFILE-02 | 待分配 | 独立审核页已接 IAM 待审列表、按租户资质查询、平台 Token 文件预览、通过与驳回接口;待使用真实待审记录验证完整写操作 |
+| ADM-USER-01 | 后台 | 内部用户 | 用户列表、搜索、分页和详情 | P0 | 进行中 | 70% | BASE-03 | 待分配 | 前端列表、筛选和分页已完成 |
+| ADM-USER-02 | 后台 | 内部用户 | 新增、编辑、启停、重置密码 | P0 | 进行中 | 65% | ADM-USER-01 | 待分配 | 前端交互已完成,操作日志与接口待接入 |
+| ADM-USER-03 | 后台 | 内部用户 | 给用户分配一个或多个角色 | P0 | 进行中 | 75% | ADM-ROLE-01 | 待分配 | 多角色选择与回显已完成 |
+| ADM-ROLE-01 | 后台 | 角色 | 角色列表、新增、编辑、删除、启停 | P0 | 联调中 | 82% | BASE-03 | 待分配 | 平台角色列表与新增已接 `/api/platform/v1/iam/roles`;编辑、删除、启停接口未提供,真实会话中明确禁用且不回退模拟写入 |
+| ADM-ROLE-02 | 后台 | 角色 | 给角色分配菜单和操作权限 | P0 | 已阻塞 | 75% | ADM-PERM-01 | 待分配 | 写接口是全量替换,但缺少角色当前 `permissionIds` 回显;真实会话暂不开放保存,避免清空已有授权 |
+| ADM-PERM-01 | 后台 | 权限 | 菜单树、页面权限、按钮权限和接口权限模型 | P0 | 联调中 | 88% | BASE-02 | 待分配 | `GET/POST /api/platform/v1/iam/permissions` 已接入;真实模式只创建 `MENU/BUTTON`,编辑和启停接口待补 |
+| ADM-PERM-02 | 后台 | 权限 | 登录后返回当前用户菜单和权限集合 | P0 | 联调中 | 80% | ADM-PERM-01 | 待分配 | 已实现 JWT 权限与 IAM 启用资源取交集、动态菜单和会话恢复;待 Gateway 恢复后复验权限变更后的 Token 刷新 |
+| ADM-PERM-03 | 后台 | 权限 | 未授权页面、按钮隐藏和接口拒绝访问 | P0 | 联调中 | 65% | ADM-PERM-02 | 待分配 | 前端路由、菜单和主要按钮已按稳定权限码控制;后端文档确认方法级按钮权限尚未覆盖所有管理接口 |
+| ADM-ORDER-01 | 后台 | 头程订单 | 订单列表、组合查询、分页和导出 | P0 | 进行中 | 70% | BASE-03 | 待分配 | 前端组合筛选、分页、选择与导出反馈已完成 |
+| ADM-ORDER-02 | 后台 | 头程订单 | 订单详情、货物、收发货和平台收货仓信息 | P0 | 进行中 | 75% | ADM-ORDER-01 | 待分配 | 前端详情按下单时仓库快照展示;API 与数据库持久化待接入 |
+| ADM-ORDER-03 | 后台 | 头程订单 | 订单审核、人工修改、受理、取消和状态流转 | P0 | 进行中 | 80% | ADM-ORDER-02 | 待分配 | Vue 已删除订单驳回状态/动作;后台修改待审核订单后仍保持待审核并自动追加审计记录,联系客户修改不改变状态;等待业务 API |
+| ADM-ORDER-04 | 后台 | 头程订单 | 订单指派、内部备注和操作记录 | P1 | 进行中 | 65% | ADM-ORDER-03 | 待分配 | 负责人、处理说明和时间线前端已完成 |
+| ADM-WH-01 | 后台 | 平台收货仓 | 仓库列表、关键词和状态筛选、分页及空态 | P0 | 进行中 | 75% | BASE-03、WH-BASE-01 | 待分配 | 静态页面和权限已完成,等待接口联调 |
+| ADM-WH-02 | 后台 | 平台收货仓 | 新增、编辑、启用和停用仓库;校验编码唯一性 | P0 | 进行中 | 75% | ADM-WH-01 | 待分配 | 停用仓库不允许新订单选择,不物理删除历史引用 |
+| WH-BASE-01 | 公共 | 仓库模型 | 定义国内平台收货仓、启停状态及订单仓库关联 | P0 | 进行中 | 65% | BASE-02 | 待分配 | 共享仓库及快照模型已完成,数据库与 API 契约待实现 |
+| MD-PROTO-01 | 公共 | 基础资料原型 | 核对 `docs/悦` 中快递公司、往来单位菜单、列表、字段、状态和现有交互,形成一期迁移口径 | P0 | 已完成 | 100% | - | 待分配 | 已确认原型存在;原型资产与当前 Vue 工程实现分开统计 |
+| MD-BASE-01 | 公共 | 基础资料模型 | 统一快递公司、往来单位的稳定编码、启停、审计、数据范围和订单快照规则 | P0 | 进行中 | 10% | BASE-02、BASE-04、MD-PROTO-01 | 待分配 | 设计文档已有字段草案;共享类型、数据库与 API 契约尚未实现 |
+| ADM-EXP-01 | 后台 | 快递公司 | 快递公司列表、关键词搜索、按状态筛选及详情 | P0 | 进行中 | 80% | BASE-03、MD-BASE-01 | 待分配 | Vue 列表、组合筛选、详情和响应式展示完成;Pinia 静态数据等待新架构业务 API |
+| ADM-EXP-02 | 后台 | 快递公司 | 后台人员新增、编辑、启用和停用;校验稳定编码与名称唯一性 | P0 | 进行中 | 80% | ADM-EXP-01 | 待分配 | Vue 维护、权限控制、编码/名称不区分大小写唯一校验和历史引用提示完成;服务端校验待接入 |
+| ADM-EXP-03 | 后台 | 快递公司 | 使用标准模板批量导入快递公司档案 | P1 | 进行中 | 60% | ADM-EXP-02、BASE-04 | 待分配 | 标准 XLSX 下载、文件选择、扩展名和大小检查已完成;工作表解析、模板版本、重复校验、整批事务及错误报告均由后端负责,等待导入 API |
+| ADM-CP-01 | 后台 | 往来单位 | 往来单位列表、关键词搜索、按单位类型/状态筛选及详情 | P0 | 进行中 | 80% | BASE-03、MD-BASE-01 | 待分配 | Vue 列表、关键词/六类角色/状态筛选、详情和空态完成;原型核对与 Vue 实现分别统计 |
+| ADM-CP-02 | 后台 | 往来单位 | 后台人员新增、编辑、启用和停用;维护单位编码、名称和类型 | P0 | 进行中 | 80% | ADM-CP-01 | 待分配 | Vue 新增/编辑/启停、多类型和编码唯一校验完成;企业客户端无维护入口,服务端数据范围待接入 |
+| ADM-CP-03 | 后台 | 往来单位 | 维护联系人、电话、邮箱、国家/地区、州省、城市、邮编和详细地址 | P0 | 进行中 | 80% | ADM-CP-02 | 待分配 | Vue 联系人与完整地址字段、邮箱格式和必填校验完成;订单快照 API 待接入 |
+| ADM-CP-04 | 后台 | 往来单位 | 使用标准模板批量导入往来单位档案 | P1 | 进行中 | 60% | ADM-CP-03、BASE-04 | 待分配 | 标准 XLSX、六类多值说明、文件类型和大小检查已完成;解析、数据范围、整批失败和错误报告由后端返回,等待导入 API |
+| CLI-AUTH-01 | 客户端 | 登录认证 | 按后端契约实现用户名密码登录、记住我、登录反馈及登录/注册互跳 | P0 | 联调中 | 85% | BASE-03 | 待分配 | 已接 `/api/auth/login|refresh|logout`、Token 轮换、MERCHANT JWT 和会话恢复;Gateway 在线但登录转发 503,待路由恢复后验证错误码与过期刷新 |
+| CLI-REG-01 | 客户端 | 注册 | 按后端契约维护用户名、8–72 位密码、企业、联系人、法人、手机、邮箱、国家和地址 | P0 | 联调中 | 85% | BASE-03 | 待分配 | 已按 DTO 补齐全部字段并接 `/api/auth/register`;Gateway/Auth 环境不稳定,待恢复后验证重复用户名与 422 字段错误 |
+| CLI-REG-02 | 客户端 | 注册 | 完成基础格式校验、协议确认、免审核注册成功反馈和登录互跳 | P0 | 联调中 | 90% | CLI-REG-01 | 待分配 | 注册成功跳登录并带入用户名,账号与企业资料审核状态分离;待 Gateway 真实验收 |
+| ADM-CUSTOMER-03 | 后台 | 企业资料审核 | 企业资料待审核列表、详情和人工审核通过操作 | P0 | 联调中 | 85% | ADM-CUSTOMER-02、CLI-PROFILE-02 | 待分配 | 已接待审列表、`/tenants/{tenantId}/qualifications`、平台资质文件二进制接口及真实审核动作;文件不再使用无 Token 直链,待审样本写操作仍待人工验收 |
+| CLI-MY-01 | 客户端 | 我的信息 | 查看用户名、姓名、联系电话、邮箱和所属公司,支持进入编辑、保存和取消 | P0 | 联调中 | 90% | CLI-AUTH-01 | 待分配 | 已接个人资料查询/编辑接口;用户名和所属公司只读,电话与邮箱按 OpenAPI 可选约束处理,保存失败保留输入 |
+| CLI-MY-02 | 客户端 | 我的信息 | 使用当前密码、新密码和确认密码修改登录密码 | P0 | 联调中 | 90% | CLI-MY-01、BASE-03 | 待分配 | 已接 `PUT /api/auth/password`,按 8–64 位且同时包含字母数字校验;成功后清理旧会话并返回登录页 |
+| CLI-PROFILE-01 | 客户端 | 公司信息 | 企业基本信息、法人信息、联系人、手机、邮箱、微信和地址查看与维护 | P0 | 进行中 | 65% | CLI-REG-01 | 待分配 | 原型按“企业基本信息/联系信息”分页签展示;当前静态编辑交互已完成,等待接口和真实权限控制 |
+| CLI-PROFILE-02 | 客户端 | 公司信息 | 一期营业执照状态、查看和上传 | P1 | 联调中 | 90% | BASE-04 | 待分配 | 已接资料编辑、资质查询、营业执照上传及携带 Token 的图片预览;按后端限制为单张 JPG/PNG、最大 5MB,待稳定环境完成浏览器验收 |
+| CLI-MEMBER-01 | 客户端 | 企业成员 | 成员列表、新增、编辑、启停和重置密码 | P0 | 联调中 | 92% | CLI-REG-01 | 待分配 | 姓名、联系方式、memberNo 和 roleIds 已真实回显;新增、编辑、启停、重置密码均接精确 membershipId 路径,所有者保护由服务端最终校验 |
+| CLI-ROLE-01 | 客户端 | 角色 | 企业角色新增、编辑、删除、启停 | P0 | 联调中 | 80% | CLI-MEMBER-01 | 待分配 | 已接角色列表和新增角色;编辑、删除、启停接口未在联调文档中提供,页面进入 API 模式后不再回退模拟写入 |
+| CLI-ROLE-02 | 客户端 | 角色 | 为成员分配一个或多个角色 | P0 | 联调中 | 92% | CLI-ROLE-01 | 待分配 | 成员 roleIds 已回显,新增/编辑成员通过精确 membershipId 全量保存角色;待浏览器执行一次真实写入验收 |
+| CLI-MENU-01 | 客户端 | 菜单分配 | 企业管理员为本企业角色分配客户端菜单和操作权限 | P0 | 进行中 | 60% | CLI-ROLE-01 | 待分配 | 已确认操作人为企业管理员;分组选择交互已完成,动态菜单生成与平台菜单隔离需由服务端契约保证 |
+| CLI-PERM-01 | 客户端 | 权限 | 页面、按钮和接口权限定义及角色授权 | P0 | 联调中 | 90% | CLI-MENU-01 | 待分配 | 角色 permissionIds 与启用权限资源已映射回显;非内置启用角色可全量保存权限,待准备自定义角色完成浏览器写入验收 |
+| CLI-PERM-02 | 客户端 | 权限 | 按当前成员权限生成菜单并执行接口鉴权 | P0 | 进行中 | 55% | CLI-PERM-01 | 待分配 | 已完成演示账号权限集合、动态菜单、路由 403、首个可访问页面、会话恢复和按钮权限预览;服务端仍必须校验 `tenant_id` 与权限 |
+| CLI-CP-01 | 客户端 | 往来单位查询 | 只读查询当前可用的发货单位和收货单位,支持关键词和类型筛选 | P0 | 联调中 | 88% | ADM-CP-03、BASE-03 | 待分配 | 已接 `/api/merchant/v1/partners/candidates`,按 SENDER/RECEIVER 查询当前租户启用候选;无维护入口且不回退演示数据 |
+| CLI-WH-01 | 客户端 | 平台收货仓选择 | 查询已启用仓库,展示名称、地址和收货时间 | P0 | 测试中 | 95% | WH-BASE-01、ADM-WH-02 | 待分配 | 浏览器已读取 1 条真实启用仓库,选择后成功加载深圳地址和每日 16:00 截单时间;历史订单引用失效仓库时要求重新选择,不回退模拟仓库 |
+| CLI-ORDER-01 | 客户端 | 头程订单 | 新建头程订单、保存草稿和提交;提交前校验企业资料审核状态 | P0 | 联调中 | 92% | BASE-03、ADM-CUSTOMER-03 | 待分配 | 企业审核状态改为进入订单页时真实加载;创建/编辑/提交契约、幂等键和权限映射已接。为避免污染联调数据,本轮只读验收未执行保存和提交 |
+| CLI-ORDER-02 | 客户端 | 头程订单 | 我的订单列表和详情 | P0 | 测试中 | 95% | CLI-ORDER-01 | 待分配 | 浏览器真实读取 1 条草稿及详情,货物、双方快照和状态历史正常回显;编辑前强制加载完整详情,修复列表简要数据导致空货物和响应式复制异常 |
+| CLI-ORDER-03 | 客户端 | 头程订单 | 下单选择平台收货仓;提交时保存仓库 ID 和展示快照 | P0 | 测试中 | 90% | CLI-WH-01、CLI-ORDER-01 | 待分配 | 新订单真实仓库选择和详情回显已验证;当前旧草稿引用已不存在的仓库 `2001`,客户端清空失效选择并提示重新选择,服务端样本关联待修复 |
+| CLI-ORDER-04 | 客户端 | 头程订单 | 从已启用往来单位选择发货方/收货方并带入联系人和地址,提交时保存快照 | P0 | 测试中 | 92% | CLI-CP-01、CLI-ORDER-01 | 待分配 | 真实候选接口和订单双方快照已接;当前新建表单候选为空,旧订单快照可完整回显并以“历史快照”标识已不在候选中的单位 |
+| ADM-ORDER-05 | 后台 | 头程订单 | 维护履约快递公司、快递单号并在订单详情展示 | P1 | 进行中 | 80% | ADM-EXP-02、ADM-ORDER-02 | 待分配 | Vue 列表/详情/维护弹窗、单组限制、停用历史回显和审计记录完成;一期不接轨迹订阅,业务 API 待新架构确认 |
+| CLI-ORDER-05 | 客户端 | 头程订单 | 订单详情只读展示后台维护的快递公司和快递单号 | P1 | 测试中 | 75% | ADM-ORDER-05、CLI-ORDER-02 | 待分配 | 真实订单详情已验证“平台尚未维护快递信息”空态,客户侧无编辑入口;仍需后台准备含快递公司和单号的样本复测有值回显 |
+| TEST-01 | 公共 | 测试 | 用户、角色、权限和越权访问测试 | P0 | 进行中 | 40% | 权限模块完成 | 待分配 | 客户端已覆盖权限过滤、403、首个可访问页面、按钮权限和会话恢复;跨企业越权及接口拒绝必须待服务端测试 |
+| TEST-02 | 公共 | 测试 | Admin 登录、企业端免审核注册、企业资料审核、下单资格和头程订单业务流程测试 | P0 | 进行中 | 45% | 业务模块完成 | 待分配 | 客户端已覆盖免审核注册、资料待审核可存草稿、提交阻断和资料引导;仍需接口失败、审核通过提交及服务端越权测试 |
+| TEST-03 | 公共 | 测试 | 编码唯一、启停控制、客户端只读选择及订单仓库关联测试 | P0 | 进行中 | 65% | ADM-WH-02、CLI-ORDER-03 | 待分配 | 前端自动化已覆盖停用限制和主数据变更后的历史快照;服务端测试待补 |
+| TEST-04 | 公共 | 测试 | 快递公司和往来单位编码唯一、数据范围、启停控制、批量导入、只读查询、订单带入及快照测试 | P0 | 进行中 | 25% | ADM-EXP-03、ADM-CP-04、CLI-ORDER-05 | 待分配 | 补充模板版本、必填/格式/重复校验、整批失败、错误报告、导入权限和审计测试 |
+| REL-01 | 公共 | 发布 | 测试环境部署、初始化账号、基础菜单权限和首批基础资料 | P0 | 待开始 | 0% | BASE-01、ADM-WH-02、ADM-EXP-02、ADM-CP-03 | 待分配 | 首批收货仓、快递公司、往来单位数据需业务验收;禁止使用通用弱密码 |
+| REL-02 | 公共 | 验收 | 一期验收、问题修复和生产发布 | P0 | 待开始 | 0% | TEST-01、TEST-02、TEST-03、TEST-04 | 待分配 | 形成验收清单 |
+
+## 四、建议里程碑
+
+| 里程碑 | 交付目标 | 状态 | 计划完成 |
+|---|---|---|---|
+| M1 基础工程 | 工程、数据库、登录认证、通用能力可用 | 待排期 | 待排期 |
+| M2 后台权限 | 内部用户、角色、权限完整可用 | 进行中 | 待排期 |
+| M3 企业入驻 | 免审核注册、企业资料人工审核、下单资格和企业成员可用 | 进行中 | 待排期 |
+| M4 企业权限 | 客户端角色、菜单和权限完整可用 | 进行中 | 待排期 |
+| M5 基础资料主数据 | 后台可维护平台收货仓、快递公司、往来单位;客户端只读查询并受数据范围控制 | 进行中 | 待排期 |
+| M6 订单闭环 | 客户选择收货仓和往来单位提交订单,后台维护履约信息,历史展示稳定 | 进行中 | 待排期 |
+| M7 一期上线 | 联调、测试、验收和生产发布完成 | 待排期 | 待排期 |
+
+## 五、产品决策与待确认事项
+
+### 已确认决策
+
+| 编号 | 决策 | 结论 |
+|---|---|---|
+| Q1 | 客户端一期是否包含头程下单、订单列表和详情? | 包含,作为一期前后台订单闭环的必要范围 |
+| Q2 | 企业注册与企业资料审核关系 | 注册无需审核,成功后即可登录;提交订单前必须提交企业资料并由平台人工点击审核通过 |
+| Q3 | 客户端“菜单分配”的操作人 | 企业管理员为本企业角色分配菜单和操作权限,不能管理其他企业或平台后台菜单 |
+| Q4 | 一个用户能否拥有多个角色? | 一期支持多角色,服务端按角色权限并集授权 |
+| Q5 | 企业注册是否使用短信或邮箱验证码? | 一期不接验证码,仅做必填、格式、密码强度和账号重复校验 |
+| Q6 | 头程订单一期状态 | 草稿、待审核、已受理、已订舱、运输中、已完成、已取消;不设置已驳回状态 |
+| Q7 | 是否需要部门/组织架构? | 一期不纳入,成员直接关联企业并通过角色授权 |
+| Q8 | 一期仓库范围与维护方 | 平台后台统一维护国内收货仓,客户端只读选择启用仓库;FBA/海外目的仓不纳入本次 |
+| Q9 | 仓库停用后的订单处理 | 禁止新单选择;历史订单继续展示下单时仓库编码、名称和地址快照 |
+| Q10 | 快递公司和往来单位维护方 | 均由当前平台后台人员维护;企业客户端无维护入口和写接口,仅可按权限查询、选择和查看 |
+| Q11 | 往来单位的数据范围 | 按所属业务主体隔离,平台人员仅在授权数据范围内维护和查看 |
+| Q12 | 往来单位一期类型 | 使用稳定编码并支持一个单位多选类型;一期覆盖供应商、客户、承运商、报关行、发货单位和收货单位 |
+| Q13 | 一个订单支持几组快递公司和快递单号? | 一期只支持一组履约快递信息;多包裹、多段运输后续扩展 |
+| Q15 | Admin 工作台是否纳入一期? | 不纳入一期交付与验收;一期先完成简单登录、企业资料审核、权限、基础资料和订单闭环 |
+| Q14 | 快递公司、往来单位批量导入是否纳入一期? | 已确认纳入一期,均由获授权的后台人员使用标准模板导入 |
+| Q16 | 多语言、微信和企业微信登录是否纳入一期? | 不纳入;一期仅交付中文账号密码登录,第三方登录后续单独排期 |
+| Q17 | 快递公司、往来单位导出是否纳入一期? | 不纳入;一期仅实现标准模板批量导入 |
+| Q18 | 一期客户端是否包含我的信息和公司信息? | 已确认包含;按现有客户端原型覆盖个人资料编辑、修改密码、企业基本/联系信息和资质文件查看维护 |
+| Q19 | 待审核订单信息不正确时如何处理? | 一期无驳回操作;后台可人工修改,不能直接确认时联系客户修改,订单保持待审核并记录修改审计 |
+| Q20 | 批量导入是否更新已有档案? | 一期仅新增;重复编码或唯一键冲突时整批失败,不覆盖已有档案 |
+| Q21 | “我的信息”中的用户名能否修改? | 用户名只读,不允许修改 |
+
+### 待确认事项
+
+| 编号 | 待确认问题 | 当前建议 |
+|---|---|---|
+| Q22 | 企业资料审核通过需要哪些必填资料? | 待产品给出字段和资质文件清单;在确认前按现有公司信息与营业执照能力保持可配置校验 |
+| Q23 | 审核通过后修改哪些关键资料需要重新审核? | 建议公司名称、统一信用代码、营业执照等关键资料变更后回到待审核;联系人等普通信息不触发 |
+| Q24 | 企业资料未审核通过时允许进行到哪一步? | 当前实现允许保存订单草稿但禁止提交;是否连新建订单也禁止仍需产品确认 |
+
+## 六、状态维护规则
+
+- 状态统一使用:待确认、待开始、进行中、联调中、测试中、已完成、已阻塞。
+- 开始开发时填写负责人、计划日期并将状态改为“进行中”。
+- 提交测试时更新为“测试中”,测试通过并验收后才更新为“已完成”。
+- 出现阻塞时在备注中写明阻塞原因、责任人和预计解除时间。
+
+## 七、后台前端阶段验收(2026-07-27)
+
+| 验收项 | 结果 | 证据/说明 |
+|---|---|---|
+| 客户管理 | 通过(静态,待调整) | 列表、筛选、分页、新增/编辑、详情和启停已完成;原注册审核交互需改为企业资料审核通过 |
+| Admin 登录 | 通过(静态) | 登录必填/失败反馈、退出确认、安全回跳、403 路由及按角色首个业务页落地已完成;一期工作台入口已移除,真实 Token 与会话失效处理待接入 |
+| 内部用户 | 通过 | 列表、筛选、新增/编辑、多角色、重置密码、启停及管理员保护 |
+| 角色管理 | 通过 | 新增/编辑/删除/启停、权限树、数据范围及内置角色保护 |
+| 权限管理 | 通过 | 目录/菜单/按钮/接口资源树、上下级维护、状态与唯一编码校验 |
+| 头程订单 | 通过 | 创建/编辑、草稿/提交、详情、时间线、单笔/批量处理、指派与导出反馈 |
+| 响应式与可访问性 | 通过 | 桌面与 390px 手机视口实测;菜单可收起,表格可滚动,关键触控区 44px |
+| 自动化测试 | 通过 | `apps/admin-web` 执行 `pnpm test`,21 个测试文件、148 项通过,覆盖企业审核、租户资质鉴权预览、平台角色/权限 IAM 路径、错误追踪信息、导入边界、真实列表/失败态、登录安全回跳及开发账号环境隔离 |
+| TypeScript 类型检查 | 通过 | `pnpm typecheck` |
+| 生产构建 | 通过 | `pnpm build`,输出至 `apps/admin-web/dist`;产物扫描确认不包含平台联调账号、密码和开发提示 |
+| impeccable 样式检测 | 通过(已修复告警) | 修复字体栈以及 width/margin 布局动画;保留既有后台视觉体系 |
+
+> 客户档案、内部用户和基础资料仍使用 Pinia 模拟数据;企业审核、平台角色、菜单及按钮权限资源已切换到真实 IAM 接口。后台前端阶段完成不等于一期业务完成,仍需后端数据、真实 RBAC 鉴权、联调和测试后才能标记“已完成”。
+
+### Admin 认证联调记录(2026-07-29)
+
+- 前端已统一通过 Gateway 前缀调用 `/api/auth/**` 和 `/api/platform/v1/iam/**`,本地 Vite 使用 `/api` 代理,不拼接 Nacos 服务名或服务直连端口。
+- 已实现 Access/Refresh Token 持久化、PLATFORM 身份域校验、刷新令牌轮换、并发 401 单次刷新、服务端退出调用,以及 JWT 权限与 IAM 启用资源交集。
+- `192.168.110.149:9000` Gateway 的 Auth、IAM、头程订单和仓库路由已恢复并完成基础连通验证;企业审核列表当前返回空数组。
+- 企业审核已新增独立路由 `/customers/reviews`,权限为 `platform:customer:review`,通过/驳回分别校验 `platform:customer:approve` 与 `platform:customer:reject`,提交参数使用审核接口返回的 `reviewId`。
+- `file-service:9206` 当前拒绝连接;IAM Swagger/OpenAPI 当前返回 500,审核 DTO 的可选展示字段仍以真实返回为准。前端不增加服务直连或模拟数据静默回退。
+
+### Admin 平台角色与权限联调记录(2026-07-30)
+
+- 已接入 `GET/POST /api/platform/v1/iam/roles`,真实会话使用 IAM 角色列表,新增角色使用后端返回的真实角色记录。
+- 新增角色按钮严格使用 `platform:role:create`;角色编辑、删除、启停接口未在最新联调文档中提供,真实会话中不展示这些模拟操作。
+- 角色权限写接口是全量替换,但联调文档没有角色当前 `permissionIds` 回显。为避免覆盖已有授权,真实会话暂不开放角色授权保存。
+- 已接入 `GET/POST /api/platform/v1/iam/permissions`;真实会话使用 IAM 权限资源树,并严格把新增类型限制为 `MENU` 和 `BUTTON`。
+- 新增权限使用 `platform:permission:create`,正确提交真实父资源 ID、路由和排序;权限编辑、启停接口未提供,真实会话不展示对应模拟操作。
+- 2026-07-30 验收时 `192.168.110.149:9000` 连接被拒绝,无法执行真实登录和角色读写现场验证;专项自动化测试已覆盖接口路径、真实列表模式和失败恢复。
+
+## 八、客户端前端阶段验收(更新至 2026-07-30)
+
+| 验收项 | 结果 | 证据/说明 |
+|---|---|---|
+| 企业资料 | 通过(静态) | 基本信息、联系信息、资质文件选择与校验、移除、提交防重、元数据详情和移动端卡片已完成 |
+| 企业成员 | 通过(静态) | 列表与移动卡片、筛选、新增/编辑、多角色、重置密码、启停和管理员保护已完成 |
+| 企业角色 | 通过(静态) | 新增/编辑/删除/启停、成员和权限数量、内置角色保护及权限入口已完成 |
+| 菜单权限 | 通过(静态) | 角色选择、分组菜单与操作权限、全选/半选、保存/重置和只读保护已完成 |
+| 我的信息与修改密码 | 通过(静态) | 原型字段、查看/编辑/保存/取消、只读账号与企业、当前密码错误、密码强度和静态会话/审计结果已完成 |
+| 头程订单与仓库 | 通过(静态) | 下单、草稿、提交、列表、详情、启用仓库选择、历史仓库快照及后端必填字段已完成;取消不纳入本轮一期客户端验收 |
+| 静态页面完整性与响应式 | 通过(100%) | 一期客户端导航和路由均落到正式页面,无在用占位页;桌面、720px 和 390px 布局、移动导航、44px 主要操作及无横向溢出已验证 |
+| 自动化测试 | 通过 | `apps/client-web` 执行 `pnpm test`,94 项通过,覆盖认证、个人资料、成员、角色权限、超大整数响应、业务总览真实加载、往来单位历史快照、仓库详情、头程订单完整详情编辑、幂等、快递字段、失败恢复、未保存保护、响应式和关键源码契约 |
+| TypeScript 类型检查 | 通过 | `apps/client-web` 执行 `pnpm typecheck` |
+| 生产构建 | 通过 | `apps/client-web` 执行 `pnpm build`;产物扫描确认不包含商户联调账号和开发提示 |
+| 登录注册 | 代码接入(待环境验收) | 已移除模拟登录成功,接入真实注册、登录、退出、Token 轮换、统一错误与 MERCHANT 身份校验 |
+| 下单资格 | 通过(静态) | 企业资料待审核时可创建、编辑和保存草稿,提交时阻断并引导至企业资料;审核通过状态允许提交 |
+| 客户端权限效果 | 通过(静态) | 按演示账号过滤导航,拒绝无权限路由并显示 403,恢复刷新后的权限身份,控制主要业务按钮和首个可访问页面 |
+| 往来单位与订单快照 | 通过(静态) | 仅选择启用的发货/收货单位,可调整本单联系人和地址;保存后形成独立快照,不反向修改主数据 |
+| 快递信息 | 通过(静态) | 订单详情只读展示平台维护的快递公司和单号,并提供未维护空态;客户侧无写入口 |
+| 服务端与数据安全 | 联调中 | 认证、权限资源、企业资料、营业执照、个人资料、成员完整维护、角色权限保存、仓库详情、往来单位、头程订单及快递只读字段已接真实 API;角色编辑/启停/删除路径仍待 Gateway OpenAPI 明确,客户端不猜测接口 |
+
+> 客户端静态页面阶段通过不等于一期业务完成。菜单隐藏和页面只读只用于前端体验,服务端仍必须按当前用户、`tenant_id` 和权限编码执行授权校验。
+
+### Client 认证与企业资料联调记录(2026-07-29)
+
+- 已按后端联调文档统一使用 Gateway `/api` 前缀,开发代理目标更新为 `http://127.0.0.1:9000`。
+- 已实现字符串业务码响应解包、422 字段错误载体、401 并发单次刷新、Refresh Token 轮换、退出清理,以及 403 不误跳登录。
+- 客户端只接受 `app_code=MERCHANT`,权限由 JWT 权限与 IAM 启用资源取交集后显式映射到现有页面权限。
+- 企业资料状态已统一为 `PROFILE_REQUIRED / PENDING / ACTIVE / REJECTED / DISABLED`;营业执照按后端限制只接受单张 JPG/PNG、最大 5MB。
+- 本机 `http://127.0.0.1:9000` 当前拒绝连接,真实登录与上传尚未执行;订单、仓库、往来单位接口文档缺少精确请求响应结构,本轮未猜测接入。
+
+### Client IAM 角色与成员联调记录(2026-07-29)
+
+- 已接入 `GET/POST /api/merchant/v1/iam/roles` 和 `GET /api/merchant/v1/iam/members`;新增角色使用后端返回的真实角色记录。
+- 已封装角色权限与成员角色的全量替换接口,请求分别使用 `roleId + permissionIds`、`membershipId + roleIds`,未误用 `userId`。
+- 成员列表接口目前只返回 membershipId、userId、memberType、status、joinedAt,页面不会伪造姓名、联系方式或角色关系。
+- 联调文档没有返回角色当前 permissionIds 和成员当前 roleIds 的查询契约。由于写接口是全量替换,页面暂禁用授权保存,避免覆盖已有权限。
+- 角色编辑、删除、启停、成员新增、资料编辑、启停和密码重置接口未提供;API 模式下相关静态写操作不再开放,也不会在请求失败后回退模拟成功。
+
+### Client 联调环境复测记录(2026-07-30)
+
+- 客户端开发服务 `http://localhost:5176` 返回 200,静态资源和前端运行环境正常。
+- 本机 `127.0.0.1:9000/9100/9201/9206` 均未监听;局域网环境 `192.168.110.149` 的 Gateway、Auth、IAM、File 健康端点曾同时返回 `UP`。
+- 通过 Gateway 请求未登录的商户权限接口返回预期 401,证明 Gateway 可达且鉴权入口生效;使用文档初始化商户账号调用 `/api/auth/login` 返回 503,无法取得 Token,后续企业资料、权限、角色和成员真实读取未能执行。
+- Auth 直连登录同样出现 503,随后端口短暂拒绝连接,表现为服务发现或服务重启不稳定;前端仍坚持只调用 Gateway,未把直连服务地址写入配置。
+- 后端恢复后优先复测:登录、Token 刷新与退出、企业状态、资质列表、权限资源、角色列表和成员列表;授权全量替换继续保持禁用,直到补齐当前 `permissionIds` 与 `roleIds` 回显。
+
+### Client 头程订单新接口接入记录(2026-07-30)
+
+- 新版联调文档和 Gateway Swagger 已确认可用;实测商户登录、企业资料、资质、权限、角色、成员、仓库分页、订单分页与订单详情均返回 `code=0`,订单详情不返回平台内部备注。
+- 已接企业资料 `PUT`、资质图片鉴权下载、仓库分页、订单分页/详情、创建/编辑草稿和提交;`SUBMITTED/PROCESSING`、`transportMode/containerMode` 均通过适配层映射,未把 FCL/LCL 错当运输方式。
+- 页面新增渠道、提货方式、报关模式、目的仓类型、包装类型等后端必填字段;订单和仓库请求失败不回退模拟数据,仓库为空时禁用创建。
+- Swagger 虽存在订单取消接口,但新版任务文档明确取消不纳入本轮本地一期验收,因此客户端不暴露取消写操作。
+- 远端环境在浏览器验收阶段再次无响应;`http://127.0.0.1:5190` 登录页正常加载并发起真实登录,但 Gateway 健康检查与登录请求均超时,未进入工作台。
+- 代码已再次通过 81 项自动化测试和 TypeScript 检查;本轮生产构建与浏览器验收结果见交付记录,真实草稿写入、资质预览与空仓禁建仍需在稳定 Gateway 和有效仓库数据下继续验收。
+
+### 最新本地联调契约收口(2026-07-30)
+
+- 最新文档再次确认浏览器只通过 Gateway `9000` 和同源 `/api` 访问,禁止直连 `9100/9201/9204/9205/9206` 等服务端口;后端文档记录 8 个应用健康检查均为 `UP`,平台账号也已由人工登录进入 Admin。
+- 本轮真实接入范围为商户企业资料/资质、商户仓库和头程订单 CRUD/提交,以及平台待审列表、指定租户资质、鉴权文件查看和审核动作。平台订单审核、受理、履约、完成、取消及 Admin 快递公司/往来单位业务接口未纳入最新本地联调契约,前端继续保留静态实现,不猜测接口。
+- 后端任务文档写有“`DRAFT`、`REJECTED` 可编辑”,与已确认的一期订单七状态规则冲突。产品确认优先:订单不恢复“已驳回”状态;兼容旧接口返回的订单 `REJECTED` 时映射为待审核且不开放客户编辑。企业资料和资质审核的 `REJECTED` 仍正常保留,这是独立业务状态。
+- 平台企业审核详情改为按租户查询资质,文件通过平台 Token 请求二进制后临时预览,不再直接打开商户文件 URL;覆盖加载、空数据、失败重试和对象地址释放。
+- 商户订单创建与提交请求增加 `Idempotency-Key`,并将 `merchant:order:create/edit/submit` 映射为三个独立前端操作权限;商户详情仍不读取或渲染 `internalNotes`。
+- 交付门禁通过:Admin `21` 个测试文件、`147` 项测试,Client `81` 项测试;两端 `pnpm typecheck` 与 `pnpm build` 均通过。已使用真实平台账号进入 `http://localhost:5173/customers/reviews`,待审列表真实返回空数据且无控制台错误;桌面和 390px 窄屏无页面级横向溢出。由于当前无待审记录,资质抽屉的真实文件预览仍待准备样本后人工验收。
+
+### Admin 前端质量收口(2026-07-30)
+
+- 主数据导入架构明确为后端解析 `.xlsx`:前端仅检查扩展名和 10MB 大小限制,不读取工作表内容;已移除按文件名制造校验结果、模拟整批成功和虚假的错误报告。后端接口接入后,前端展示服务端返回的上传进度、逐行错误和报告地址。
+- API 错误适配层保留业务错误码、`requestId`、`traceId`;登录、企业审核、角色与权限主要失败态展示可复制追踪标识,接口失败仍不回退模拟成功。
+- 浏览器逐页检查 Admin 9 个主要业务路由;桌面与 390px 窄屏均无页面级横向溢出,修复了头程订单日期范围控件将窄屏筛选网格撑宽的问题,控制台无业务错误。
+- 两端登录页完成生产环境隔离:本地开发继续提供联调账号预填/提示,生产表单默认留空。Admin 21 个测试文件、148 项测试和 Client 82 项测试均通过,两端 `pnpm typecheck`、`pnpm build` 均通过;扫描生产 `dist` 对平台/商户联调账号、联调密码及开发提示零匹配。
+- 已读取后端 `phase1-business-maturity-regression-report.md` 并从 Gateway OpenAPI/真实只读请求复核契约:商户个人资料、成员资料及 roleIds、角色 permissionIds、往来单位候选均真实返回。Client 已移除个人资料和成员静态成功路径,接入修改密码、成员新增/编辑/启停/重置密码、角色权限全量保存与 SENDER/RECEIVER 候选;82 项测试、类型检查和生产构建通过,生产联调账号扫描零匹配。角色编辑/启停/删除路径未进入 OpenAPI,Admin 订单查询又要求显式 target tenantId,前端暂不猜测这两部分契约。
+
+### Client 成熟度报告接入与联调加固(2026-07-30)
+
+- 后端成熟度报告确认个人资料、修改密码、成员完整维护、角色权限回显与保存、仓库详情、往来单位候选、订单草稿/提交及平台快递只读信息已通过回归;客户端相应真实接口均已接入,不回退模拟成功。
+- 订单列表与详情已区分真实空数据和加载失败,均提供原位重试;编辑抽屉、路由离开和浏览器刷新/关闭均增加未保存草稿保护。
+- 选择收货仓时加载真实详情并回显地址、截单时间;历史订单优先展示仓库地址快照。订单详情映射快递公司、快递单号、收货仓地址和收货时间。
+- 往来单位按 `SENDER -> SHIPPER`、`RECEIVER -> CONSIGNEE` 查询启用候选;当前测试数据清理后候选为空,客户端保持真实空态,不恢复演示单位。
+- 角色 `permissionIds` 已映射为客户端权限码,权限保存执行真实全量替换;角色编辑、启停、删除虽已通过后端回归,但路径未进入当前 Gateway OpenAPI,页面继续隐藏对应写入口。
+- 代码门禁通过:Client 89 项自动化测试、`pnpm typecheck` 和 `pnpm build` 均成功。最新复测时 `192.168.110.149:9000` 再次拒绝连接,完整浏览器联调待 Gateway 恢复后继续。
+
+### Client Gateway 重启后浏览器联调(2026-07-30)
+
+- Gateway 重启后健康检查返回 `UP`,商户登录业务码为 `0`;浏览器真实登录成功,工作台、我的信息、企业成员和角色管理页均正常读取,控制台无错误。
+- 个人资料真实回显用户名、姓名、电话、邮箱和企业;成员接口真实返回 5 条记录,其中 1 条启用、4 条历史回归数据已停用,角色和联系方式均正常展示。
+- 浏览器发现角色页直接打开时未加载成员关系,导致成员数显示为 0;现已改为在拥有成员列表权限时并行加载角色与成员,统计按真实 `roleIds` 计算。
+- 服务随后再次超时,菜单权限页初始化期间原实现会因会话上下文失败清空 Token 并跳回登录。现已调整为临时网络故障或刷新超时保留有效会话,只有明确 401/`A0401` 才清理会话。
+- 修复后 89 项自动化测试、TypeScript 检查和生产构建通过;Gateway 当前健康检查仍超时,菜单权限、企业资料、仓库和头程订单浏览器验收待服务恢复后继续。
+
+### Client 后端修改后重新联调(2026-07-30)
+
+- Gateway 健康检查恢复为 `UP`,商户账号可重新登录;浏览器完成业务总览、头程订单列表、订单详情、创建表单、仓库详情和草稿编辑的真实只读验收。
+- 修复业务总览仍展示演示初始值的问题:首页现在按权限加载真实企业资料、成员和订单,显示企业已审核、1 名启用成员和 1 条真实草稿;接口失败时提供页面内重试。
+- 修复头程订单页未加载企业资料导致错误显示“待审核”的问题;页面现在真实显示企业已审核,可提交资格与服务端状态一致。
+- 修复真实草稿点击编辑时对 Vue 响应式对象调用 `structuredClone` 导致的 `DataCloneError`;保存与提交前也统一复制为纯草稿数据。
+- 修复从列表直接编辑只使用简要记录、造成货物和收发货快照为空的问题;编辑前先读取完整详情,并为已不在候选中的往来单位展示“历史快照”名称。
+- 真实仓库详情已回显“深圳头程收货仓”、广东省深圳市地址和每日 16:00 截单时间。现有旧草稿仍引用已失效仓库 `2001`,客户端会清空选择并提示重新选择;该样本关联需后端清理。
+- 当前订单详情的快递公司和快递单号均为空,客户端正确显示只读空态;需后端准备含快递信息的样本后复测有值场景。
+- 当前订单的部分中文字段由接口直接返回 `????`,涉及仓库名称、发货方、品名、渠道名称和备注;英文、数字、货物数量重量及收货方地址正常。该问题应由后端检查初始化脚本、数据库字符集或写入编码。
+- 过程中 Gateway 曾短暂返回 502/401,页面失败态、重试和会话清理行为符合预期;重新登录后恢复。最终代码门禁通过:Client 94 项自动化测试、`pnpm typecheck` 和 `pnpm build` 均成功。
diff --git a/一期/虫虫出海一期开发进度表.xlsx b/一期/虫虫出海一期开发进度表.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..76d32443c391383bc64827c6697d96a5ef47b108
GIT binary patch
literal 29095
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%0AEMdfUXzjI7$9nbbDLu&qt^x=
zG^ty$M93eos9W)5$ZwcbnSX#jYlTYcTRprvQD6`>(Em(4_IB0%eiZos_4dxUydV6Y
z1?%sjKtKilHE*-{7bn91it1^Q2rm%{Hs3R-;w%*;G_Dl=kfdg)cf;z
zpM3s<@?G;^QGVOg_bBh<`#&fh#{WZ_cUt}TSoIGA^BalCe~Vn-ANqYv_Ge(A+3!RD
zhY0OG&ig3h4-U4)dqwI>lh-Uf!0sP~s-vhpPd4B*Ato}cMe;nX@!1uo7
i4Hh!$TzNGB
literal 0
HcmV?d00001
diff --git a/三期/README.md b/三期/README.md
new file mode 100644
index 0000000..9458473
--- /dev/null
+++ b/三期/README.md
@@ -0,0 +1,16 @@
+# 三期文档
+
+三期以头程物流“03 出仓”为范围,完成从排柜、订舱、拖车和仓内拣货,到封柜、报关、国内出仓并等待装船的业务闭环。
+
+## 文档
+
+- [三期开发规划:国内出仓](三期开发规划.md)
+- [三期开发进度表](三期开发进度表.md):参考一期采用“大任务 → 详细任务 → 里程碑 → 未确认事项 → 开工准入 → 验收”结构维护。
+- [虫虫出海三期开发进度表(Excel)](虫虫出海三期开发进度表.xlsx):可筛选、可下拉维护并使用公式汇总的项目进度工作簿。
+- [三期需求确认表](三期需求确认表.md):集中跟踪 P3-Q1~P3-Q13、负责人和最终结论。
+- [三期页面与原型清单](三期页面与原型清单.md):按管理后台、企业客户端和 PDA 维护页面范围及原型状态。
+- `参考资料/出仓流程.png`:本期 9 个核心动作及业务终点的原始参考图。
+
+## 当前状态
+
+三期处于范围规划阶段,当前开工结论为 `NO-GO`。当前以原型图片中的“完成国内出仓,等待装船”为阶段终点。动作依赖与并行关系、排柜规则、PDA 设备、拖车协作、柜封照片清单、报关回执及放行门禁、港务/船期信息范围和来源仍需在启动前确认。产品和业务完成确认后先进入契约与任务准备,六项开工准入全部通过后再进入全面功能开发。
diff --git a/三期/三期开发规划.md b/三期/三期开发规划.md
new file mode 100644
index 0000000..9e7370a
--- /dev/null
+++ b/三期/三期开发规划.md
@@ -0,0 +1,310 @@
+# 虫虫出海三期开发规划:国内出仓
+
+> 创建日期:2026-07-28
+> 状态:范围规划中
+> 流程依据:[出仓流程](参考资料/出仓流程.png)中的头程物流“03 出仓”;当前以图片中的“完成国内出仓,等待装船”为阶段终点
+> 前置阶段:[一期文档](../一期/README.md) · [二期文档](../二期/README.md)
+
+## 一、三期目标
+
+三期承接二期“货物完成到仓、实测、差异处理和指定库位”的结果,将已受理货物转化为可执行、可追踪、可审计的国内出仓任务。
+
+流程覆盖九个动作:
+
+```text
+智能排柜 → 订舱 → 预约拖车
+ ↓
+PDA 拣货 → 装柜并上传货柜/铅封照片
+ ↓
+客户上传报关资料 → 平台整理提交报关代理 → 上传回执供客户下载
+ ↓
+查询或维护预计开船、到港等港务/船期信息
+ ↓
+完成国内出仓,等待装船
+```
+
+三期完成标准不是“订单改成已出仓”,而是每个柜次能够回答:装了哪些订单和货物、依据什么方案排柜、订了什么舱、谁承运拖车、仓库实际拣装了什么、柜号与铅封是什么、报关资料和回执在哪里、实际何时出仓、当前等待哪一班船。
+
+### 原型动作覆盖
+
+| 原型动作 | 规划模块 | 开发任务 | 覆盖结果 |
+|---|---|---|---|
+| 1. 智能排柜 | 智能排柜 | P3-PLAN-01、P3-PLAN-02 | 已覆盖,规则待 P3-Q1 确认 |
+| 2. 订舱 | 订舱与港务/船期信息 | P3-BOOK-01 | 已覆盖 |
+| 3. 预约托车 | 预约拖车 | P3-TRUCK-01 | 已覆盖,用词待 P3-Q3 确认 |
+| 4. PDA 拣货 | PDA 拣货与复核 | P3-PICK-01、P3-PDA-01、P3-PDA-02 | 已覆盖 |
+| 5. 拍货柜及铅封照上传 | 装柜及柜封证据 | P3-LOAD-01、P3-LOAD-02 | 已补充现场拍照上传任务,清单待 P3-Q6 确认 |
+| 6. 客户上传报关资料 | 报关资料协同 | P3-CUS-01 | 已覆盖 |
+| 7. 整理给到报关代理报关 | 报关资料协同 | P3-CLEAR-01 | 已覆盖 |
+| 8. 回执上传到系统供客户下载 | 报关回执与客户下载 | P3-CLEAR-01、P3-CUS-02 | 已覆盖,回执类型待 P3-Q12 确认 |
+| 9. 查港务信息(预计开船、到港等) | 订舱与港务/船期信息 | P3-PORT-01、P3-CUS-02 | 已补充独立查询任务,范围和数据源待 P3-Q9 确认 |
+
+## 二、阶段边界
+
+### 纳入三期
+
+- 出仓单、柜次、智能排柜建议、人工调整和版本确认。
+- 订舱申请、舱位结果,以及原型所述预计开船、到港等港务/船期信息;具体字段和数据源待确认。
+- 预约拖车、车辆司机、到仓装柜和离仓记录。
+- PDA 任务领取、扫码拣货、部分拣货、异常、复核和幂等提交。
+- 装柜、柜号、铅封号及货柜/铅封照片证据。
+- 客户上传报关资料、平台审核补件、整理并提交报关代理。
+- 报关回执上传、版本、客户可见范围和授权下载。
+- 国内出仓门禁、确认、冲正、时间线和站内通知。
+
+### 明确不纳入三期
+
+- 入库、上架、实时库存、移库、盘点、冻结、补货和完整 WMS。
+- 港区闸口、车队、船公司、海关单一窗口的正式自动化接口。
+- GPS 实时跟车、电子铅封、称重设备、摄像头 OCR 和 IoT 自动采集。
+- 自动报关、关税计算、退税、完整清关业务和自动单证识别。
+- 海上运输、海外清关、目的港提柜、海外仓入库和末端派送。
+- 无人工确认的全自动排柜、自动订舱和不可逆业务操作。
+
+## 三、参与角色与数据边界
+
+| 角色 | 数据范围 | 主要操作 |
+|---|---|---|
+| 企业订单操作员 | 当前企业订单与出仓单 | 上传/补充报关资料、查看出仓和港务/船期进度、下载回执 |
+| 平台运营 | 授权客户、订单和出仓单 | 创建出仓单、确认排柜、订舱、维护港务/船期信息和协调异常 |
+| 仓库主管 | 被授权的平台收货仓 | 分配拣货任务、复核差异、确认装柜和出仓条件 |
+| 仓库作业员 | 分配给本人或本仓的任务 | PDA 扫码、数量确认、异常上报和任务提交 |
+| 拖车调度员 | 授权出仓单与车辆范围 | 预约车辆、维护司机/车牌、到仓和离仓节点 |
+| 报关专员 | 授权客户、订单和报关批次 | 审核、退回、整理、提交资料并上传回执 |
+| 平台管理员 | 平台授权范围 | 维护权限、规则、服务商和高风险冲正 |
+
+服务端必须依据登录身份确定企业、仓库、客户和数据范围。前端传入的订单 ID、出仓单 ID、仓库 ID、客户 ID、作业员 ID 或报关批次 ID 不能单独作为授权依据。
+
+## 四、流程与状态设计
+
+原型以 1 至 9 编号表达动作顺序,但尚未说明哪些是强制前置、哪些允许并行。当前按原型顺序规划业务节点,同时使用主状态和子流程状态保留后续调整空间;在 P3-Q11 确认前,不把并行关系写成固定业务规则。
+
+### 1. 出仓单主状态
+
+| 稳定编码 | 中文名称 | 含义 |
+|---|---|---|
+| `DRAFT` | 草稿 | 出仓单已创建,排柜方案尚未确认 |
+| `PLANNING` | 排柜中 | 系统生成建议或人工调整方案 |
+| `PREPARING` | 出仓准备中 | 按已确认的依赖关系处理订舱、拖车、拣货和报关 |
+| `READY_TO_DISPATCH` | 待出仓 | 必要子流程和证据已满足 |
+| `DISPATCHED` | 已出仓 | 货柜已离开国内仓库 |
+| `WAITING_FOR_LOADING` | 等待装船 | 国内出仓已完成,等待对应船班装船 |
+| `CANCELLED` | 已取消 | 按规则取消并保留原因与历史 |
+| `BLOCKED` | 已阻塞 | 存在必须人工解除的关键异常 |
+
+### 2. 子流程状态
+
+- 订舱:待订舱、订舱中、已订舱、订舱失败、已取消。
+- 拖车:待预约、已预约、车辆已到仓、装柜中、已离仓、改约、已取消。
+- 拣货:待分配、待拣货、拣货中、待复核、已完成、异常挂起、已取消。
+- 报关:资料待上传、资料待审核、待补件、待提交、已提交代理、回执待上传、回执已上传、已退回、已取消。海关放行如需管理,作为待确认的回执类型或后续状态,不默认作为三期出仓门禁。
+- 港务/船期:待维护、已确认、信息变更、已开船;“已开船”属于三期之后的运输阶段,不是当前三期完成条件。
+
+主状态由服务端根据已确认的必要子流程推进。客户端不得通过传任意目标状态跳过拣货复核、柜封证据或已配置的出仓门禁。
+
+## 五、业务模块
+
+### 1. 出仓单
+
+- 从已上架且允许出仓的头程订单创建一张或多张出仓单。
+- 支持一张订单分多个柜次,也支持多个订单拼柜,具体开放范围由产品确认。
+- 保存订单、客户、仓库、货物、往来单位和计量数据快照。
+- 维护计划出仓时间、优先级、负责人、异常和整体时间线。
+- 重复创建和确认使用幂等键,并通过版本字段防止并发覆盖。
+
+### 2. 智能排柜
+
+- 原型仅明确“智能排柜”,具体硬约束、软偏好、输入数据和输出结果以 P3-Q1 的业务规则表为准。
+- 柜型容量、重量、体积、箱数、同票/混票、不可混装、装载顺序和利用率暂列为候选能力,不作为未经确认的固定验收项。
+- 当前建议首版采用“系统建议、人工确认”;是否允许调整、是否强制填写原因由排柜规则确认。
+- 建议排柜方案保留版本、规则版本、输入快照、操作者和前后差异,以支持追溯。
+- 未确认方案不得生成正式拣货任务或执行不可逆状态变化。
+
+### 3. 订舱与港务/船期信息
+
+- 原型明确需要查询预计开船、到港等港务信息;“港务信息”的准确业务含义、字段范围和归属以 P3-Q9 为准。
+- 船公司/订舱代理、航线、订舱号、船名航次、起运港、目的港、截单、截关、截港、ETD 和 ETA 暂列为候选字段。
+- 订舱失败、改船、甩柜、船期延误和取消暂列为候选异常场景,按业务确认结果实现。
+- 港务信息查询与人工维护分开设计:三期至少支持查询系统内已维护的信息,并记录查询条件、数据来源和更新时间;如后续确认可靠外部数据源,再通过预留适配边界接入,不在三期默认承诺正式接口。
+- 客户查看预计开船、到港等信息时展示数据来源和最近更新时间,避免把过期结果显示为实时信息。
+- 当前建议首版由平台人工维护,外部港务或船期接口只预留适配边界。
+- 建议关键信息变更保留旧值、新值、原因,并向授权用户发送站内提醒。
+
+### 4. 预约拖车
+
+- 从往来单位选择已启用拖车服务商,维护车牌、司机、电话和预约时间窗。
+- 记录提柜、到仓、装柜、离仓、还柜节点和交接说明。
+- 支持改约、取消、迟到、未到、车辆更换和柜号变更。
+- 司机手机号等个人信息按最小权限展示,不进入不必要的客户响应。
+- 图片原文“预约托车”建议统一为行业常用的“预约拖车”,需产品最终确认。
+
+### 5. PDA 拣货与复核
+
+- 按已确认排柜方案生成仓库、柜次、订单和货物明细级任务。
+- PDA 支持登录、领取、箱号选择、扫码、数量确认、部分拣货、跳拣、撤销和异常上报。
+- 服务端校验任务归属、状态、重复扫码、超量、错货和重复提交。
+- 拣货完成后必须复核;差异未处理前不得进入待出仓。
+- 扫描器、声音、震动、网络和缓存通过设备适配层实现,不直接绑定单一厂商 SDK。
+
+### 6. 装柜及柜封证据
+
+- 维护柜号、铅封号、装柜开始/完成时间、操作人和异常说明。
+- 支持按可配置清单上传货柜及铅封照片;柜体、开门空柜、装柜过程、满柜、关门和铅封照仅为候选类型,必传类型、角度和数量以 P3-Q6 为准。
+- 现场执行端支持直接拍照或从相册选择后上传,上传前显示柜次、柜号、铅封号和照片类型,防止证据关联错误。
+- 支持上传进度、失败重试、重复照片提示和提交前预览;弱网下不得因重复点击产生多份有效证据。
+- 照片记录文件哈希、上传人、上传时间、关联柜次和客户可见范围。
+- 铅封号重复、已确认的必传照片缺失或复核未通过时禁止确认出仓。
+- 修改柜号或铅封号需要二次确认、原因和完整审计。
+
+### 7. 报关资料协同
+
+- 客户按资料清单上传发票、箱单、合同、委托书和申报要素等文件。
+- 资料清单可按国家/地区、渠道和货物类型配置,并保存订单使用的清单版本。
+- 平台报关专员审核完整性,可退回具体文件并记录补件原因和时限。
+- 提交报关代理时生成提交批次,冻结该批次关联的文件版本。
+- 首版采用系统内整理加线下提交,不直接对接海关单一窗口。
+
+### 8. 报关回执与客户下载
+
+- 上传代理回传的报关回执并关联提交批次;回执类型可区分接收、申报、退单、查验或放行等,实际类型及出仓门禁以 P3-Q12 为准。
+- 替换文件产生新版本,不覆盖原记录;退单或补件形成明确任务。
+- 客户只能下载本企业且标记为客户可见的回执。
+- 文件下载使用授权地址并记录审计,不暴露内部存储路径。
+
+### 9. 国内出仓确认
+
+- 服务端校验排柜已确认、拣货复核完成、已确认的柜封证据齐全、车辆已离仓,以及已配置的报关回执和港务/船期信息门禁。
+- 当前不默认要求“海关已放行”后才能确认国内出仓;是否需要放行或其他特定回执作为门禁,以 P3-Q12 的业务结论为准。
+- 授权人员执行确认出仓,记录实际出仓时间、车辆、柜号、铅封号和说明。
+- 确认操作具备幂等、权限、版本和并发校验,重复请求只产生一次有效事件。
+- 完成后进入“等待装船”,企业客户可查看允许公开的节点、港务/船期信息和回执。
+- 出仓后发现错误不得直接回退数据库状态,必须使用授权冲正动作和反向审计事件。
+
+## 六、核心数据对象
+
+| 数据对象 | 关键内容 |
+|---|---|
+| 出仓单 | 订单、企业、仓库、计划/实际时间、主状态、负责人和版本 |
+| 排柜方案 | 经确认的规则版本、输入快照、柜次、货物分配、规则计算结果和确认记录 |
+| 柜次 | 柜型、柜号、铅封号、装载顺序、重量、体积和关联订单 |
+| 订舱记录 | 船公司/代理、订舱号、船名航次、港口、舱位和异常 |
+| 港务/船期节点 | 经确认的信息字段、变更历史和来源;候选字段包括截单、截关、截港、ETD 和 ETA |
+| 拖车预约 | 服务商、车辆、司机、预约时间窗、到离仓节点和异常 |
+| 拣货任务 | 柜次、货物明细、分配人、作业员、扫描、数量、差异和复核 |
+| 装柜证据 | 柜号、铅封号、照片类型、文件、上传人、时间和可见范围 |
+| 报关批次 | 资料清单版本、文件版本、补件、提交代理和回执 |
+| 出仓时间线 | 事件、前后状态、操作者、发生时间、说明和请求关联 ID |
+
+基础资料引用必须同时保存稳定 ID 和必要快照。订单、客户、仓库、往来单位、港务/船期信息或文件后续修改时,不得改变历史出仓记录。
+
+## 七、应用范围
+
+### 管理后台 `apps/admin-web`
+
+- 出仓单列表、筛选、详情、异常和状态操作。
+- 按已确认的排柜规则提供建议、冲突展示、人工调整、版本对比和确认。
+- 订舱、船期、拖车预约、装柜、柜号、铅封和照片。
+- 报关资料审核、补件、提交批次、回执上传和客户可见控制。
+- 权限至少拆分为查看、排柜、订舱、拖车、仓内复核、报关、确认出仓和冲正。
+
+### 企业客户端 `apps/client-web`
+
+- 查看本企业出仓单、柜次和允许公开的进度时间线。
+- 上传、补充和查看报关资料及处理结果。
+- 下载客户可见的报关回执。
+- 查看预计开船、到港和船期变更,不暴露内部成本、供应商敏感信息和内部备注。
+
+### PDA `apps/pda-uniapp`
+
+- 仓库人员登录、任务领取、箱号选择、扫码拣货和数量确认。
+- 部分拣货、跳拣、撤销、异常上报、待复核和完成提交。
+- 按授权柜次拍摄或选择货柜、铅封照片,确认关联信息后上传,并处理进度、失败重试和重复提交。
+- 弱网、断网、前后台切换、重复提交和换班清理。
+- 真实设备、扫描头和发布方式确认前,不绑定厂商 SDK。
+
+### 服务端 `services/api`
+
+- 最终保证身份、租户、仓库数据范围、权限、状态、门禁、幂等、并发和审计。
+- 管理出仓、排柜、订舱、拖车、拣货、装柜、报关和时间线的事务边界。
+- 文件上传校验类型、大小、内容和权限;使用不可预测标识和授权下载。
+- 为船期、车队、海关等外部接口预留适配层,但三期不承诺正式对接。
+
+## 八、建议里程碑
+
+| 里程碑 | 交付目标 | 进入条件 |
+|---|---|---|
+| P3-M0 规则与设备锁定 | 流程、角色、状态、排柜规则、PDA、文件和验收确认 | 二期到仓契约稳定 |
+| P3-M1 出仓单与排柜 | 出仓单可创建,并按确认范围提供排柜建议、人工确认与追溯 | 排柜规则确认 |
+| P3-M2 订舱与拖车 | 订舱、船期、拖车预约和异常处理可用 | 服务商与权限可用 |
+| P3-M3 PDA 拣货 | 任务生成、扫码、差异、复核和幂等提交可用 | 目标设备与仓库流程确认 |
+| P3-M4 装柜封柜 | 柜号、铅封和照片证据完整,门禁生效 | 文件能力与必传清单确认 |
+| P3-M5 报关协同 | 客户上传、平台审核、补件、提交和回执下载闭环 | 报关资料清单确认 |
+| P3-M6 国内出仓 | 必要子流程满足后可确认出仓并进入等待装船 | 出仓门禁和冲正规则确认 |
+| P3-M7 联调验收 | 跨端、设备、安全、弱网、性能、迁移和发布完成 | P3-M1 至 P3-M6 验收通过 |
+
+## 九、建议开发任务
+
+| ID | 端 | 模块 | 交付内容 | 优先级 | 依赖 |
+|---|---|---|---|---|---|
+| P3-BASE-01 | 公共 | 出仓契约 | 主/子状态、权限、事件、错误码、门禁和快照模型 | P0 | 二期到仓契约 |
+| P3-BASE-02 | 公共 | 数据模型 | 出仓单、排柜、柜次、订舱、拖车、拣货、装柜、报关和时间线 | P0 | P3-BASE-01 |
+| P3-DSP-01 | 后台 | 出仓单 | 列表、筛选、创建、详情、异常和取消 | P0 | P3-BASE-02 |
+| P3-PLAN-01 | 公共 | 排柜规则 | 按已确认规则实现输入、约束、偏好和冲突判断 | P0 | P3-BASE-02、P3-Q1 |
+| P3-PLAN-02 | 后台 | 智能排柜 | 按已确认范围实现建议、人工确认和追溯 | P0 | P3-PLAN-01 |
+| P3-BOOK-01 | 后台 | 订舱 | 订舱和经确认的船名航次、港口、变更及异常 | P0 | P3-DSP-01、P3-Q9 |
+| P3-PORT-01 | 后台/服务端 | 港务信息查询 | 查询系统内预计开船、到港等信息,记录来源和更新时间,并提供授权人工维护兜底 | P0 | P3-BOOK-01、P3-Q9 |
+| P3-TRUCK-01 | 后台 | 拖车预约 | 服务商、车辆司机、时间窗、到离仓和异常 | P0 | P3-DSP-01 |
+| P3-PICK-01 | 公共 | 拣货任务 | 按排柜方案生成任务、明细、差异和复核规则 | P0 | P3-PLAN-02 |
+| P3-PDA-01 | PDA | 扫码拣货 | 领取、扫描、部分拣货、跳拣、撤销和异常 | P0 | P3-PICK-01 |
+| P3-PDA-02 | PDA/服务端 | 弱网幂等 | 重试、去重、冲突、换班和设备缓存清理 | P0 | P3-PDA-01 |
+| P3-LOAD-01 | 后台 | 装柜封柜 | 柜号、铅封号、装柜节点、可配置照片清单和复核 | P0 | P3-PICK-01、P3-Q6 |
+| P3-LOAD-02 | PDA/服务端 | 柜封拍照上传 | 现场拍照/相册选择、关联确认、进度、预览、失败重试、去重和提交 | P0 | P3-LOAD-01、文件能力可用 |
+| P3-CUS-01 | 客户端 | 报关资料 | 清单、上传、补件、版本和进度查看 | P0 | 文件能力可用 |
+| P3-CLEAR-01 | 后台 | 报关协同 | 审核、退回、提交代理、批次、回执和可见范围 | P0 | P3-CUS-01 |
+| P3-CUS-02 | 客户端 | 回执及港务信息 | 回执下载、预计开船/到港信息、数据来源、更新时间和变更时间线 | P0 | P3-PORT-01、P3-CLEAR-01 |
+| P3-GATE-01 | 服务端 | 出仓门禁 | 按确认规则校验必要子流程、确认出仓、等待装船和冲正 | P0 | P3-PORT-01、P3-TRUCK-01、P3-LOAD-01、P3-LOAD-02、P3-CLEAR-01、P3-Q11、P3-Q12 |
+| P3-NOTIFY-01 | 公共 | 通知异常 | 站内通知、阻塞、责任人、时限和失败补偿 | P1 | 核心流程完成 |
+| P3-TEST-01 | 公共 | 自动化测试 | 权限、排柜、幂等、并发、文件、门禁和状态测试 | P0 | 所有 P0 模块 |
+| P3-DEVICE-01 | PDA | 真机验收 | 扫描头、弱网、性能、电量、前后台和发布验证 | P0 | 目标设备确认 |
+| P3-REL-01 | 公共 | 发布验收 | 初始化规则、迁移、联调、演练、灰度和生产发布 | P0 | P3-TEST-01、P3-DEVICE-01 |
+
+## 十、测试与验收重点
+
+- 系统排柜符合已确认的业务规则;如启用建议解释、人工调整、版本或原因记录,对应结果可追溯。
+- 多订单拼柜和一单多柜的件数、重量、体积能与二期实测版本对账。
+- PDA 重复扫码、超量、错货、断网重试和重复提交不产生重复扣减或完成事件。
+- 柜封照片能够在现场完成拍摄、关联确认和上传;失败重试或重复提交不产生多份有效证据。
+- 未完成复核、缺少已确认的必传柜封证据或存在关键阻塞时不能确认出仓。
+- 企业 A 无法查看、上传或下载企业 B 的报关资料和回执。
+- 报关资料替换、退回、补件、提交和回执均能追溯到明确版本。
+- 港务/船期查询结果展示来源和更新时间;变更保留历史并通知授权用户,旧信息不被无痕覆盖。
+- 确认出仓的并发请求只产生一次状态变化和一次有效审计事件。
+- 管理后台覆盖加载、空态、失败、无权限和数据冲突;PDA 覆盖弱网、前后台切换和硬件扫描。
+- 当前三期验收基线为“完成国内出仓,等待装船”,不以海上运输或海外签收作为完成条件;最终以 P3-Q13 确认结果为准。
+
+## 十一、启动前待确认事项
+
+| 编号 | 待确认问题 | 当前建议 |
+|---|---|---|
+| P3-Q1 | 智能排柜需考虑哪些硬约束和软偏好? | 业务先提供可执行规则表;建议必须可解释且人工确认 |
+| P3-Q2 | 是否存在拼柜、一单多柜和拆批出仓? | 数据模型全部支持,页面按实际高频场景逐步开放 |
+| P3-Q3 | “预约托车”是否统一为“预约拖车”? | 建议统一使用行业常用的“拖车”,并确认业务实际含义 |
+| P3-Q4 | 目标 PDA 型号、系统和扫描头接入方式是什么? | 设备确认前保持适配层,不绑定厂商 SDK |
+| P3-Q5 | 拣货是否依赖实时库存和库位可用量? | 若需要,完整 WMS 前置范围会显著扩大,必须单独评估 |
+| P3-Q6 | 柜封照片有哪些必传角度和留存期限? | 启动前由仓库、业务和合规共同锁定 |
+| P3-Q7 | 报关资料清单是否按国家、渠道和货物类型变化? | 建议配置化,并保留下单使用的清单版本 |
+| P3-Q8 | 报关代理如何接收资料和返回回执? | 首版系统内整理加线下提交,正式接口后续评估 |
+| P3-Q9 | 原型中的“港务信息”具体指船期、港口作业状态还是两者,包含哪些字段,由谁维护? | 先确认业务词义和字段;首版建议平台人工维护并审计,外部接口仅预留适配层 |
+| P3-Q10 | 确认出仓后发现错误如何处理? | 不直接回退状态,使用授权冲正动作和反向审计事件 |
+| P3-Q11 | 九个动作中哪些是强制前置,哪些允许并行? | 确认前按原型编号顺序规划,不承诺固定并行关系 |
+| P3-Q12 | “报关回执”具体包含哪些类型,海关放行是否为国内出仓硬门禁? | 当前不默认以放行为门禁;由业务明确接收、申报、退单、查验和放行的含义及门禁 |
+| P3-Q13 | 三期终点以“等待装船”还是“装船发运”为准? | 当前以本期出仓图片的“完成国内出仓,等待装船”为基线,完整流程 SVG 的不同表述待产品确认 |
+
+## 十二、建议实施顺序
+
+1. 锁定待确认事项、业务规则、目标设备和协作责任人。
+2. 统一出仓单、柜次、订舱、拖车、拣货、报关和港务/船期信息的稳定编码。
+3. 先实现服务端权限、状态、门禁、幂等、并发和审计,再接各端页面。
+4. 完成管理后台的出仓编排,再接 PDA 现场执行和客户资料协同。
+5. 使用脱敏数据演练拼柜、一单多柜、错拣、补件、改船和冲正。
+6. 在真实 PDA 和代表性仓库网络环境中完成联调、验收和灰度发布。
diff --git a/三期/三期开发进度表.md b/三期/三期开发进度表.md
new file mode 100644
index 0000000..da59c97
--- /dev/null
+++ b/三期/三期开发进度表.md
@@ -0,0 +1,152 @@
+# 虫虫出海三期开发进度表
+
+> 创建日期:2026-07-28
+> 当前阶段:范围规划与大任务拆分
+> 总体状态:待确认
+> 规划依据:`三期开发规划.md`
+> 维护方式:参考一期进度表,采用“总体大任务 → 详细任务 → 里程碑 → 未确认事项 → 开工准入 → 验收”的结构。
+
+## 一、三期目标
+
+三期承接二期到仓、实测、差异处理、处理单元编码和当前位置记录,完成智能排柜、订舱、拖车预约、PDA 拣货、柜封拍照、报关协同、港务信息查询和国内出仓闭环。
+
+当前验收基线为“完成国内出仓,等待装船”。在 P3-Q13 最终确认前,不把装船发运纳入三期完成条件。
+
+## 二、总体进度(大任务)
+
+| 大任务 ID | 大任务 | 范围 | 状态 | 进度 | 计划开始 | 计划完成 | 负责人 | 关键依赖/备注 |
+|---|---|---|---|---:|---|---|---|---|
+| T01 | 需求确认与原型 | 锁定阶段边界、流程依赖、排柜规则、设备、文件、报关和港务信息;完成页面原型 | 进行中 | 40% | 2026-07-28 | 待排期 | 待分配 | 已盘点 `docs/悦` 三期相关原型;后台有较完整参考,客户端三期页面和 PDA 柜封拍照仍待补 |
+| T02 | 公共契约与数据模型 | 主/子状态、权限、事件、错误码、出仓单、柜次、任务、证据、报关和审计模型 | 待确认 | 0% | 待排期 | 待排期 | 待分配 | 依赖 T01、二期输出契约 |
+| T03 | 出仓单与柜次 | 出仓单创建、列表、详情、订单拆分/拼柜、柜次和时间线 | 待确认 | 0% | 待排期 | 待排期 | 待分配 | 依赖 T02、P3-Q2、P3-Q11 |
+| T04 | 智能排柜 | 排柜规则、系统建议、冲突、人工确认和追溯 | 待确认 | 0% | 待排期 | 待排期 | 待分配 | 依赖 T03、P3-Q1、P3-Q2 |
+| T05 | 订舱与港务信息 | 订舱、变更异常、预计开船/到港信息、来源和更新时间 | 待确认 | 0% | 待排期 | 待排期 | 待分配 | 依赖 T03、P3-Q9、P3-Q11 |
+| T06 | 拖车预约 | 服务商、车辆司机、预约时间窗、到离仓节点和异常 | 待确认 | 0% | 待排期 | 待排期 | 待分配 | 依赖 T03、一期往来单位、P3-Q3 |
+| T07 | PDA 拣货与复核 | 任务生成、领取、扫码、部分拣货、异常、弱网幂等和后台复核 | 待确认 | 0% | 待排期 | 待排期 | 待分配 | 依赖 T04、二期处理单元/位置、P3-Q4、P3-Q5 |
+| T08 | 装柜及柜封证据 | 装柜节点、柜号、铅封号、PDA 拍照上传、照片清单和复核 | 待确认 | 0% | 待排期 | 待排期 | 待分配 | 依赖 T07、文件能力、P3-Q6 |
+| T09 | 报关资料与回执 | 客户上传、后台审核补件、提交代理、回执上传和客户下载 | 待确认 | 0% | 待排期 | 待排期 | 待分配 | 依赖文件能力、P3-Q7、P3-Q8、P3-Q12 |
+| T10 | 国内出仓门禁 | 必要条件校验、确认出仓、阻塞、通知、冲正和审计 | 待确认 | 0% | 待排期 | 待排期 | 待分配 | 依赖 T05~T09、P3-Q10~P3-Q13 |
+| T11 | 客户端出仓协同 | 出仓进度、柜次、回执、预计开船/到港和变更时间线 | 待确认 | 0% | 待排期 | 待排期 | 待分配 | 依赖 T05、T09、T10;客户可见范围 |
+| T12 | 联调测试与发布 | 跨端联调、自动化测试、PDA 真机、安全、弱网、迁移、验收和发布 | 待开始 | 0% | 待排期 | 待排期 | 待分配 | 依赖 T02~T11 完成 |
+
+## 三、详细任务表
+
+详细任务按大任务逐项拆分。当前先建立任务骨架;每次拆分一个大任务,确认交付内容、优先级和依赖后再进入开发。
+
+| ID | 大任务 | 端 | 模块 | 功能/交付内容 | 优先级 | 状态 | 进度 | 依赖 | 负责人 | 备注 |
+|---|---|---|---|---|---|---|---:|---|---|---|
+| P3-T01-00 | T01 | 公共 | 需求确认与原型 | 完成需求确认表、页面清单和原型评审,锁定开工阻断项 | P0 | 进行中 | 40% | - | 待分配 | 已建立文档骨架并完成 `docs/悦` 原型初审,后续逐项确认和裁剪 |
+| P3-T02-00 | T02 | 公共 | 公共契约与数据模型 | 待 T01 确认后拆分 | P0 | 待确认 | 0% | P3-T01-00 | 待分配 | 下一层将拆状态、权限、数据模型、接口和审计 |
+| P3-T03-00 | T03 | 后台/服务端 | 出仓单与柜次 | 待 T02 契约明确后拆分 | P0 | 待确认 | 0% | P3-T02-00 | 待分配 | - |
+| P3-T04-00 | T04 | 后台/服务端 | 智能排柜 | 待排柜规则确认后拆分 | P0 | 待确认 | 0% | P3-T03-00、P3-Q1 | 待分配 | - |
+| P3-T05-00 | T05 | 后台/服务端 | 订舱与港务信息 | 待港务范围和字段确认后拆分 | P0 | 待确认 | 0% | P3-T03-00、P3-Q9 | 待分配 | - |
+| P3-T06-00 | T06 | 后台/服务端 | 拖车预约 | 待流程依赖确认后拆分 | P0 | 待确认 | 0% | P3-T03-00、P3-Q11 | 待分配 | - |
+| P3-T07-00 | T07 | PDA/后台/服务端 | PDA 拣货与复核 | 待拣货输入和设备确认后拆分 | P0 | 待确认 | 0% | P3-T04-00、P3-Q4、P3-Q5 | 待分配 | 已有静态 PDA 原型可复用 |
+| P3-T08-00 | T08 | PDA/后台/服务端 | 装柜及柜封证据 | 待照片清单确认后拆分 | P0 | 待确认 | 0% | P3-T07-00、P3-Q6 | 待分配 | 需新增柜封拍照原型 |
+| P3-T09-00 | T09 | 客户端/后台/服务端 | 报关资料与回执 | 待资料和回执规则确认后拆分 | P0 | 待确认 | 0% | P3-Q7、P3-Q8、P3-Q12 | 待分配 | - |
+| P3-T10-00 | T10 | 后台/服务端 | 国内出仓门禁 | 待流程、回执和终点确认后拆分 | P0 | 待确认 | 0% | P3-T05-00~P3-T09-00 | 待分配 | 高风险状态操作 |
+| P3-T11-00 | T11 | 客户端/服务端 | 客户端出仓协同 | 待客户可见字段确认后拆分 | P0 | 待确认 | 0% | P3-T05-00、P3-T09-00、P3-T10-00 | 待分配 | - |
+| P3-T12-00 | T12 | 公共 | 联调测试与发布 | 待各模块拆分完成后细化测试与发布任务 | P0 | 待开始 | 0% | P3-T02-00~P3-T11-00 | 待分配 | - |
+| P3-T01-PROTO-01 | T01 | 公共 | 原型盘点 | 盘点流程图、后台、企业客户端和 PDA 中与三期相关的页面及交互 | P0 | 已完成 | 100% | - | 待分配 | 2026-07-28 已完成首次盘点,来源为 `docs/悦` |
+| P3-T03-PROTO-01 | T03 | 后台 | 出仓单原型核验 | 对照通用 WMS 出库单、货柜和装柜清单,确定三期出仓单可复用字段与需重做部分 | P0 | 进行中 | 50% | P3-T01-PROTO-01、P3-Q11 | 待分配 | 通用“出库”不能直接等同三期“国内出仓” |
+| P3-T04-PROTO-01 | T04 | 后台 | 智能排柜原型核验 | 映射智能装柜的线路页签、筛选、智能锁定、订单分柜、拖放调整和集装箱详情 | P0 | 已完成 | 100% | P3-T01-PROTO-01 | 待分配 | 原型叫“智能装柜”,与“智能排柜”的业务边界待 P3-Q1 确认 |
+| P3-T05-PROTO-01 | T05 | 后台 | 订舱港务原型核验 | 映射订舱列表、新增/详情、放舱、船名航次、港口和 ETD/ATD/ETA/ATA 字段 | P0 | 已完成 | 100% | P3-T01-PROTO-01 | 待分配 | 港务信息是否独立模块仍待 P3-Q9 确认 |
+| P3-T06-PROTO-01 | T06 | 后台 | 拖车原型核验 | 映射拖车列表、新增表单、运输公司、司机、车头号、装箱日期、费用和附件 | P0 | 已完成 | 100% | P3-T01-PROTO-01 | 待分配 | 预约时间窗和到离仓节点仍需按三期流程补充 |
+| P3-T07-PROTO-01 | T07 | 后台/PDA | 拣货原型核验 | 对照通用 WMS 出库拣货和现有 PDA 集装箱拣货,锁定可复用交互与真实接口缺口 | P0 | 已完成 | 100% | P3-T01-PROTO-01 | 待分配 | PDA 静态交互已有,任务、鉴权、持久化和弱网仍待开发 |
+| P3-T08-PROTO-01 | T08 | 后台 | 装柜证据原型核验 | 映射货柜列表、预装清单、装柜清单、柜号、单证、船期和装柜明细 | P0 | 已完成 | 100% | P3-T01-PROTO-01 | 待分配 | 后台参考较完整,但现场拍照上传原型缺失 |
+| P3-T08-PROTO-02 | T08 | PDA | 柜封拍照原型 | 新增柜次确认、货柜/铅封拍照、照片类型、预览、重试和提交页面原型 | P0 | 待开始 | 0% | P3-Q4、P3-Q6 | 待分配 | `docs/悦` 暂无对应原型 |
+| P3-T09-PROTO-01 | T09 | 后台 | 报关单证原型核验 | 映射报关单列表、单证管理、报关/清关/放行资料及装柜清单附件 | P0 | 已完成 | 100% | P3-T01-PROTO-01 | 待分配 | 客户上传和回执下载页面仍需新建 |
+| P3-T10-PROTO-01 | T10 | 后台 | 出仓门禁原型 | 设计统一门禁检查、阻塞原因、确认出仓和冲正页面 | P0 | 进行中 | 30% | P3-Q10~P3-Q13 | 待分配 | 现有原型只有分散状态和放行字段,无统一出仓门禁页 |
+| P3-T11-PROTO-01 | T11 | 客户端 | 客户端三期原型 | 新增出仓进度、报关资料上传/补件、回执下载和港务/船期页面原型 | P0 | 待开始 | 0% | P3-Q7~P3-Q9、P3-Q12、P3-Q13 | 待分配 | 现有客户端原型未覆盖三期专用页面 |
+
+## 四、原型对照与开发影响
+
+| 大任务 | `docs/悦` 现有原型 | 覆盖判断 | 开发处理 |
+|---|---|---|---|
+| T03 出仓单与柜次 | 通用 WMS 出库单、货柜列表、装柜清单 | 部分参考 | 保留列表、状态和明细交互,按国内出仓业务重新定义对象和门禁 |
+| T04 智能排柜 | 入库单列表中的“智能装柜”弹窗 | 已有参考 | 复用线路、筛选、锁定、分柜和拖放交互,按 P3-Q1 裁剪规则 |
+| T05 订舱与港务信息 | 订舱列表、新增/详情、放舱、货柜船期字段 | 已有参考 | 复用订舱字段和页面结构,确认港务信息范围及来源后裁剪 |
+| T06 拖车预约 | 拖车列表、新增拖车 | 已有参考 | 复用车辆司机和费用字段,补预约时间窗、到仓及离仓节点 |
+| T07 PDA 拣货与复核 | 通用 WMS 出库、PDA 集装箱拣货 | 已有参考 | 保留 PDA 交互,重做真实任务、权限、幂等、弱网和后台复核 |
+| T08 装柜及柜封证据 | 货柜列表、预装清单、装柜清单 | 部分参考 | 后台页面裁剪复用;PDA 货柜/铅封拍照页面新建 |
+| T09 报关资料与回执 | 报关单列表、单证管理、装柜清单附件 | 部分参考 | 后台裁剪复用;客户上传、补件和回执下载页面新建 |
+| T10 国内出仓门禁 | 分散的出库状态、国内报关成功和放行资料 | 部分参考 | 新建统一门禁检查和确认出仓页面,避免直接照搬“已放行”规则 |
+| T11 客户端出仓协同 | 头程下单客户端只有船期字段和出仓时间展示 | 覆盖不足 | 新建三期客户端出仓进度、报关和港务信息页面 |
+
+> `货代SaaS平台原型.html` 是全量平台参考原型,其中海外仓、完整 WMS、费用和清关能力不自动纳入三期;所有复用项仍需经过三期范围裁剪。
+
+## 五、建议拆分模板
+
+每个大任务按照同一顺序拆成可开发、可验收的小任务:
+
+1. `RULE`:业务规则、状态、权限和异常。
+2. `DATA`:数据表、字段、快照、版本和审计。
+3. `API`:接口、鉴权、幂等、并发和错误码。
+4. `ADM` / `CLI` / `PDA`:各端页面与交互。
+5. `TEST`:单元、接口、端到端、权限和边界测试。
+6. `ACCEPT`:业务验收、证据和遗留问题。
+
+例如 T04 智能排柜后续可使用 `P3-T04-RULE-01`、`P3-T04-DATA-01`、`P3-T04-API-01`、`P3-T04-ADM-01`、`P3-T04-TEST-01` 编号。
+
+## 六、建议里程碑
+
+| 里程碑 | 交付目标 | 状态 | 计划完成 |
+|---|---|---|---|
+| P3-M0 需求与原型锁定 | 阶段边界、流程、规则、设备、文件和页面原型确认 | 待确认 | 待排期 |
+| P3-M1 公共契约 | 二三期输入、状态、权限、数据模型和接口契约稳定 | 待排期 | 待排期 |
+| P3-M2 出仓编排 | 出仓单、排柜、订舱、港务和拖车可用 | 待排期 | 待排期 |
+| P3-M3 仓内出仓 | PDA 拣货、复核、装柜和柜封证据闭环 | 待排期 | 待排期 |
+| P3-M4 报关协同 | 客户资料、后台审核、提交代理、回执上传下载闭环 | 待排期 | 待排期 |
+| P3-M5 国内出仓 | 门禁满足后可确认出仓并进入当前约定终点 | 待排期 | 待排期 |
+| P3-M6 三期上线 | 联调、真机、安全、测试、验收和生产发布完成 | 待排期 | 待排期 |
+
+## 七、未确认事项(需求确认进度)
+
+当前共 13 项待确认事项,其中 7 项为开工阻断、5 项为模块阻断、1 项为非阻断。完整建议、负责人、计划确认日期和最终结论统一维护在 [三期需求确认表](三期需求确认表.md);开工阻断项未确认前,受影响的大任务保持“待确认”。
+
+| 编号 | 阻断级别 | 待确认事项 | 状态 | 主要影响 |
+|---|---|---|---|---|
+| P3-Q1 | 开工阻断 | 智能排柜的硬约束和软偏好 | 待确认 | T04 智能排柜、T07 拣货任务 |
+| P3-Q2 | 开工阻断 | 是否支持拼柜、一单多柜和拆批出仓 | 待确认 | T03 出仓单与柜次、T04 智能排柜 |
+| P3-Q3 | 非阻断 | “预约托车”是否统一为“预约拖车” | 待确认 | T06 拖车预约、页面与接口文案 |
+| P3-Q4 | 模块阻断 | PDA 型号、系统和扫描头接入方式 | 待确认 | T07 PDA 拣货、T08 柜封拍照、真机验收 |
+| P3-Q5 | 开工阻断 | 拣货是否依赖实时库存和库位可用量 | 待确认 | T02 二三期契约、T07 PDA 拣货 |
+| P3-Q6 | 模块阻断 | 柜封照片必传类型、角度、数量和留存期限 | 待确认 | T08 装柜证据、T10 出仓门禁 |
+| P3-Q7 | 模块阻断 | 报关资料清单是否按国家、渠道和货物类型变化 | 待确认 | T09 报关资料、文件版本 |
+| P3-Q8 | 模块阻断 | 报关代理接收资料和返回回执的方式 | 待确认 | T09 报关协同、回执上传 |
+| P3-Q9 | 开工阻断 | 港务信息的业务含义、字段和维护方 | 待确认 | T05 订舱港务、T11 客户端展示 |
+| P3-Q10 | 模块阻断 | 确认出仓后的错误处理和冲正方式 | 待确认 | T10 出仓门禁、权限和审计 |
+| P3-Q11 | 开工阻断 | 九个动作的强制前置和并行关系 | 待确认 | T03~T10 全流程和状态机 |
+| P3-Q12 | 开工阻断 | 报关回执类型及海关放行是否为出仓硬门禁 | 待确认 | T09 报关状态、T10 出仓门禁 |
+| P3-Q13 | 开工阻断 | 三期终点是等待装船还是装船发运 | 待确认 | 阶段边界、状态、里程碑和验收 |
+
+## 八、开工准入清单
+
+产品和业务完成需求确认后,先进入“开工准备”;以下准入项全部通过后,三期才能从范围规划正式切换到全面开发。
+
+| 准入编号 | 准入条件 | 当前状态 | 责任方 | 完成证据 |
+|---|---|---|---|---|
+| P3-GO-01 | P3-Q1~P3-Q13 均形成明确结论,7 项开工阻断全部解除 | 进行中 | 产品、业务 | `三期需求确认表.md` 状态均为已确认并填写最终结论 |
+| P3-GO-02 | 确认结论已同步开发规划、进度表、页面清单和验收范围 | 待开始 | 产品、项目负责人 | 四份文档口径一致,无未标注的候选规则 |
+| P3-GO-03 | 关键缺失原型已补齐并评审,包括出仓门禁、客户端三期页面和 PDA 柜封拍照 | 进行中 | 产品、设计、业务 | 页面清单中的关键页面达到已确认状态 |
+| P3-GO-04 | T02 公共契约完成,二期输入、状态机、权限、数据模型、接口、错误码和审计口径稳定 | 待开始 | 前后端、架构/技术负责人 | 契约评审记录及稳定的数据/API 定义 |
+| P3-GO-05 | T03~T12 已拆成 RULE、DATA、API、ADM/CLI/PDA、TEST、ACCEPT 任务,并填写负责人和计划 | 待开始 | 项目负责人、研发、测试 | 详细任务可独立开发、联调和验收 |
+| P3-GO-06 | 产品、业务、研发和测试完成开工评审,确认范围、依赖、风险和首批任务 | 待开始 | 项目负责人 | 开工评审纪要及明确的 GO 结论 |
+
+准入口径:`P3-GO-01` 完成后可以进入 T02 契约设计和详细任务拆分;`P3-GO-01~P3-GO-06` 全部通过后,才进入全面功能开发。
+
+## 九、状态维护规则
+
+- 状态统一使用:待确认、待开始、进行中、联调中、测试中、已完成、已阻塞。
+- 进度填写 `0%~100%`;只有开发、测试和业务验收均完成后才能填写 `100%`。
+- 开始开发时填写负责人、计划开始和计划完成日期。
+- 出现阻塞时在备注中填写阻塞原因、责任人和预计解除时间。
+- 大任务进度应由其详细任务加权汇总;当前骨架阶段先人工维护,拆分完成后再确定权重。
+
+## 十、下一步拆分顺序
+
+1. 先处理 T01,逐项确认 P3-Q1~P3-Q13,并补齐关键页面原型。
+2. 拆 T02 公共契约与数据模型,固定二期输入和三期核心对象。
+3. 按业务顺序拆 T03~T10,每个模块补齐规则、数据、接口、页面和测试。
+4. 拆 T11 客户端可视范围和交互。
+5. 最后拆 T12 联调、真机、验收和发布任务。
diff --git a/三期/三期需求确认表.md b/三期/三期需求确认表.md
new file mode 100644
index 0000000..1ac4b11
--- /dev/null
+++ b/三期/三期需求确认表.md
@@ -0,0 +1,69 @@
+# 虫虫出海三期需求确认表
+
+> 创建日期:2026-07-28
+> 当前状态:确认中
+> 用途:记录会影响三期范围、流程、数据模型、页面和验收的产品决策。
+
+## 一、维护规则
+
+- 状态统一使用:待确认、确认中、已确认、已取消。
+- 阻断级别统一使用:开工阻断、模块阻断、非阻断。
+- 结论确认后同步更新 `三期开发规划.md`、`三期开发进度表.md` 和受影响的页面原型。
+- 未确认事项只能作为候选方案,不能直接写成固定开发或验收承诺。
+
+## 二、确认事项
+
+| 编号 | 决策/问题 | 当前建议 | 阻断级别 | 状态 | 负责人 | 计划确认 | 最终结论 | 影响模块 |
+|---|---|---|---|---|---|---|---|---|
+| P3-Q1 | 智能排柜需考虑哪些硬约束和软偏好? | 业务提供可执行规则表,建议可解释并由人工确认 | 开工阻断 | 待确认 | 待分配 | 待排期 | - | 智能排柜、拣货任务 |
+| P3-Q2 | 是否存在拼柜、一单多柜和拆批出仓? | 数据模型预留能力,页面按高频场景逐步开放 | 开工阻断 | 待确认 | 待分配 | 待排期 | - | 出仓单、柜次、排柜、拣货 |
+| P3-Q3 | 原型“预约托车”是否统一为“预约拖车”? | 建议使用行业常用的“拖车”,同时确认业务实际含义 | 非阻断 | 待确认 | 待分配 | 待排期 | - | 页面文案、接口字段说明 |
+| P3-Q4 | 目标 PDA 型号、系统和扫描头接入方式是什么? | 确认前保持设备适配层,不绑定厂商 SDK | 模块阻断 | 待确认 | 待分配 | 待排期 | - | PDA 拣货、真机验收 |
+| P3-Q5 | 拣货是否依赖实时库存和库位可用量? | 默认使用二期处理单元和当前位置;如需完整库存,单独评估 WMS 范围 | 开工阻断 | 待确认 | 待分配 | 待排期 | - | 二三期契约、拣货、库存边界 |
+| P3-Q6 | 柜封照片有哪些必传类型、角度、数量和留存期限? | 使用可配置清单,由仓库、业务和合规共同确认 | 模块阻断 | 待确认 | 待分配 | 待排期 | - | 装柜、PDA 拍照、文件存储、出仓门禁 |
+| P3-Q7 | 报关资料清单是否按国家、渠道和货物类型变化? | 清单配置化,并保存业务使用的清单版本 | 模块阻断 | 待确认 | 待分配 | 待排期 | - | 客户资料、报关审核、文件版本 |
+| P3-Q8 | 报关代理如何接收资料并返回回执? | 首版系统内整理、线下提交,正式接口后续评估 | 模块阻断 | 待确认 | 待分配 | 待排期 | - | 报关协同、回执上传 |
+| P3-Q9 | “港务信息”指船期、港口作业状态还是两者,包含哪些字段,由谁维护? | 先确认词义和字段;首版平台人工维护并审计 | 开工阻断 | 待确认 | 待分配 | 待排期 | - | 订舱、港务查询、客户展示 |
+| P3-Q10 | 确认出仓后发现错误如何处理? | 不直接回退状态,使用授权冲正和反向审计事件 | 模块阻断 | 待确认 | 待分配 | 待排期 | - | 出仓门禁、权限、审计 |
+| P3-Q11 | 九个动作中哪些是强制前置,哪些允许并行? | 确认前按原型编号顺序规划 | 开工阻断 | 待确认 | 待分配 | 待排期 | - | 全流程、状态机、页面进度 |
+| P3-Q12 | 报关回执包含哪些类型,海关放行是否为国内出仓硬门禁? | 当前不默认以放行为门禁,业务明确各类回执含义 | 开工阻断 | 待确认 | 待分配 | 待排期 | - | 报关状态、出仓门禁、客户回执 |
+| P3-Q13 | 三期终点以“等待装船”还是“装船发运”为准? | 当前以“完成国内出仓,等待装船”为基线 | 开工阻断 | 待确认 | 待分配 | 待排期 | - | 阶段边界、状态、里程碑、验收 |
+
+## 三、建议确认顺序
+
+1. 先确认 P3-Q13、P3-Q11,锁定阶段终点和流程依赖。
+2. 再确认 P3-Q1、P3-Q2、P3-Q5,锁定排柜、柜次和拣货输入。
+3. 然后确认 P3-Q12、P3-Q7、P3-Q8,锁定报关和出仓门禁。
+4. 最后确认设备、照片、港务信息、冲正和文案事项。
+
+## 四、产品与业务确认会议
+
+### 4.1 参会角色
+
+- 产品负责人:逐项说明问题、候选方案和影响范围,维护最终结论。
+- 业务负责人:确认流程、规则、例外、责任边界和客户可见范围。
+- 仓库/运营代表:确认现场作业、PDA、照片、拖车、装柜和冲正可执行性。
+- 研发与测试代表:识别数据、接口、设备、权限和验收风险,不代替业务作决定。
+
+### 4.2 会议输入
+
+- 本确认表中的 P3-Q1~P3-Q13。
+- `三期开发规划.md` 的流程、状态、里程碑和任务骨架。
+- `三期页面与原型清单.md` 中已有参考原型和待补页面。
+- 二期输出契约、目标 PDA 信息、文件存储能力及报关/港务协作现状。
+
+### 4.3 每项确认要求
+
+1. 必须填写负责人、计划确认日期和可执行的最终结论,不能只记录“按建议处理”。
+2. 最终结论需明确正常流程、异常/冲正、权限责任和验收口径。
+3. 暂缓事项必须写明本期是否排除、临时方案、影响模块和再次确认日期。
+4. 开工阻断项未解除时,不得将受影响模块标记为可开发。
+5. 会议结束后,将结论同步到开发规划、开发进度表、页面原型和后续验收任务。
+
+### 4.4 会议输出
+
+- 13 项确认事项的状态和最终结论。
+- 需要新增或调整的原型清单。
+- 三期范围内/范围外清单及跨期依赖。
+- 仍有风险的事项、责任人和完成日期。
+- 是否允许进入 T02 契约设计与任务拆分的明确结论。
diff --git a/三期/三期页面与原型清单.md b/三期/三期页面与原型清单.md
new file mode 100644
index 0000000..66936e1
--- /dev/null
+++ b/三期/三期页面与原型清单.md
@@ -0,0 +1,55 @@
+# 虫虫出海三期页面与原型清单
+
+> 创建日期:2026-07-28
+> 当前状态:页面盘点中
+> 原型依据:`参考资料/出仓流程.png`、现有 PDA 拣货原型
+
+## 一、维护规则
+
+- 页面状态统一使用:待确认、待原型、原型中、待评审、已确认、开发中、已完成。
+- 页面只有在业务流程、角色权限和关键字段确认后才能标记“已确认”。
+- 页面原型至少覆盖正常态、空态、加载态、失败态、无权限态和关键冲突态。
+- 当前先列页面级大项,后续按开发进度表的大任务逐项拆交互、字段和验收。
+
+## 二、管理后台
+
+| 页面 ID | 页面/入口 | 主要能力 | 对应大任务 | 原型状态 | 依赖确认项 | 备注 |
+|---|---|---|---|---|---|---|
+| P3-ADM-01 | 出仓单列表 | 查询、筛选、创建、异常和状态展示 | T03 出仓单与柜次 | 部分参考原型 | P3-Q2、P3-Q11 | 可参考通用 WMS 出库单,但需重定义国内出仓对象 |
+| P3-ADM-02 | 出仓单详情 | 柜次、任务、证据、报关和时间线 | T03 出仓单与柜次 | 部分参考原型 | P3-Q11、P3-Q13 | 可组合参考货柜列表和装柜清单,缺统一详情页 |
+| P3-ADM-03 | 智能排柜 | 生成建议、冲突、调整和确认 | T04 智能排柜 | 已有参考原型 | P3-Q1、P3-Q2 | 参考“智能装柜”弹窗,需确认名称和规则边界 |
+| P3-ADM-04 | 订舱管理 | 订舱申请、结果、变更和异常 | T05 订舱与港务信息 | 已有参考原型 | P3-Q9、P3-Q11 | 已有订舱列表、新增和详情 |
+| P3-ADM-05 | 港务/船期信息 | 查询系统信息、人工维护、来源和更新时间 | T05 订舱与港务信息 | 部分参考原型 | P3-Q9 | 订舱详情和货柜列表已有船期字段,缺独立查询口径 |
+| P3-ADM-06 | 拖车预约 | 服务商、车辆司机、时间窗和节点 | T06 拖车预约 | 已有参考原型 | P3-Q3、P3-Q11 | 已有拖车列表和新增表单,需补预约及到离仓节点 |
+| P3-ADM-07 | 拣货任务与复核 | 分配、进度、差异、复核和异常 | T07 PDA 拣货与复核 | 部分参考原型 | P3-Q4、P3-Q5 | 可参考通用 WMS 出库和 PDA 原型,缺三期真实任务页 |
+| P3-ADM-08 | 装柜封柜 | 柜号、铅封号、照片清单和复核 | T08 装柜及柜封证据 | 部分参考原型 | P3-Q6 | 已有货柜/预装/装柜清单,缺现场照片复核闭环 |
+| P3-ADM-09 | 报关协同 | 资料审核、补件、提交批次和回执上传 | T09 报关资料与回执 | 部分参考原型 | P3-Q7、P3-Q8、P3-Q12 | 已有报关单和单证管理,缺客户补件协同闭环 |
+| P3-ADM-10 | 国内出仓确认 | 门禁检查、确认、阻塞和冲正 | T10 国内出仓门禁 | 待原型 | P3-Q10、P3-Q11、P3-Q12、P3-Q13 | 现有状态分散,无统一门禁确认页 |
+
+## 三、企业客户端
+
+| 页面 ID | 页面/入口 | 主要能力 | 对应大任务 | 原型状态 | 依赖确认项 | 备注 |
+|---|---|---|---|---|---|---|
+| P3-CLI-01 | 出仓进度列表 | 查看本企业出仓单、柜次和当前节点 | T11 客户端出仓协同 | 待原型 | P3-Q11、P3-Q13 | 现有客户端未覆盖三期专用页面 |
+| P3-CLI-02 | 出仓进度详情 | 时间线、柜号、船期和允许公开的证据 | T11 客户端出仓协同 | 待原型 | P3-Q6、P3-Q9 | 现有客户端只有零散船期/出仓时间字段,需新建详情页 |
+| P3-CLI-03 | 报关资料上传 | 清单、上传、补件、版本和处理进度 | T09 报关资料与回执 | 待原型 | P3-Q7 | 文件规则确认后细化 |
+| P3-CLI-04 | 报关回执下载 | 回执列表、类型、版本和授权下载 | T09 报关资料与回执 | 待原型 | P3-Q8、P3-Q12 | 区分客户可见回执 |
+| P3-CLI-05 | 港务/船期信息 | 预计开船、到港、来源、更新时间和变更 | T11 客户端出仓协同 | 待原型 | P3-Q9 | 不将过期信息展示为实时信息 |
+
+## 四、PDA
+
+| 页面 ID | 页面/入口 | 主要能力 | 对应大任务 | 原型状态 | 依赖确认项 | 备注 |
+|---|---|---|---|---|---|---|
+| P3-PDA-01 | 登录 | 人员登录和快捷登录 | T07 PDA 拣货与复核 | 已有静态原型 | P3-Q4 | 真实鉴权待服务端接入 |
+| P3-PDA-02 | 箱号与任务选择 | 领取任务、选择箱号和查看进度 | T07 PDA 拣货与复核 | 已有静态原型 | P3-Q4、P3-Q5 | 需对接真实任务和处理单元 |
+| P3-PDA-03 | 扫码拣货 | 扫码、整拣、部分拣货、跳拣和撤销 | T07 PDA 拣货与复核 | 已有静态原型 | P3-Q4、P3-Q5 | 已有本地交互,缺服务端 |
+| P3-PDA-04 | 拣货提交 | 汇总、异常、提交和完成统计 | T07 PDA 拣货与复核 | 已有静态原型 | P3-Q5 | 需补幂等和冲突处理 |
+| P3-PDA-05 | 柜封拍照上传 | 柜次确认、拍照/相册、类型、预览和重试 | T08 装柜及柜封证据 | 待原型 | P3-Q4、P3-Q6 | `docs/悦` 中暂无对应页面,属于明确原型缺口 |
+
+## 五、下一步拆分顺序
+
+1. 先补 P3-ADM-01、P3-ADM-02,确定三期后台信息架构。
+2. 根据 P3-Q1 结论补 P3-ADM-03 智能排柜原型。
+3. 根据 P3-Q5 复核现有 PDA 拣货原型并补真实状态。
+4. 根据 P3-Q6 优先补 P3-PDA-05 柜封拍照上传原型。
+5. 报关和港务规则确认后,再补客户端及对应后台页面。
diff --git a/三期/参考资料/出仓流程.png b/三期/参考资料/出仓流程.png
new file mode 100644
index 0000000000000000000000000000000000000000..8d8b1a7d2fed905d9b50e9f98fbdbe072e1f8b3f
GIT binary patch
literal 81714
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