vue-h5-template/openapi/schema.yaml
fonghehe 7b1c087c00 feat: 重构整体架构并迁移 oxlint/oxfmt 工具链
架构与目录:
- 引入分层 API:transport/interceptors 收敛到 src/api/client.ts,
  域名端点拆到 src/api/modules,页面不再直接依赖 Axios
- 服务层(src/services)承载 AI 流式解析与框架无关的 provider
- TanStack Query 接管服务端状态,Pinia 仅保留会话/主题等客户端状态
- 路由表显式懒加载,组件/组合式函数按职责拆分

功能:
- AI 流式对话:fetchStreamProvider + useStreamingChat + 安全 Markdown 渲染
- 商店模块:商品列表/详情/购物车/后台管理,多语言(中/英/日)
- 示例页:请求错误矩阵、query 缓存、移动端适配、图标演示
- 离线页、PWA、图片优化、eruda 调试等能力

工程化:
- ESLint/Prettier 迁移到 oxlint/oxfmt,stylelint 保留
  - 新增 oxlint.config.ts(移植自 monorepo 的 @vh5/oxlint-config 全套规则)
  - 新增 oxfmt.config.ts(移植自 @vh5/oxfmt-config,printWidth 80)
  - lint-staged、format、lint 脚本同步切换
- pnpm 作为唯一包管理器,删除 package-lock.json 与 yarn.lock
- 引入 Vitest/Playwright/release-please,补充单元与组件测试
- OpenAPI schema 与生成类型入库
- 环境变量按 mode 拆分,重构 wrapperEnv 解析

清理:
- 删除 .commitlintrc.js(CJS 配置在 type:module 下会崩溃),改用 commitlint.config.mjs
- 删除 eslint.config.mjs、prettier.config.js、.prettierignore
- 停止跟踪 .eslintrc-auto-import.json(已切 oxlint,无人引用)
- 移除 iconfont、旧 demo/list 页与 useAxiosApi/useFetchApi 等遗留实现
- husky 钩子移除 DEPRECATED 的 shebang 写法
- .workbuddy/ 加入 .gitignore
2026-09-02 14:37:52 +08:00

785 lines
19 KiB
YAML

openapi: 3.0.3
info:
title: Vue H5 Template API Contract
version: 2.0.0
servers:
- url: /api
paths:
/auth/login:
post:
operationId: login
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/LoginRequest'
responses:
'200':
description: Login result
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ApiResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/LoginResult'
/user/profile:
get:
operationId: getUserProfile
responses:
'200':
description: Current user
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ApiResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/UserProfile'
/examples/tasks:
get:
operationId: getTasks
responses:
'200':
description: Task list
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ApiResponse'
- type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/Task'
/examples/tasks/{id}/toggle:
post:
operationId: toggleTask
parameters:
- in: path
name: id
required: true
schema:
type: integer
responses:
'200':
description: Updated task
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ApiResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/Task'
/examples/feed:
get:
operationId: getFeed
parameters:
- in: query
name: cursor
schema:
type: integer
minimum: 0
- in: query
name: limit
schema:
type: integer
minimum: 1
maximum: 20
responses:
'200':
description: Cursor feed
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
/examples/{scenario}:
get:
operationId: triggerRequestErrorExample
description: Development-only request error fixtures exposed by Mock and Gin.
parameters:
- in: path
name: scenario
required: true
schema:
type: string
enum:
[
bad-request,
unauthorized,
forbidden,
not-found,
conflict,
validation,
server-error,
timeout,
]
responses:
'200':
description: Business validation or delayed success fixture
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
'400':
description: Bad request fixture
'401':
description: Unauthorized fixture
'403':
description: Forbidden fixture
'404':
description: Not found fixture
'409':
description: Conflict fixture
'500':
description: Server error fixture
/projects:
get:
operationId: listProjects
security:
- bearerAuth: []
parameters:
- in: query
name: page
schema:
type: integer
minimum: 1
- in: query
name: pageSize
schema:
type: integer
minimum: 1
maximum: 100
responses:
'200':
description: Paginated projects owned by the current user
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ApiResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/ProjectPage'
post:
operationId: createProject
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectInput'
responses:
'201':
description: Created project
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ApiResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/Project'
/projects/{id}:
get:
operationId: getProject
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ProjectId'
responses:
'200':
description: Project
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
patch:
operationId: updateProject
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ProjectId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectUpdateInput'
responses:
'200':
description: Updated project
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
delete:
operationId: deleteProject
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ProjectId'
responses:
'200':
description: Deletion result
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
/products:
get:
operationId: listProducts
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PageSize'
- in: query
name: keyword
schema:
type: string
- in: query
name: category
schema:
type: string
- in: query
name: sort
schema:
type: string
enum: [featured, sales, price_asc, price_desc]
responses:
'200':
description: Public on-sale product catalog
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ApiResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/ProductPage'
/products/{id}:
get:
operationId: getProduct
parameters:
- $ref: '#/components/parameters/ProductId'
responses:
'200':
description: Public product detail
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ApiResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/Product'
/admin/products:
get:
operationId: listAdminProducts
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/PageSize'
- in: query
name: keyword
schema:
type: string
- in: query
name: status
schema:
$ref: '#/components/schemas/ProductStatus'
responses:
'200':
description: Product management list
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/ApiResponse'
- type: object
properties:
data:
$ref: '#/components/schemas/ProductPage'
post:
operationId: createProduct
security:
- bearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProductInput'
responses:
'201':
description: Created product
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
/admin/products/{id}:
patch:
operationId: updateProduct
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ProductId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProductUpdateInput'
responses:
'200':
description: Updated product
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
delete:
operationId: deleteProduct
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/ProductId'
responses:
'200':
description: Soft-deleted product
content:
application/json:
schema:
$ref: '#/components/schemas/ApiResponse'
/ai/chat:
post:
operationId: streamChat
security:
- bearerAuth: []
- {}
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ChatRequest'
responses:
'200':
description: Server-sent ChatChunk events
content:
text/event-stream:
schema:
type: string
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
parameters:
Page:
in: query
name: page
schema:
type: integer
minimum: 1
PageSize:
in: query
name: pageSize
schema:
type: integer
minimum: 1
maximum: 50
ProjectId:
in: path
name: id
required: true
schema:
type: integer
minimum: 1
ProductId:
in: path
name: id
required: true
schema:
type: integer
minimum: 1
schemas:
ApiResponse:
type: object
required: [code, data, msg]
properties:
code:
type: integer
data: {}
msg:
type: string
requestId:
type: string
LoginRequest:
type: object
required: [name, password]
properties:
name:
type: string
minLength: 1
password:
type: string
minLength: 1
LoginResult:
type: object
required: [name, token]
properties:
name:
type: string
token:
type: string
expiresIn:
type: integer
UserProfile:
type: object
required: [id, name, role, plan]
properties:
id:
type: integer
name:
type: string
role:
type: string
enum: [admin, member]
plan:
type: string
enum: [free, pro]
Task:
type: object
required: [id, title, done]
properties:
id:
type: integer
title:
type: string
done:
type: boolean
FeedItem:
type: object
required: [id, title, summary, category]
properties:
id:
type: integer
title:
type: string
summary:
type: string
category:
type: string
Project:
type: object
required: [id, ownerId, name, description, status, createdAt, updatedAt]
properties:
id:
type: integer
ownerId:
type: integer
name:
type: string
description:
type: string
status:
$ref: '#/components/schemas/ProjectStatus'
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
ProjectStatus:
type: string
enum: [active, paused, archived]
ProjectInput:
type: object
required: [name]
properties:
name:
type: string
minLength: 1
maxLength: 120
description:
type: string
maxLength: 5000
status:
$ref: '#/components/schemas/ProjectStatus'
ProjectUpdateInput:
type: object
properties:
name:
type: string
minLength: 1
maxLength: 120
description:
type: string
maxLength: 5000
status:
$ref: '#/components/schemas/ProjectStatus'
ProjectPage:
type: object
required: [list, total, page, pageSize, hasMore]
properties:
list:
type: array
items:
$ref: '#/components/schemas/Project'
total:
type: integer
page:
type: integer
pageSize:
type: integer
hasMore:
type: boolean
Product:
type: object
required:
[
id,
sku,
name,
subtitle,
description,
category,
brand,
coverUrl,
priceCents,
originalPriceCents,
stock,
sales,
rating,
status,
featured,
createdAt,
updatedAt,
]
properties:
id:
type: integer
sku:
type: string
name:
$ref: '#/components/schemas/LocalizedText'
subtitle:
$ref: '#/components/schemas/LocalizedText'
description:
$ref: '#/components/schemas/LocalizedText'
category:
type: string
brand:
type: string
coverUrl:
type: string
priceCents:
type: integer
format: int64
originalPriceCents:
type: integer
format: int64
stock:
type: integer
sales:
type: integer
rating:
type: number
format: double
status:
$ref: '#/components/schemas/ProductStatus'
featured:
type: boolean
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
ProductStatus:
type: string
enum: [draft, on_sale, sold_out]
LocalizedText:
type: object
required: [zh-CN, en-US, ja-JP]
properties:
zh-CN:
type: string
minLength: 1
en-US:
type: string
minLength: 1
ja-JP:
type: string
minLength: 1
ProductInput:
type: object
required:
[
sku,
name,
subtitle,
description,
category,
brand,
coverUrl,
priceCents,
originalPriceCents,
stock,
sales,
rating,
status,
featured,
]
properties:
sku:
type: string
minLength: 1
maxLength: 64
name:
$ref: '#/components/schemas/LocalizedText'
subtitle:
$ref: '#/components/schemas/LocalizedText'
description:
$ref: '#/components/schemas/LocalizedText'
category:
type: string
minLength: 1
maxLength: 60
brand:
type: string
minLength: 1
maxLength: 80
coverUrl:
type: string
minLength: 1
maxLength: 500
priceCents:
type: integer
minimum: 0
originalPriceCents:
type: integer
minimum: 0
stock:
type: integer
minimum: 0
sales:
type: integer
minimum: 0
rating:
type: number
minimum: 0
maximum: 5
status:
$ref: '#/components/schemas/ProductStatus'
featured:
type: boolean
ProductUpdateInput:
type: object
properties:
sku:
type: string
minLength: 1
maxLength: 64
name:
$ref: '#/components/schemas/LocalizedText'
subtitle:
$ref: '#/components/schemas/LocalizedText'
description:
$ref: '#/components/schemas/LocalizedText'
category:
type: string
minLength: 1
maxLength: 60
brand:
type: string
minLength: 1
maxLength: 80
coverUrl:
type: string
minLength: 1
maxLength: 500
priceCents:
type: integer
minimum: 0
originalPriceCents:
type: integer
minimum: 0
stock:
type: integer
minimum: 0
sales:
type: integer
minimum: 0
rating:
type: number
minimum: 0
maximum: 5
status:
$ref: '#/components/schemas/ProductStatus'
featured:
type: boolean
ProductPage:
type: object
required: [list, total, page, pageSize, hasMore]
properties:
list:
type: array
items:
$ref: '#/components/schemas/Product'
total:
type: integer
page:
type: integer
pageSize:
type: integer
hasMore:
type: boolean
DeleteResult:
type: object
required: [deleted, id]
properties:
deleted:
type: boolean
id:
type: integer
ChatMessage:
type: object
required: [role, content]
properties:
role:
type: string
enum: [system, user, assistant]
content:
type: string
minLength: 1
maxLength: 20000
ChatRequest:
type: object
required: [messages]
properties:
conversationId:
type: string
maxLength: 120
messages:
type: array
minItems: 1
maxItems: 100
items:
$ref: '#/components/schemas/ChatMessage'