warehouse应用的前端仓库

yinxia.yang 58cb7eca34 up vor 17 Stunden
public 5b2f601325 up vor 20 Stunden
src 58cb7eca34 up vor 17 Stunden
.env.development b6460e3528 up vor 19 Stunden
.env.production b6460e3528 up vor 19 Stunden
.gitignore 9b095f9988 Initial commit vor 4 Tagen
README.md abaf2c6b13 up vor 1 Tag
forward.html 43fd03b740 up vor 21 Stunden
index.html e816fbafa4 替换logo,及样式 vor 4 Tagen
package-lock.json 9b095f9988 Initial commit vor 4 Tagen
package.json 1d7f0ae100 清理# "vue-router": "^5.3.1" vor 3 Tagen
tsconfig.app.json 9b095f9988 Initial commit vor 4 Tagen
tsconfig.json 9b095f9988 Initial commit vor 4 Tagen
tsconfig.node.json 9b095f9988 Initial commit vor 4 Tagen
vite.config.ts 9b095f9988 Initial commit vor 4 Tagen

README.md

HS 仓储运营台

上海闵行仓一期前端工程。Vue 3、TypeScript、Vite、Element Plus、Pinia、Axios、MSW。原始 PRD、交互说明及 HTML 原型保留在上级目录。

运行

建议 Node.js 22.13+。已在 Node 22.12 下通过构建及测试,但部分开发依赖提示更高版本要求。

在本目录执行:

npm install
npm run dev

打开终端打印的地址,通常是 http://localhost:5173/。演示账号 demo,密码 123,仅用于本地 Mock。

npm test
npm run build
npm run preview

当前 package.jsonscripts 配置如下:

命令 实际执行 用途
npm run dev vite 启动本地开发服务
npm run build vue-tsc -b && vite build 先执行 TypeScript / Vue 类型检查,再生成生产构建产物
npm run preview vite preview 本地预览生产构建产物,需先执行 npm run build,不作为生产服务器使用
npm test vitest run 单次运行全部测试,不进入监听模式

开发模式默认开启 Mock。生产构建默认关闭 Mock,preview 需要配套后端,不会自动使用演示数据。构建有大 chunk 警告,不影响运行;正式发布前建议进行路由和组件按需拆包。

发布部署

发布后页面访问地址:http://wms.mangoo.hobbystocks.cn 。生产构建使用 .env.production,OAuth 回调地址为 http://wms.mangoo.hobbystocks.cn/login,不再使用内网开发地址。

  • 执行 npm run build,将 dist 目录部署到该域名的站点根目录。环境变量在构建时写入产物,修改后必须重新构建并发布。
  • VITE_API_WMS_URL=/ 保持同源访问,由部署服务将 /api/wms/ 请求转发到实际 WMS 后端,不要返回前端 HTML。
  • 认证中心须为客户端 client 注册完整回调地址 http://wms.mangoo.hobbystocks.cn/login,并允许页面来源 http://wms.mangoo.hobbystocks.cn 跨域调用令牌接口。
  • 当前生产配置保留 VITE_OAUTH_RESPONSE_MODE=form_post。部署端必须接收 /login 的 POST 回调,并将 codestate 或认证错误参数转交到同源前端 URL 查询参数;仅配置静态页面回退不足以处理 POST 回调。若没有该服务端处理,应在确认认证中心支持后改用 query 模式并重新构建。
  • /login 的 GET 请求应返回应用入口。认证服务仍使用现有的 https://oidc-dev.mangoo.hobbystocks.cn,发布前需确认该认证环境是否适用;页面域名不替代认证服务地址。
  • 当前按提供的 HTTP 地址配置,但 HTTP 不加密页面及同源业务请求,存在令牌和业务数据泄露风险。正式使用建议启用 HTTPS,并同步更新回调地址、认证白名单及跨域配置。

上述配置不代表 DNS、反向代理、认证白名单或线上登录联调已经完成。

功能与数据

  • 登录、工作台、基础资料、SKU、入库、出库、库存台账。
  • 草稿不影响库存,可编辑删除;完成流水不可编辑删除,使用反向流水冲销。
  • 正整数数量、禁止负库存、剩余可冲销数量限制、历史 SKU 快照。
  • 内外部订单、条件物流字段、图片上传及预览。
  • 查询筛选、分页、SKU 库存和关联流水查看。

工作台当日笔数按上海时区的完成时间统计,包含冲销产生的对应方向流水,不跨 SKU 汇总数量。

Mock 数据保存在当前浏览器、当前站点的 IndexedDB(idb-keyval 默认数据库内的 warehouse-db-v1 键),刷新后保留。图片以 data URL 存储,单张支持 5MB 内 PNG/JPEG/WebP,不适合真实大量附件。会话放在 sessionStorage。不要录入敏感或正式业务数据,也不要多标签页并发写入;Mock 不提供跨标签页事务一致性。

首次使用自动载入原型 Mock 数据:9 项基础资料、5 个 SKU、8 条已完成流水及 2 条草稿,含内部订单、外部订单、快递、闪送和部分冲销场景。SKU000001 至 SKU000005 的库存依次为 1 个、1 盒、3 个、2 盒、10 包。示例凭证可预览,明确标记 Mock,不是真实订单或物流凭证。

种子数据保留原型的 2026-09-05 至 2026-09-07 日期,其他日期查看工作台时,当日出入库笔数不会包含这些历史流水。仅新库或基础资料完全未修改的原始空库会自动初始化,已有业务记录或基础资料修改不会被覆盖。清理站点数据会删除全部本地业务记录,请先确认无需要保留的数据。

接口接入

统一认证登录

真实认证模式下,业务接口返回 HTTP 401 时自动清理认证态,生成新的 PKCE 会话并跳转认证中心;同一页面跳转期间的并发 401 只处理一次。Mock 模式仍返回本地登录页,403 不触发认证跳转。授权配置错误或跳转失败时回退到登录页手动重试;主动退出仍暂停自动认证。此并发保护不限制跨页面的重新认证次数,若后端持续拒绝新令牌,可能反复跳转,需排查认证与业务后端配置。

src/store/index.ts 统一导出仓储 useWarehouse 和认证 useStore(默认导出)。认证工具通过 Pinia 读写令牌、显示名称、角色与 PKCE 临时会话,并同步持久化到当前标签页的 sessionStorage,刷新或授权跳转后可恢复;退出或认证失效时清理相应缓存。PKCE 会话不设置本地过期时间,保留一次性消费校验;重新发起授权会覆盖旧会话,缓存仍受 sessionStorage 生命周期约束。仓储数据不重复缓存到认证 Store,仍由原 API 和 Mock IndexedDB 管理。

src/views/Login/index.vue 为登录入口。VITE_USE_MOCK=true 时保留本地账号登录;关闭 Mock 后使用 OAuth 授权码 + PKCE S256 登录,认证失败不会自动循环跳转。

在本地环境文件或构建环境中配置以下变量(示例域名需替换为实际认证服务):

VITE_USE_MOCK=false
VITE_OAUTH_REDIRECT_URI=http://localhost:5175/
VITE_OAUTH_RESPONSE_MODE=query

授权服务地址 VITE_API_AUTH_URL;系统自动拼接 /oauth2/authorize/oauth2/token,单独配置的完整接口地址优先。客户端 ID 默认 client,实际值必须与认证中心注册信息一致。

认证中心需注册支持 PKCE 的公共客户端,并将回调地址加入白名单。回调地址必须与配置完全一致且不含 #,未配置时默认使用当前站点 origin + /login,部署服务需将该路径回退到应用入口。默认采用 response_mode=query,应用读取地址栏中的 code/state 后清除临时参数,再进入 Hash 路由。只有接入服务端 POST 回调转发后,才可将 VITE_OAUTH_RESPONSE_MODE 改为 form_post

Token 接口使用表单编码,需允许前端跨域访问或配置同源代理,返回标准 access_tokentoken_type=Bearer。不在前端配置 client_secret;若认证中心强制要求客户端密钥或 form_post,应由后端代理完成回调与令牌交换。未接入权限接口,不将未经验证的 JWT 内容作为权限依据;可选的令牌响应字段 displayName 仅用于界面显示。

PKCE 使用 CryptoJS 同步计算 SHA-256/Base64URL,随机值仍由 crypto.getRandomValues 生成。授权链接包含随机 state 和 nonce,临时会话使用 sessionStorage 持久化,不设置本地过期时间,保留 state、回调地址和一次性消费校验;认证中心仍决定授权码和令牌的有效期。目前不消费 ID Token,nonce 发送和缓存不代表已完成 ID Token 校验。生产环境应使用 HTTPS。现有本地退出只清除本应用会话,不会注销认证中心的 SSO 会话。环境变量修改后需重启开发服务或重新构建。

页面通过 src/api/index.ts 中的统一接口方法请求;src/http/index.ts 配置 Axios 实例、请求 Token 注入和响应 401 拦截;src/mock.ts 在启用 Mock 时拦截接口并返回模拟数据;src/domain.ts 定义数据模型及库存规则。

在部署环境配置 VITE_USE_MOCK=falseVITE_API_BASE_URL,并为跨域或同源 /api 配置真实服务。所有 VITE 变量都会进入前端,不能存储秘密。

多服务配置

SKU 管理统一使用 /api/wms/sku/page 服务端分页,请求类型为 WmsSkuQueryPageRequest,支持 keywordspecstatuscategoryIdsportTypeIdbrandId 筛选。keyword 同时匹配 SKU 编码和商品名称,不再发送旧的 skuIdproductName 查询字段,也不使用下拉搜索接口替代管理查询。列表按响应 stock 展示库存,0 正常显示,字段缺失显示占位符,不在前端计算或跨 SKU 汇总。详情展示 recentFlows 字符串列表;契约注明库存仅分页返回,详情不展示未经重新查询的列表库存。

库存台账顶部统计独立请求 /api/wms/ledger/adminSummary:优先使用实际接口的 warehouseName 展示仓库名称,兼容生成契约中的 queryScope;兼容类型定义在应用层,不修改生成文件。totalStockCount 为启用 SKU 数,todayFlowCount 为按创建时间统计的当日入库、出库、冲销/更正流水数。统计不由当前页或筛选结果推算,冲销成功后重新获取;零值正常展示,加载或失败时显示占位符。

台账普通流水详情同时传递 flowNoflowTyperecordId。冲销方向按 reversalDirection 数字值处理(1=入库、2=出库);台账详情缺少方向时回退到原流水类型,列表缺少方向时回退到带符号数量。首页轨迹同时兼容旧的 IN / OUT 方向值。

当前 WmsSkuUpdateRequest 包含分类、运动类型、品牌、规格字段,但生成服务说明仍限定仅修改商品名称、配置明细、备注。前端保留原编辑限制,待后端明确规则后再同步,避免仅依据可选字段扩展业务权限。

WMS 接口通过 api.wmsApi 调用。应用使用的接口模型保存在 src/api/types,由 src/api/indexType.ts 统一转出;这些类型文件需要提交到 Git。automation/apiType 仅是临时接口契约,不参与应用编译,也不需要提交。接口更新后需将相关模型同步到 src/api/types,再核对 API 封装与页面用法。基础资料 dataType 使用数字:1=产品种类、2=运动类型、3=品牌。

出入库分页分别使用 WmsInboundPageRequest / WmsOutboundPageRequest,与草稿保存请求分离。列表与详情使用新版 Response 模型;响应附件从 attachments 读取,提交时仍使用 fileUrls / fileNames / fileTypes。操作人优先显示 updateUser,为空时使用 createUser。分页继续读取顶层 rows / total,业务成功码兼容 0200。生成目录仅作为接口契约,运行时仍经 Axios 实例发送请求,不直接使用生成客户端的固定地址。

services.wms 使用独立的 VITE_API_WMS_URL,只配置服务根地址,不要追加 /api/api/wms,接口封装已包含 /api/wms/... 前缀。开发环境配置为 http://192.168.32.159:8096;生产环境配置为 /,由部署代理转发同源 /api/wms 请求;未配置时也使用同源请求。该实例始终请求真实 WMS,不受 Mock 开关控制,本地 Mock 不代表真实接口已完成联调。

页面继续调用 api,由 API 层选择服务。src/http/index.ts 中的 services.warehouseservices.files 是独立 Axios 实例,共享 Token 注入和全局并发 401 跳转保护;http 保留为仓储实例的兼容别名。认证实例 authHttp 不注入业务 Token,也不触发业务 401 跳转。

VITE_USE_MOCK=false
VITE_API_BASE_URL=/api
VITE_API_WAREHOUSE_URL=https://warehouse.example.com/api
VITE_API_FILES_URL=https://files.example.com/api

两个服务地址未配置时分别回退到 VITE_API_BASE_URL,该变量未配置时使用 /api。现有业务接口使用仓储服务,上传接口使用文件服务,路径仍为 /files。Mock 模式下两者固定使用本地 /api,数据仍由 MSW 和 IndexedDB 模拟,不代表已接入真实服务。

后续新增服务,在 services 中注册实例,然后在 API 方法中选择该实例:

// services 中新增一项,地址应配置为可信后端。
orders: createServiceHttp(import.meta.env.VITE_API_ORDERS_URL || defaultBaseURL)

// API 方法中调用;响应类型定义在 src/api/indexType.ts。
orders: async () => (await services.orders.get<Order[]>('/orders')).data

默认服务工厂会发送当前业务 Bearer Token,仅用于接受同一认证体系令牌的可信服务。无需业务认证的服务使用 createServiceHttp(baseURL, false);不同认证体系需要单独设计令牌获取与失效处理,不能直接复用当前 Token。配置跨域地址时需由后端允许当前站点、Authorization 请求头及对应请求方法;相对地址需由开发或部署代理转发,本项目不会根据这些变量自动创建代理。修改环境变量后需要重启开发服务或重新构建。

方法 路径 用途
POST /login {username,password},返回 {username,token}
GET /state 返回 {masters,skus,entries,sequence}
POST /masters 新增或更新基础资料
DELETE /masters/:id 删除未使用资料
POST /skus 新增或更新 SKU
POST /entries {data,submit},保存草稿或提交
DELETE /entries/:id 删除草稿
POST /entries/:id/reverse {quantity,evidence,remark},冲销
POST /files multipart file,返回 {id,name,url}

除登录外使用 Authorization: Bearer <token>。字段错误返回 HTTP 422 {message,fields},未登录返回 401。完整实体字段见 domain 类型;当前聚合 state 接口服务于原型联调,真实数据量增长后应改为后端分页查询。

真实后端必须独立实现鉴权、权限、库存事务、并发校验、幂等提交、附件存储及审计,不能将前端校验或 Mock 会话当作安全保证。

验证范围

  • TypeScript 与 Vite 生产构建通过。
  • 9 项 Vitest 测试通过:6 项业务测试覆盖草稿与重复提交、数量和库存限制、部分及全额冲销、反向回补、凭证及字段清理、快照保留;3 项 Mock 测试覆盖原型库存与关联、流水提交规则、空库初始化及已有数据保护。
  • 浏览器已验证登录、页面创建 SKU、Mock 接口入出库及冲销、台账库存显示;390px 手机页面无页面级横向溢出。
  • 尚未覆盖全部表单分支的自动化 UI 回归,也未接入或验证真实后端。