Skip to content

一套后端,三端联动:RuoYi Office 如何实现 OA、CRM、HRM、ERP 的 Web + 移动端一体化

🌐 文档地址http://ruoyioffice.com | 📦 源码1https://gitcode.com/zhouzhongyan/ruoyi-office-vben.git |📦 源码2https://gitcode.com/zhouzhongyan/ruoyi-office.git |📦 源码3https://github.com/yuqing2026/ruoyi-office.git | 💬 微信:17156169080(备注「RuoYi Office」)

企业数字化的真正挑战不是"做一个 Web 后台"或"做一个 App",而是让 Web 端和移动端像同一个系统一样运行——同一个账号、同一套权限、同一条审批流、同一份数据。RuoYi Office 通过统一后端 API + 双 Token 认证 + 菜单权限联动 + BPM 审批流贯通,实现了 OA、CRM、HRM、ERP 等 14 大模块的 Web + 移动端无缝协同。本文将从源码层面深度拆解这套多端一体化架构的设计思想与工程实现。

引言:企业管理系统为什么必须做多端联动?

如果你做过企业管理系统,一定遇到过这些场景:

  • 📱 出差在外:销售经理在客户现场,需要手机上提交一份 CRM 合同审批,领导在 PC 端直接审批通过
  • 🏢 办公室内:HR 在 Web 端录入员工入职信息,新员工在手机上就能看到自己的入职进度
  • 🚗 路上审批:部门总监在高铁上用手机审批了一份 OA 用车申请,申请人在 PC 端实时看到状态更新
  • 📊 数据同步:仓库管理员在手机上扫码入库,ERP 系统的库存数据立即在 Web 端同步更新

这些场景的共同特点是:数据在 Web 端和移动端之间无缝流转,用户在任意一端的操作都能实时反映到另一端。

很多团队的做法是:Web 端一套系统、移动端另一套系统,两边各写各的 API、各管各的状态。结果就是——数据不一致、权限不同步、审批流断裂、维护成本翻倍。

RuoYi Office 从架构层面解决了这个问题:一套后端 API,Web 端和移动端共享同一套认证、权限、数据和业务流程。

RuoYi Office 移动端首页 - 集成考勤打卡、业务申请、请假、审批、待办、工资条、企业云盘等功能

▲ RuoYi Office 移动端首页:考勤打卡、业务申请、请假审批、工资条、企业云盘,一站式移动办公


一、整体架构:一套后端,三端共享

1.1 架构全景图

RuoYi Office 的多端架构可以用一句话概括:后端是"一",前端是"多"。

┌─────────────────────────────────────────────────────────┐
│                    统一后端 API 层                        │
│         Spring Boot 3.5 / Spring Cloud Alibaba           │
│  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│  │ OA   │ │ BPM  │ │ HRM  │ │ CRM  │ │ ERP  │ │ AI   │ │
│  └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
│         /admin-api/{module}/...                          │
└───────────────────────┬─────────────────────────────────┘
                        │ RESTful API(JSON)
          ┌─────────────┼─────────────────┐
          ▼             ▼                 ▼
   ┌─────────────┐ ┌──────────┐  ┌──────────────┐
   │  Web 端      │ │ 移动端    │  │ 小程序端      │
   │  Vue3 +      │ │ UniApp + │  │ UniApp +     │
   │  Vben Admin  │ │ Vue3     │  │ Vue3         │
   │  Ant Design  │ │ wot-ui   │  │ wot-ui       │
   └─────────────┘ └──────────┘  └──────────────┘

关键设计原则:

原则说明
API 统一Web 端和移动端调用同一套后端 RESTful API,路径前缀统一为 /admin-api
认证统一统一使用 OAuth2 Token 认证,支持单 Token / 双 Token 两种模式
权限统一后端基于 RBAC 模型统一鉴权,前端按需过滤菜单和按钮
数据统一同一个数据库、同一套 Service 层,数据天然一致
流程统一BPM 审批流引擎(Flowable)统一管理,Web 端发起 → 移动端审批完全打通

1.2 技术栈对比

维度Web 端移动端
框架Vue 3 + TypeScriptUniApp + Vue 3 + TypeScript
脚手架Vben Admin 5.xunibest 4.x
UI 库Ant Design Vue 4.xwot-design-uni
构建工具Vite 6.xVite
样式方案TailwindCSSUnoCSS
状态管理PiniaPinia(persist: true)
路由Vue Router 4uni.navigateTo / uni.switchTab
HTTP 客户端Axiosuni.request(封装)
目标平台浏览器H5 / 微信小程序 / APP

虽然技术栈不同,但核心思想一致:Vue 3 Composition API + Pinia 状态管理 + TypeScript 类型安全,让两端开发者可以无缝切换。


二、登录认证:一套账号,多端通行

登录是多端联动的第一道关卡。RuoYi Office 实现了统一认证体系——同一个账号在 Web 端和移动端都能登录,且支持多种登录方式。

2.1 移动端登录界面

RuoYi Office 移动端登录页 - 支持账号密码、手机号、微信、钉钉等多种登录方式

▲ 移动端登录页:支持租户选择、账号密码登录、手机号登录、微信/钉钉社交登录

移动端登录页支持以下登录方式:

登录方式说明
🔑 账号密码与 Web 端共享同一套用户体系
📱 手机号验证码发送短信验证码登录
💬 微信登录微信授权快捷登录
🔔 钉钉登录钉钉授权快捷登录
🏢 多租户支持在登录时选择所属租户

2.2 统一的后端认证 API

无论 Web 端还是移动端,登录请求最终都打到同一个后端 Controller:

java
// AuthController.java — 后端统一认证入口
@Tag(name = "管理后台 - 认证")
@RestController
@RequestMapping("/system/auth")
public class AuthController {

    @PostMapping("/login")
    @PermitAll
    @Operation(summary = "使用账号密码登录")
    public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
        return success(authService.login(reqVO));
    }

    @PostMapping("/sms-login")
    @PermitAll
    @Operation(summary = "使用短信验证码登录")
    public CommonResult<AuthLoginRespVO> smsLogin(@RequestBody @Valid AuthSmsLoginReqVO reqVO) {
        return success(authService.smsLogin(reqVO));
    }

    @PostMapping("/social-login")
    @PermitAll
    @Operation(summary = "社交快捷登录,使用 code 授权码")
    public CommonResult<AuthLoginRespVO> socialQuickLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) {
        return success(authService.socialLogin(reqVO));
    }

    @PostMapping("/refresh-token")
    @PermitAll
    @Operation(summary = "刷新令牌")
    public CommonResult<AuthLoginRespVO> refreshToken(@RequestParam("refreshToken") String refreshToken) {
        return success(authService.refreshToken(refreshToken));
    }

    @GetMapping("/get-permission-info")
    @Operation(summary = "获取登录用户的权限信息")
    public CommonResult<AuthPermissionInfoRespVO> getPermissionInfo() {
        // 获取用户信息 + 角色列表 + 菜单权限 + 部门信息
        // ...
    }
}

2.3 移动端 Token 管理:单 Token 与双 Token 双模式

RuoYi Office 的移动端设计了一个非常灵活的 Token 管理机制——同时支持单 Token 和双 Token 两种模式,通过环境变量一键切换。

typescript
// api/types/login.ts — Token 类型定义
export type AuthMode = 'single' | 'double'

// 单 Token 模式:简单直接
export interface ISingleTokenRes {
  token: string
  expiresIn: number // 有效期(秒)
}

// 双 Token 模式:更安全,支持无感刷新
export interface IDoubleTokenRes {
  accessToken: string
  refreshToken: string
  expiresTime: number // 访问令牌过期时间(毫秒)
}

export type IAuthLoginRes = ISingleTokenRes | IDoubleTokenRes

为什么要支持两种模式?

模式适用场景优势
单 Token内部系统、安全性要求不高实现简单,一个 Token 搞定
双 Token面向外部、安全性要求高accessToken 短期有效 + refreshToken 长期有效,支持无感续期

移动端的 Token Store 核心逻辑:

typescript
// store/token.ts — Pinia Token 状态管理
export const useTokenStore = defineStore(
  'token',
  () => {
    const tokenInfo = ref<IAuthLoginRes | null>(null)

    /** 统一登录入口 */
    const login = async (loginForm: ILoginForm) => {
      let res: IAuthLoginRes
      switch (loginForm.type) {
        case 'username':
          res = await _login({
            username: loginForm.username,
            password: loginForm.password,
            captchaVerification: loginForm.captchaVerification,
          })
          break
        case 'sms':
          res = await smsLogin({
            mobile: loginForm.mobile,
            code: loginForm.code,
          })
          break
        // ... 其他登录方式
      }
      setTokenInfo(res)
      // 登录成功后,加载用户信息和字典数据
      await useUserStore().fetchUserInfo()
      await useDictStore().loadAllDict()
    }

    /** 获取有效 Token(自动判断单/双模式) */
    const getValidToken = computed(() => {
      if (!tokenInfo.value) return ''
      if (isSingleTokenRes(tokenInfo.value)) {
        return tokenInfo.value.token
      }
      if (isDoubleTokenRes(tokenInfo.value)) {
        return tokenInfo.value.accessToken
      }
      return ''
    })

    /** Token 刷新(双 Token 模式下自动续期) */
    const refreshToken = async () => {
      if (!tokenInfo.value || !isDoubleTokenRes(tokenInfo.value)) return
      const res = await _refreshToken(tokenInfo.value.refreshToken)
      setTokenInfo(res)
    }

    return { login, logout, tokenInfo, validToken: getValidToken, refreshToken }
  },
  { persist: true } // ✅ 关键:Token 持久化存储,App 重启不丢失
)

💡 关键设计persist: true 让 Token 在 App 重启后依然有效,用户不需要重复登录。这对移动端体验至关重要。

2.4 HTTP 拦截器:自动注入认证信息

移动端的每一个 HTTP 请求都会经过拦截器,自动注入 Token、租户 ID 等认证信息:

typescript
// http/interceptor.ts — 请求拦截器
const whiteList = ['/login', '/refresh-token', '/system/tenant/get-id-by-name']

const httpInterceptor = {
  invoke(options: CustomRequestOptions) {
    // 1. 拼接完整 URL
    if (!options.url.startsWith('http')) {
      options.url = baseUrl + options.url
    }

    // 2. 自动注入 Bearer Token
    const tokenStore = useTokenStore()
    const token = tokenStore.validToken
    const isWhite = whiteList.some(v => options.url.includes(v))
    if (!isWhite && token) {
      options.header.Authorization = `Bearer ${token}`
    }

    // 3. 自动注入租户 ID(多租户隔离)
    if (tenantEnable === 'true') {
      const tenantId = useUserStore().tenantId
      if (tenantId) {
        options.header['tenant-id'] = tenantId
      }
    }

    // 4. API 加密(可选)
    if (options.isEncrypt && options.data) {
      options.data = ApiEncrypt.encryptRequest(options.data)
      options.header[ApiEncrypt.getEncryptHeader()] = 'true'
    }
  },
}

这套拦截器机制确保了:移动端的每一个请求都携带了和 Web 端完全一致的认证信息,后端无需区分请求来自哪个端。


三、工作台菜单:统一配置,权限联动

3.1 移动端工作台

RuoYi Office 移动端工作台 - OA协同办公、人力资源管理、系统管理等功能分组

▲ 移动端工作台:OA 协同办公(用车/还车/用印/会议室)、人力资源管理(入职/转正/调动/离职)、系统管理,功能一目了然

3.2 菜单配置:声明式 + 权限过滤

移动端的菜单采用声明式配置,每个菜单项绑定权限标识和流程定义 Key:

typescript
// pages/index/menu-config.ts — 工作台菜单配置
export const menuGroupsData: MenuGroup[] = [
  {
    key: 'oa',
    name: 'OA协同办公',
    menus: [
      {
        key: 'oaCarApply',
        name: '用车申请',
        icon: 'location',
        iconColor: '#2563eb',
        url: '/pages-oa/car/index',
        permission: 'oa:car-apply-bill:create',         // ✅ 权限标识
        processDefinitionKey: 'oa_car_apply_bill',       // ✅ 流程定义 Key
      },
      {
        key: 'oaSealApply',
        name: '用印申请',
        icon: 'edit-outline',
        iconColor: '#7c3aed',
        url: '/pages-oa/seal/index',
        permission: 'oa:seal-apply-bill:create',
        processDefinitionKey: 'oa_seal_apply_bill',
      },
      // ... 更多 OA 菜单
    ],
  },
  {
    key: 'hrm',
    name: '人力资源管理',
    menus: [
      {
        key: 'hrmEntry',
        name: '员工入职',
        icon: 'user',
        iconColor: '#2563eb',
        url: '/pages-hrm/entry/index',
        permission: 'hrm:employee-entry:create',
        processDefinitionKey: 'hrm_employee_entry',
      },
      // ... 员工转正、人事调动、员工离职等
    ],
  },
  // ... 系统管理等更多分组
]

3.3 权限过滤:与后端 RBAC 联动

菜单不是"写死就完事"——它会根据当前用户的权限动态过滤

typescript
// pages/index/index.ts — 菜单权限过滤
export function getMenuGroups(): MenuGroup[] {
  const { hasAccessByCodes } = useAccess()

  return menuGroupsData
    .map(group => ({
      ...group,
      // 过滤掉没有权限的菜单项
      menus: group.menus.filter((menu) => {
        if (!menu.permission) return true  // 没配权限的默认展示
        return hasAccessByCodes([menu.permission])
      }),
    }))
    .filter(group => group.menus.length > 0)  // 过滤掉空分组
}

权限数据从哪来? 用户登录成功后,移动端会调用 /system/auth/get-permission-info 接口,获取当前用户的角色和权限列表。这个接口返回的数据和 Web 端完全一致——同一个用户在 Web 端能看到的功能,在移动端也能看到;Web 端没权限的,移动端同样被过滤掉。

3.4 智能导航:TabBar 页面 vs 普通页面

移动端的页面导航需要区分 TabBar 页面和普通页面,UniApp 对这两种页面的跳转方式不同:

typescript
// pages/index/components/menu-grid.vue — 菜单点击导航
function handleClick(menu: MenuItem) {
  if (!menu.url) {
    toast.show('功能开发中')
    return
  }

  const { path, query } = parseUrl(menu.url)

  if (isTabBarPage(path)) {
    // TabBar 页面:必须用 switchTab,且不能传参,需要通过缓存传递
    if (Object.keys(query).length > 0) {
      setTabParams(query)  // 将参数存入缓存
    }
    uni.switchTab({ url: path })
  } else {
    // 普通页面:直接 navigateTo,支持 URL 参数
    uni.navigateTo({ url: menu.url })
  }
}

TabBar 配置采用自定义策略,支持多种模式:

typescript
// tabbar/config.ts — 底部导航栏配置
export const customTabbarList: CustomTabBarItem[] = [
  { text: '首页',   pagePath: 'pages/index/index',     icon: 'i-carbon-home' },
  { text: '审批',   pagePath: 'pages/bpm/index',       icon: 'i-carbon-document' },
  { text: '工作台', pagePath: 'pages/workspace/index',  icon: 'i-carbon-grid' },
  { text: '消息',   pagePath: 'pages/message/index',    icon: 'i-carbon-chat' },
  { text: '我的',   pagePath: 'pages/user/index',       icon: 'i-carbon-user' },
]

四、BPM 审批流:Web 端发起,移动端审批

审批流是企业管理系统的核心场景,也是多端联动最能体现价值的地方。RuoYi Office 基于 Flowable BPMN 2.0 引擎,实现了 Web 端和移动端的审批流完全贯通。

4.1 移动端审批列表

RuoYi Office 移动端审批页 - 待办任务、我的流程、已办任务、抄送我的四个 Tab

▲ 移动端审批页:待办任务列表支持快捷审批(同意/拒绝),也可进入详情页查看完整表单和流程图

4.2 审批页面架构

移动端审批页采用 Tab 切换 架构,四个维度覆盖审批全生命周期:

vue
<!-- pages/bpm/index.vue — 移动端审批主页 -->
<template>
  <view class="bpm-page">
    <wd-navbar title="审批" placeholder safe-area-inset-top fixed />

    <!-- Tab 切换:四个审批维度 -->
    <wd-tabs v-model="activeTab" @change="handleTabChange">
      <wd-tab title="待办任务" name="todo" />
      <wd-tab title="我的流程" name="my" />
      <wd-tab title="已办任务" name="done" />
      <wd-tab title="抄送我的" name="copy" />
    </wd-tabs>

    <!-- 列表内容:按需渲染 -->
    <view class="bpm-content">
      <TodoList v-show="activeTab === 'todo'" />
      <MyList v-show="activeTab === 'my'" />
      <DoneList v-show="activeTab === 'done'" />
      <CopyList v-show="activeTab === 'copy'" />
    </view>
  </view>
</template>

💡 设计亮点:使用 v-show 而非 v-if,切换 Tab 时不会销毁组件,保留滚动位置和加载状态,提升用户体验。

4.3 待办任务:快捷审批 + 详情审批双模式

待办列表中的每一条任务都支持两种操作模式:

typescript
// pages/bpm/components/todo-list.vue — 待办任务处理
function handleDetail(item: Task) {
  // 进入详情页:查看完整表单 + 审批时间线 + 操作按钮
  uni.navigateTo({
    url: `/pages-bpm/processInstance/detail/index?id=${item.processInstance.id}&taskId=${item.id}&viewType=todo`
  })
}

function handleApprove(item: Task) {
  // 判断是否需要强制跳转详情页(某些复杂表单必须看完才能审批)
  if (shouldForceDetail(item.processInstance?.name, item.name)) {
    handleDetail(item)
    return
  }
  // 快捷审批:直接进入审批操作页
  uni.navigateTo({
    url: `/pages-bpm/processInstance/detail/audit/index?processInstanceId=${item.processInstance.id}&taskId=${item.id}&pass=true`
  })
}

4.4 BPM 菜单配置:流程定义与移动端页面的桥梁

BPM 模块有一个专门的菜单配置,将后端流程定义 Key 与移动端页面路径关联起来:

typescript
// pages-bpm/config/bpm-menu-config.ts — BPM 流程菜单配置
export interface BpmMenuItem {
  key: string
  name: string
  icon: string
  processDefinitionKey: string    // 后端 Flowable 流程定义的 key
  mobileCreatePath?: string       // 移动端制单页面路径
  mobileViewComponent?: string    // 审批详情中嵌入的表单组件标识
  forceDetailTaskNames?: string[] // 强制跳转到详情页的任务名称列表
}

const bpmMenuGroupsData: BpmMenuGroup[] = [
  {
    key: 'oa',
    name: '行政',
    menus: [
      {
        key: 'oaLeave',
        name: '请假',
        icon: 'calendar',
        processDefinitionKey: 'oa_leave',
        mobileCreatePath: '/pages-bpm/oa/leave/create/index',
        mobileViewComponent: 'LeaveDetail',
      },
      {
        key: 'oaCarApply',
        name: '用车申请',
        icon: 'location',
        processDefinitionKey: 'oa_car_apply_bill',
        mobileCreatePath: '/pages-bpm/oa/car/create/index',
        mobileViewComponent: 'CarApplyDetail',
      },
      // ... 用印申请、会议室预约、员工入职、转正、调动、离职等
    ],
  },
]

这个配置的精妙之处在于:

  1. processDefinitionKey:与后端 Flowable 引擎的流程定义 Key 一一对应,确保移动端发起的流程能被后端正确识别
  2. mobileCreatePath:指定移动端的制单页面路径,不同业务表单有不同的制单 UI
  3. mobileViewComponent:在审批详情页中,根据这个标识动态加载对应的业务表单组件
  4. forceDetailTaskNames:某些复杂审批节点(如财务复核),必须查看完整表单才能操作

4.5 审批流程的完整链路

一个典型的 OA 请假审批在 Web 端和移动端的完整流程:

┌──────────────────────────────────────────────────────────┐
│  1. 员工在【移动端】提交请假申请                            │
│     POST /admin-api/bpm/process-instance/create          │
│     { processDefinitionKey: 'oa_leave', variables: {...} }│
├──────────────────────────────────────────────────────────┤
│  2. Flowable 引擎创建流程实例,分配任务给审批人              │
├──────────────────────────────────────────────────────────┤
│  3. 审批人在【Web 端】或【移动端】看到待办任务               │
│     GET /admin-api/bpm/task/todo-page                     │
├──────────────────────────────────────────────────────────┤
│  4. 审批人在【移动端】快捷审批通过                           │
│     PUT /admin-api/bpm/task/approve                       │
│     { id: 'taskId', reason: '同意' }                      │
├──────────────────────────────────────────────────────────┤
│  5. 员工在【Web 端】实时看到审批状态更新为"已通过"           │
│     GET /admin-api/bpm/process-instance/get               │
└──────────────────────────────────────────────────────────┘

核心要点:整个流程中,Web 端和移动端调用的是同一套 API,操作的是同一个流程实例,数据天然一致,无需任何同步机制。


五、首页与个人中心:多端体验一致

5.1 移动端首页:信息聚合 + 快捷入口

移动端首页是用户打开 App 后的第一个页面,它聚合了用户最关心的信息:

vue
<!-- pages/index/index.vue — 移动端首页 -->
<script lang="ts" setup>
// 快捷入口:考勤打卡、业务申请、请假、审批、待办
const quickActions = [
  { name: '考勤打卡', icon: 'location', url: '/pages-hrm/attendance/punch/index' },
  { name: '业务申请', icon: 'edit-outline', url: '/pages-bpm/create/index' },
  { name: '请假申请', icon: 'calendar', url: '/pages-bpm/oa/leave/create/index' },
  { name: '审 批', icon: 'check-circle', url: '/pages/bpm/index' },
  { name: '待 办', icon: 'clock', url: '/pages/bpm/index?tab=todo' },
]

/** 快捷入口点击:智能判断跳转方式 */
function handleQuickAction(action: any) {
  const path = action.url.split('?')[0]
  if (isTabBarPage(path)) {
    // TabBar 页面需要用 switchTab + 缓存传参
    const query = parseQueryFromUrl(action.url)
    if (query) setTabParams(query)
    uni.switchTab({ url: path })
  } else {
    uni.navigateTo({ url: action.url })
  }
}
</script>

首页还集成了:

  • 📢 通知公告:与 Web 端同步,支持已读追踪
  • 💰 工资条:上月总工资、考核评分、绩效工资
  • 📁 企业云盘:我的文件、共享文件、我的收藏

5.2 个人中心

RuoYi Office 移动端个人中心 - 通讯录、文件助手、账户安全、帮助中心等功能

▲ 移动端个人中心:VIP 会员、通讯录、文件助手、账户安全、在线客服、技术热线


六、企业云盘:跨端文件协同

企业云盘是 OA 场景中的高频功能,RuoYi Office 的云盘实现了 Web 端和移动端的文件完全同步:

vue
<!-- pages-oa/file/index.vue — 移动端企业云盘 -->
<script lang="ts" setup>
const tabs = [
  { key: 'my', name: '我的文件' },
  { key: 'shared', name: '共享文件' },
  { key: 'favorite', name: '我的收藏' },
]

// 面包屑导航:支持多级目录浏览
interface BreadcrumbItem {
  id: number
  name: string
  rootShareId?: number
}
const pathStack = ref<BreadcrumbItem[]>([{ id: 0, name: '我的文件' }])

// 支持从首页传入 tab 参数
onLoad((query) => {
  if (query?.tab) {
    const tabIndex = tabs.findIndex(t => t.key === query.tab)
    if (tabIndex >= 0) activeTab.value = tabIndex
  }
  loadData()
})
</script>

在 Web 端上传的文件,移动端可以立即看到和下载;移动端拍照上传的文件,Web 端也能实时查看——因为它们调用的是同一套文件管理 API


七、关键设计模式总结

7.1 "配置驱动"模式

无论是工作台菜单还是 BPM 流程,移动端都采用配置驱动的方式:

配置文件(menu-config.ts / bpm-menu-config.ts)
    ↓ 声明式定义菜单、权限、流程 Key
运行时过滤(getMenuGroups / getMenuItemByProcessDefinitionKey)
    ↓ 根据用户权限动态过滤
UI 渲染(MenuGrid / TodoList)
    ↓ 自动渲染可见菜单和操作

新增一个业务模块只需要:在配置文件中加一行菜单配置 + 开发对应的页面,无需修改任何框架代码。

7.2 "统一 Store"模式

移动端使用 Pinia Store 管理全局状态,且所有 Store 都支持持久化:

Store职责持久化
useTokenStoreToken 管理、登录/登出
useUserStore用户信息、权限列表、租户 ID
useDictStore数据字典缓存

7.3 "API 同构"模式

移动端的 API 层与 Web 端保持路径一致

typescript
// 移动端 API
export function login(data: AuthLoginReqVO) {
  return http.post<IAuthLoginRes>('/system/auth/login', data)
}

// Web 端 API(路径完全一致)
export function login(data: AuthLoginReqVO) {
  return requestClient.post<AuthLoginRespVO>('/system/auth/login', data)
}

两端的 API 路径完全一致,只是 HTTP 客户端不同(移动端用 uni.request 封装,Web 端用 axios)。这意味着:

  • 后端开发者只需要写一套 API
  • 前端开发者可以直接参考另一端的 API 调用
  • 接口文档(Knife4j / Swagger)对两端都适用

八、PC 端需要截图的关键页面路径

如果你想在 PC 端(Web 端)查看对应功能,以下是关键页面路径:

功能PC 端路径说明
登录页/loginWeb 端登录页,支持账号密码/手机号/社交登录
工作台首页//home自定义首页,千人千面
BPM 审批-我的流程/bpm/manager/process-instance流程实例管理
BPM 审批-待办任务/bpm/manager/task/todo待办任务列表
OA-用车管理/oa/car-apply-bill用车申请列表
HRM-员工管理/hrm/employee员工信息管理
菜单管理/system/menu系统菜单配置(Web + 移动端共享权限)
流程模型/bpm/manager/modelBPMN 2.0 流程设计器

九、总结:多端一体化的核心价值

RuoYi Office 的 Web + 移动端一体化架构,不是简单的"做两个前端",而是从架构层面实现了真正的多端协同

维度传统方案RuoYi Office 方案
后端 APIWeb 端和移动端各写一套统一一套 RESTful API
认证体系各端独立认证统一 OAuth2 Token,支持单/双 Token
权限管理各端独立维护权限后端统一 RBAC,前端按需过滤
审批流程各端独立流程Flowable 统一引擎,跨端流转
数据一致性需要同步机制同库同表,天然一致
开发成本两套代码 × 两套测试后端一套 + 前端两套(共享逻辑)
维护成本修改一处改两端后端改一处,两端自动生效

一句话总结:RuoYi Office 让企业管理真正做到了"办公室用电脑,出门用手机,数据不丢、流程不断、体验不降"。


📦 完整源码获取

💬 技术交流:微信 17156169080(备注「RuoYi Office」)

🌐 在线文档http://ruoyioffice.com