如何处理管理系统中(Vue PC + uni-app 移动端):业务逻辑复用基本方案

本文主要从以下几个方面入手:

  1. API请求、

  2. 状态管理、

  3. 工具函数

  4. 路由

  5. 包管理工具

一、整体设计:分层解耦,复用优先

核心思路是 "业务逻辑抽离为公共层,两端仅保留平台特有逻辑" ,整体架构分为 5 层,从下到上分别为:

bash 复制代码
├─ 1. 基础工具层(utils):纯函数工具,两端完全复用
├─ 2. API 通信层(api):统一请求逻辑,适配两端差异
├─ 3. 状态管理层(store):核心业务状态,两端共享
├─ 4. 业务逻辑层(services):封装业务方法,两端复用
└─ 5. 视图层(components/views):平台特有组件/页面,差异化实现

核心原则

  1. 公共逻辑 "上提" :API、状态、工具函数等无平台依赖的逻辑,抽离到独立包 / 目录,避免两端重复编写;
  2. 平台差异 "下沉" :UI 组件、路由、原生能力(如扫码、推送)等平台特有逻辑,在两端单独实现,通过 "适配层" 对接公共逻辑;
  3. 依赖统一管理:统一包管理工具(如 npm),公共依赖(如 axios、lodash)在两端共享版本,避免兼容性问题。

二、具体技术方案:分层实现复用

1. 基础工具层(utils):100% 复用,纯函数设计

核心目标

提供无副作用的纯函数工具,覆盖格式化、验证、计算等通用能力,两端完全复用。

实现方案

  • 目录结构 :在项目根目录创建 packages/utils(或独立 npm 包),按功能分类:

    bash 复制代码
    utils/
    ├─ format/:时间格式化(dateFormat)、金额格式化(moneyFormat)
    ├─ validate/:手机号验证(isPhone)、邮箱验证(isEmail)、表单规则(formRules)
    ├─ compute/:分页计算(calcPageInfo)、权限判断(hasPermission)
    └─ common/:深拷贝(deepClone)、防抖节流(debounce/throttle)
  • 代码示例(时间格式化工具):

    javascript 复制代码
    // packages/utils/format/dateFormat.js
    export const dateFormat = (date, format = 'YYYY-MM-DD HH:mm:ss') => {
      // 纯函数实现,无平台依赖
      const dt = new Date(date);
      const options = {
        'YYYY': dt.getFullYear(),
        'MM': String(dt.getMonth() + 1).padStart(2, '0'),
        // ... 其他格式化逻辑
      };
      return Object.entries(options).reduce((res, [key, val]) => res.replace(key, val), format);
    };
  • 复用方式 :两端通过 import { dateFormat } from '@/utils/format/dateFormat' 直接引入,无需修改。

2. API 通信层(api):统一请求逻辑,适配两端差异

核心目标

封装 API 请求逻辑(请求拦截、响应拦截、错误处理),统一接口调用方式,仅适配两端的请求库差异(Vue 用 axios,uni-app 用 uni.request)。

实现方案

  • 分层设计:分为 "基础请求适配层" 和 "业务接口层",前者处理平台差异,后者纯业务逻辑复用:

    vbscript 复制代码
    api/
    ├─ request/:基础请求适配(区分 Vue/uni-app)
    │  ├─ index.js:入口文件(根据环境导出对应请求实例)
    │  ├─ webRequest.js:Vue 端(基于 axios)
    │  └─ uniRequest.js:uni-app 端(基于 uni.request)
    └─ modules/:业务接口(两端完全复用)
       ├─ user.js:用户相关(登录、权限)
       ├─ order.js:订单相关(列表、详情)
       └─ goods.js:商品相关(新增、编辑)
  • 关键实现:请求适配层(处理平台差异):

    javascript 复制代码
    // api/request/webRequest.js(Vue 端)
    import axios from 'axios';
    const service = axios.create({
      baseURL: import.meta.env.VITE_API_BASE_URL, // PC 端环境变量
      timeout: 10000
    });
    // 请求拦截:添加 token
    service.interceptors.request.use(config => {
      config.headers.token = localStorage.getItem('token');
      return config;
    });
    // 响应拦截:统一错误处理
    service.interceptors.response.use(
      res => res.data,
      err => { /* 统一错误提示(如 Element Plus Message) */ }
    );
    export default service;
    
    // api/request/uniRequest.js(uni-app 端)
    export default function uniRequest(config) {
      return new Promise((resolve, reject) => {
        uni.request({
          url: config.baseURL || import.meta.env.VITE_API_BASE_URL, // 移动端环境变量
          method: config.method || 'GET',
          data: config.data,
          header: { token: uni.getStorageSync('token') }, // uni-app 存储 API
          success: res => resolve(res.data),
          fail: err => { /* 统一错误提示(如 uni.showToast) */ }
        });
      });
    }
    
    // api/request/index.js(入口:自动适配环境)
    let request;
    if (process.env.VUE_APP_PLATFORM === 'web') {
      request = import('./webRequest').then(m => m.default);
    } else {
      request = import('./uniRequest').then(m => m.default);
    }
    export default request;
  • 业务接口层(纯逻辑复用,无平台依赖):

    javascript 复制代码
    // api/modules/user.js(两端完全复用)
    import request from '../request';
    
    // 登录接口
    export const login = (params) => request({
      url: '/api/user/login',
      method: 'POST',
      data: params
    });
    
    // 获取用户权限列表
    export const getUserPermissions = () => request({
      url: '/api/user/permissions',
      method: 'GET'
    });

3. 状态管理层(store):核心业务状态共享

核心目标

用 Vuex/Pinia 管理全局状态(如用户信息、权限、全局配置),两端共享状态定义和 mutations/actions,仅适配平台特有存储(如 token 存储)。

实现方案

  • 技术选型:优先用 Pinia(Vue 3 推荐,支持 TypeScript,更轻量,如果项目的搭建时不要求ts,推荐vuex),两端共用 Pinia 实例。

  • 目录结构

    复制代码
    store/
    ├─ index.js:Pinia 实例创建(适配两端存储)
    ├─ modules/
    │  ├─ userStore.js:用户状态(登录、权限)
    │  ├─ appStore.js:应用配置(主题、语言)
    │  └─ orderStore.js:订单状态(待办数量、筛选条件)
  • 关键实现:适配两端存储

    javascript 复制代码
    // store/index.js(Pinia 实例创建)
    import { createPinia } from 'pinia';
    import { createPersistedState } from 'pinia-plugin-persistedstate'; // 持久化插件
    
    const pinia = createPinia();
    
    // 适配两端持久化存储:Vue 用 localStorage,uni-app 用 uniStorage
    const storage = process.env.VUE_APP_PLATFORM === 'web' 
      ? window.localStorage 
      : {
          getItem: uni.getStorageSync,
          setItem: uni.setStorageSync,
          removeItem: uni.removeStorageSync
        };
    
    // 安装持久化插件,指定存储方式
    pinia.use(createPersistedState({
      storage: {
        getItem: (key) => storage.getItem(key),
        setItem: (key, value) => storage.setItem(key, value),
        removeItem: (key) => storage.removeItem(key)
      }
    }));
    
    export default pinia;
  • 业务状态示例(用户状态,两端复用):

    javascript 复制代码
    // store/modules/userStore.js
    import { defineStore } from 'pinia';
    import { login, getUserPermissions } from '@/api/modules/user';
    import { hasPermission } from '@/utils/compute/permission';
    
    export const useUserStore = defineStore('user', {
      state: () => ({
        token: '',
        info: {}, // 用户信息
        permissions: [] // 权限列表
      }),
      actions: {
        // 登录:业务逻辑完全复用
        async loginAction(params) {
          const res = await login(params);
          this.token = res.token;
          await this.getPermissionsAction(); // 登录后获取权限
        },
        // 获取权限:业务逻辑完全复用
        async getPermissionsAction() {
          const res = await getUserPermissions();
          this.permissions = res.list;
        },
        // 权限判断:复用工具函数
        hasPerm(perm) {
          return hasPermission(this.permissions, perm);
        }
      },
      persist: true // 持久化状态(适配两端存储)
    });

4. 业务逻辑层(services):封装复杂业务流程

核心目标

将跨组件的复杂业务流程(如表单提交、数据导出、批量操作)抽离为 service 方法,两端复用业务逻辑,仅调用平台特有 UI 交互(如弹窗、加载提示)。

实现方案

  • 目录结构:按业务模块分类,每个 service 方法接收 "平台适配回调" 处理 UI 差异:

    plaintext

    复制代码
    services/
    ├─ userService.js:用户相关(密码重置、信息修改)
    ├─ orderService.js:订单相关(批量审核、导出订单)
    └─ formService.js:表单相关(复杂表单提交、数据校验)
  • 代码示例(订单批量审核,适配两端 UI):

    javascript 复制代码
    // services/orderService.js
    import { useOrderStore } from '@/store/modules/orderStore';
    import { batchAuditOrder } from '@/api/modules/order';
    
    /**
     * 批量审核订单
     * @param {Array} orderIds - 订单ID列表
     * @param {Function} loadingCallback - 平台加载提示(如 Vue 的 ElLoading、uni 的 showLoading)
     * @param {Function} successCallback - 平台成功提示(如 ElMessage、uni.showToast)
     */
    export const batchAuditOrderService = async (orderIds, loadingCallback, successCallback) => {
      const orderStore = useOrderStore();
      // 1. 调用平台加载提示(通过回调适配)
      const closeLoading = loadingCallback();
      
      try {
        // 2. 业务逻辑:调用 API + 更新状态(两端复用)
        await batchAuditOrder({ ids: orderIds });
        await orderStore.getOrderListAction(); // 重新获取订单列表
        // 3. 调用平台成功提示(通过回调适配)
        successCallback('审核成功');
      } catch (err) {
        throw err; // 抛错让调用方处理(如统一错误提示)
      } finally {
        closeLoading(); // 关闭加载提示
      }
    };
  • 两端调用示例

    javascript 复制代码
    // Vue PC 端调用
    import { batchAuditOrderService } from '@/services/orderService';
    import { ElLoading, ElMessage } from 'element-plus';
    
    const handleBatchAudit = async () => {
      await batchAuditOrderService(
        selectedIds,
        () => ElLoading.service({ text: '审核中...' }), // PC 加载提示
        (msg) => ElMessage.success(msg) // PC 成功提示
      );
    };
    
    // uni-app 移动端调用
    import { batchAuditOrderService } from '@/services/orderService';
    
    const handleBatchAudit = async () => {
      await batchAuditOrderService(
        selectedIds,
        () => { // 移动端加载提示
          uni.showLoading({ title: '审核中...' });
          return () => uni.hideLoading(); // 返回关闭方法
        },
        (msg) => uni.showToast({ title: msg, icon: 'success' }) // 移动端成功提示
      );
    };

5. 视图层:差异化实现,复用公共组件

核心目标

UI 组件和页面因平台交互差异(PC 用鼠标 / 键盘,移动端用触摸)需单独实现,但可抽离 "无交互纯展示组件"(如数据卡片、空状态)两端复用。

实现方案

  • 公共 UI 组件 :在 components/common 目录创建纯展示组件(无平台依赖),如:

    css 复制代码
    components/
    ├─ common/:两端复用组件
    │  ├─ EmptyState.vue:空状态(无数据提示)
    │  ├─ DataCard.vue:数据卡片(展示统计数据)
    │  └─ TablePagination.vue:分页控件(适配两端表格)
    ├─ web/:Vue PC 特有组件(如 ElTable 封装)
    └─ uni/:uni-app 特有组件(如 uni-table 封装)
  • 页面差异化:两端页面目录分开,但复用公共业务逻辑:

    ruby 复制代码
    // Vue PC 端页面
    views/web/order/OrderList.vue:用 Element Plus 组件,调用 orderService
    // uni-app 移动端页面
    pages/uni/order/OrderList.vue:用 uni-app 组件,调用 same orderService

三、工程化保障:统一规范,降低维护成本

1. 环境配置统一

  • .env 文件统一管理环境变量(API 地址、环境标识),两端共享变量名:

    ini 复制代码
    // Vue PC 端 .env.development
    VITE_API_BASE_URL = 'https://pc-api.xxx.com'
    VITE_APP_PLATFORM = 'web'
    
    // uni-app 端 .env.development
    VITE_API_BASE_URL = 'https://mobile-api.xxx.com'
    VITE_APP_PLATFORM = 'uni'

2. 代码规范统一

  • 用 ESLint + Prettier 统一代码风格,两端共用配置文件(.eslintrc.js.prettierrc);
  • 用 Husky + lint-staged 做提交校验,避免不规范代码提交。

3. 构建部署统一

  • Vue PC 端:用 Vite 构建,部署到 Web 服务器(如 Nginx);
  • uni-app 端:用 HBuilderX 或 CLI 构建,发布为微信小程序 / APP;
  • 公共层(utils/api/store)可打包为 npm 私有包,两端通过 npm 安装,避免代码复制。
相关推荐
边洛洛3 小时前
next.js项目部署流程
开发语言·前端·javascript
Zsnoin能3 小时前
浏览器连接 新北洋BTP-P33/P32蓝牙打印机,打印 二维码
前端
非凡ghost3 小时前
Syncovery Premium(文件同步软件)
前端·javascript·后端
trsoliu3 小时前
2025前端AI Coding产品与实战案例大盘点
前端·ai编程
杨筱毅3 小时前
【底层机制】Linux内核4.10版本的完整存储栈架构讲解--用户空间到物理设备完整IO路径
linux·架构·1024程序员节·底层机制
云中雾丽3 小时前
react-checkbox的封装
前端
乐园游梦记3 小时前
告别Ctrl+F5!解决VUE生产环境缓存更新的终极方案
前端
岁月宁静3 小时前
用 Node.js 封装豆包语音识别AI模型接口:双向实时流式传输音频和文本
前端·人工智能·node.js
猪猪拆迁队3 小时前
前端图形架构设计:AI生成设计稿落地实践
前端·后端·ai编程