我把 2000 行下单代码,重构成了一套交易前端架构

在很多金融类产品里,下单模块几乎永远是最复杂的前端代码之一

一个完整的交易流程通常包括:

  • 普通单 / 条件单
  • 创建订单 / 改单
  • 价格校验
  • 资产校验
  • 风险提示
  • 协议签署
  • 二次确认
  • 输入交易密码
  • 提交订单
  • 结果处理

随着需求不断叠加,很多项目最后都会演变成这样:

ts 复制代码
async function onOrder() {

  if (!priceValid()) return toast("价格不合法")

  if (!assetEnough()) return toast("资产不足")

  if (needRiskConfirm()) {
    await openRiskDialog()
  }

  if (!signedAgreement()) {
    await openAgreementDialog()
  }

  if (!await openConfirmDialog()) return

  const password = await openPassword()

  const res = await submitOrderApi()

  handleResult(res)

}

组件文件很容易膨胀到:

ts 复制代码
Order.vue
≈ 2000 行

随着业务增长,会出现三个典型问题:

1️⃣ 校验逻辑越来越复杂

2️⃣ 创建单 / 改单到处是 if (isEdit)

3️⃣ 提交流程越来越长

后来我对这块代码做了一次系统性的重构,最终形成了一套 稳定可扩展的交易前端架构

ts 复制代码
OrderSession
+ OrderFlowStateMachine
+ RuleEngine
+ SubmitPipeline
+ Ports / Adapters

下面把这套架构完整拆解。


一、交易系统为什么容易失控

交易模块有一个典型特点:

流程很长 + 规则很多。

完整流程通常是:

ts 复制代码
填写订单
 ↓
前置校验
 ↓
风险确认
 ↓
协议签署
 ↓
最终确认
 ↓
输入密码
 ↓
提交订单
 ↓
结果处理

如果所有逻辑都写在组件里,代码结构会变成:

ts 复制代码
UI + 业务规则 + 流程控制 + API调用

全部混在一起。

解决办法只有一个:

拆层。


二、交易前端架构分层

重构后我们把交易模块拆成五层:

ts 复制代码
Presentation
↓
Application
↓
Domain
↓
Ports
↓
Adapters

整体结构如下:

ts 复制代码
UI (Vue / React)
      ↓
useOrderFlow
      ↓
OrderFlowMachine
      ↓
SubmitPipeline
      ↓
RuleEngine
      ↓
OrderSession
      ↓
Ports
      ↓
Adapters(API / Store)

每一层职责都非常清晰。


三、OrderSession:统一创建单和改单

交易系统中有一个非常经典的问题:

ts 复制代码
创建订单
改单

很多项目的代码会变成:

ts 复制代码
if (isEdit) {
  // 修改逻辑
} else {
  // 创建逻辑
}

时间久了,整个项目会充满:

ts 复制代码
if (isEdit)

解决方案是引入一个领域模型:

OrderSession

ts 复制代码
interface OrderSession {

  type: "CREATE" | "EDIT"

  entrustId?: string

  originOrder?: OrderDTO

}

它表示:

用户的一次下单会话。

例如:

ts 复制代码
CREATE Session → 创建订单
EDIT Session → 修改订单

所有逻辑只依赖 session.type,而不是 isEdit


四、RuleEngine:把校验逻辑规则化

原来的校验代码通常是:

ts 复制代码
if (!priceValid()) return toast()

if (!assetEnough()) return toast()

if (priceDiffTooLarge()) openRiskDialog()

随着需求增加,preVerify 会变成一大坨 if

解决方案是 规则引擎化

定义统一结果结构:

ts 复制代码
interface ValidationResult {

  code: string

  severity: "block" | "warn"

  message: string
}

规则写成纯函数:

ts 复制代码
function priceRule(ctx): ValidationResult | null

function assetRule(ctx): ValidationResult | null

统一执行:

ts 复制代码
function runRules(ctx, rules) {

  return rules
    .map(rule => rule(ctx))
    .filter(Boolean)

}

新增规则只需要:

ts 复制代码
新增一个函数

而不需要修改原有代码。


五、SubmitPipeline:拆解提交流程

原来的提交流程通常是:

ts 复制代码
verify
↓
risk confirm
↓
confirm
↓
password
↓
submit

我们把它拆成 Pipeline

ts 复制代码
ValidateStep
↓
RiskConfirmStep
↓
AgreementStep
↓
FinalConfirmStep
↓
PasswordStep
↓
SubmitStep
↓
ResultStep

代码实现:

ts 复制代码
async function runPipeline(ctx, steps) {

  for (const step of steps) {

    await step(ctx)

  }

}

好处是:

流程步骤可以自由插拔。

例如新增:

ts 复制代码
冷静期确认

只需要增加一个 step。


六、OrderFlowStateMachine:状态机驱动流程

交易流程本质上是一个 状态机

定义状态:

ts 复制代码
FORM
VALIDATING
RISK_CONFIRM
PASSWORD
SUBMITTING
SUCCESS
FAILED

状态转移:

ts 复制代码
FORM
 ↓
VALIDATING
 ↓
RISK_CONFIRM
 ↓
PASSWORD
 ↓
SUBMITTING
 ↓
SUCCESS

简单实现:

ts 复制代码
class OrderFlowMachine {

  state = "FORM"

  transition(next) {
    this.state = next
  }

}

UI 只根据状态渲染:

ts 复制代码
FORM → 表单
RISK_CONFIRM → 风险弹窗
PASSWORD → 密码输入

逻辑会变得非常清晰。


七、Ports / Adapters:隔离外部系统

交易模块通常依赖很多系统:

ts 复制代码
行情
资产
交易接口
协议系统

如果直接依赖 Store 或 API,会导致代码强耦合。

解决方案是 Ports + Adapters

定义接口:

ts 复制代码
interface OrderPort {

  submitOrder(command)

}

Adapter 实现:

ts 复制代码
export const orderAdapter = {

  submitOrder(cmd) {

    return api.trade.submit(cmd)

  }

}

Domain 只依赖:

ts 复制代码
Port

而不是具体 API。


八、完整目录结构

重构后的目录结构大致如下:

ts 复制代码
order/

domain/

  OrderSession.ts
  OrderContext.ts

  validation/
    priceRule.ts
    assetRule.ts
    modifyRule.ts

application/

  OrderFlowMachine.ts
  submitPipeline.ts

ports/

  OrderPort.ts
  MarketPort.ts

adapters/

  orderAdapter.ts
  marketAdapter.ts

composables/

  useOrderFlow.ts

结构非常清晰。


九、改造后的效果

重构前:

ts 复制代码
Order.vue
≈ 2000 行

重构后:

ts 复制代码
UI组件
≈ 300 行

其余逻辑全部放在:

ts 复制代码
Domain
Application

新增规则或流程时:

ts 复制代码
新增 Rule
新增 Step

而不是修改原有代码。


十、总结

复杂交易系统的稳定架构通常由五个核心模块组成:

ts 复制代码
OrderSession
+
StateMachine
+
RuleEngine
+
SubmitPipeline
+
Ports / Adapters

简单理解就是:

ts 复制代码
Session 管数据
StateMachine 管流程
RuleEngine 管规则
Pipeline 管步骤
Ports 管依赖

当这些模块拆清楚之后,下单系统就会变成:

稳定、清晰、可扩展。

这也是很多大型金融系统前端常见的架构模式。

相关推荐
ouzz2 分钟前
使用纯canvas绘制一个掘金首页
前端·canvas
CoovallyAIHub3 分钟前
RK3588上111 FPS:轻量YOLOv8+异步视频处理系统实现无人机自主电力巡检
算法·架构·github
lzhdim10 分钟前
SQL 入门 10:SQL 内置函数:数值、字符串与时间处理
前端·数据库·sql
jstopo网站12 分钟前
水厂水泵工作流程图canvas动画
前端·javascript
张元清15 分钟前
5 分钟用 Vite SSR 搭建一个全栈 React 应用
前端·javascript·面试
空中海15 分钟前
6.1 主题与暗色模式
运维·服务器·前端·flutter
好家伙VCC19 分钟前
# 发散创新:基于事件驱动架构的实时日志监控系统设计与实现在现代分布式系统中,**事件驱动编程模型**正
java·python·架构
踩着两条虫25 分钟前
效率翻倍!AI智能体深度解析:自然语言 → DSL → Vue组件
前端·人工智能·低代码
小江的记录本31 分钟前
【Transformer架构】Transformer架构核心知识体系(包括自注意力机制、多头注意力、Encoder-Decoder结构)
java·人工智能·后端·python·深度学习·架构·transformer
吴声子夜歌1 小时前
Vue3——条件判断指令
前端·es6