Files
integral-shop/docs/integral-pages-coding-plan.md
scott ee0886b800 feat: 新增积分外部页面(免认证三页 + 配套基础设施)
前端:
- 新增 EmptyLayout 空壳布局(无侧边栏/导航)
- 新增 requestNoAuth Axios 实例(不注入 token)
- 新增 integralExternal 路由模块(/integral-external/*)
- permission.js 加入 whiteListPrefixes 前缀白名单跳过登录
- 新增 phoneDesensitize 手机号脱敏过滤器
- 新增三个免认证页面:
  · 积分订单页(/integral-external/order)
  · 用户积分页(/integral-external/user,手机号脱敏)
  · 用户积分明细子页(/integral-external/user/integral-detail)

后端:
- 新增 ExternalIntegralController(无 @PreAuthorize)
  · GET  /api/external/integral/order/list
  · GET  /api/external/integral/user/list
  · POST /api/external/integral/log/list
- WebSecurityConfig 加入 /api/external/integral/** permitAll

文档与工具:
- 新增 coding plan、schedule、测试报告
- 新增 start-backend.sh / start-frontend.sh 本地启动脚本
- 新增 .mvn/wrapper/maven-wrapper.properties

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:41:30 +08:00

23 KiB
Raw Permalink Blame History

积分模块新增页面 — Coding Plan

版本v1.0 日期2026-03-30 范围管理后台backend-adminend新增积分订单、用户积分、用户积分明细三个独立页面


1. 需求概述

在管理后台中新增三个独立页面,用于积分业务的外部查看与运营。所有页面需跳过用户登录验证,按后端 API 最小修改原则,尽量复用现有后端接口。

序号 页面 参考原页面 说明
1 积分订单 /order/index 新建独立页面,展示积分相关订单
2 用户积分 /user/index 新建独立页面,增加 wa_users 相关字段
3 用户积分明细 用户管理 → 账户详情 → 积分明细 子页面,复用 /admin/user/integral/list 接口

2. 技术架构分析

2.1 技术栈

管理后台前端基于 Vue 2 + Vue CLI + Element UI + Vue Router (history mode) + Vuex + Axios。

2.2 现有认证机制

认证逻辑位于 src/permission.js,通过 router.beforeEach 全局守卫实现。未登录时除白名单路由外,一律重定向至 /login

白名单当前值:['/login', '/auth-redirect']

请求拦截器(src/utils/request.js)会在 header 中附加 Authori-zation token后端返回 401 时自动跳转登录页。

2.3 关键参考文件

文件 说明
src/views/order/index.vue 订单列表页,约 40k 行,含筛选/表格/分页/操作
src/views/user/list/index.vue 用户管理页,含多条件筛选、用户详情弹窗
src/views/user/integral/index.vue 积分日志页242 行),表格 + 搜索 + 分页
src/api/integral.js 积分接口:integralListApi → POST /admin/user/integral/list
src/api/user.js 用户接口:userListApi → GET /admin/user/list
src/router/modules/order.js 订单路由定义
src/router/modules/user.js 用户路由定义
src/router/index.js 主路由,含 constantRoutes 和白名单
src/permission.js 全局路由守卫(登录校验)
src/utils/request.js Axios 封装token 注入 & 401 拦截

2.4 wa_users 表字段(需要在用户积分页展示)

字段 类型 说明
id int 主键
username string 用户名
nickname string 昵称
mobile string 手机号
money BigDecimal 账户余额
selfBonus BigDecimal 个人奖金
shareBonus BigDecimal 分享奖金
score BigDecimal 积分
level int 等级
status int 状态0=禁用, 1=启用)
isVip int VIP0=否, 1=是)
isResell int 可转卖0=否, 1=是)
joinTime timestamp 注册时间
lastTime timestamp 最后登录

3. 整体方案设计

3.1 目录结构规划

src/
├── views/
│   └── integral-external/           # 新增:积分外部页面目录
│       ├── order/
│       │   └── index.vue            # 积分订单页面
│       ├── user/
│       │   └── index.vue            # 用户积分页面
│       └── user-integral-detail/
│           └── index.vue            # 用户积分明细子页面
├── api/
│   └── integralExternal.js          # 新增:积分外部页面 API 集合
├── router/
│   └── modules/
│       └── integralExternal.js      # 新增:积分外部路由模块
└── layout/
    └── EmptyLayout.vue              # 新增:空白布局(无侧边栏/顶栏)

3.2 跳过登录验证方案

采用多层级免登录策略,确保页面完全绕过认证:

第一层:路由白名单

src/permission.jswhiteList 中添加新页面路径前缀:

const whiteList = ['/login', '/auth-redirect', '/integral-external'];

同时修改白名单匹配逻辑,从精确匹配改为前缀匹配:

// 修改前
if (whiteList.indexOf(to.path) !== -1)

// 修改后
if (whiteList.some(path => to.path.startsWith(path)))

第二层:无 token 请求支持

新建一个不注入 token、不拦截 401 的 Axios 实例 requestNoAuth,供外部页面 API 使用:

// src/utils/requestNoAuth.js
import axios from 'axios';
import { Message } from 'element-ui';
import SettingMer from '@/utils/settingMer';

const service = axios.create({
  baseURL: SettingMer.apiBaseURL,
  timeout: 60000,
});

// 不注入 token不拦截 401 跳转
service.interceptors.response.use(
  (response) => {
    const res = response.data;
    if (res.code !== 0 && res.code !== 200) {
      Message({ message: res.msg || '请求失败', type: 'error' });
      return Promise.reject(new Error(res.msg || '请求失败'));
    }
    return res.data;
  },
  (error) => {
    Message({ message: '网络请求失败', type: 'error' });
    return Promise.reject(error);
  },
);

export default service;

第三层:空白布局

新建 EmptyLayout.vue,不包含侧边栏、顶栏和权限组件,作为外部页面的容器:

<template>
  <div class="integral-external-layout">
    <router-view />
  </div>
</template>

4. 各页面详细设计

4.1 积分订单页面

路由/integral-external/order 参考src/views/order/index.vue

功能要点

从原订单页面中提取积分订单相关的核心功能,去除权限校验(v-hasPermi)和管理操作(编辑、发货、退款等),保留只读展示。

筛选条件

筛选项 类型 说明
订单状态 RadioGroup 全部/未支付/未发货/待收货/交易完成 等
时间选择 DateRangePicker 快捷选项 + 自定义范围
订单号 Input 精确搜索

表格列

字段 宽度
订单号 orderId 210
订单类型 orderType 110
收货人 realName 100
商品信息 productList 400
支付金额 payPrice 100
支付方式 payType 100
订单状态 status 100
创建时间 createTime 150

API 复用

直接复用现有订单列表接口。需确认后端是否允许无 token 调用,若不允许,需后端新增一个免认证的订单查询接口(或在已有接口上增加免认证标注)。

// src/api/integralExternal.js
export function getIntegralOrderList(params) {
  return requestNoAuth({
    url: '/admin/order/list',  // 复用原接口或后端新增免认证接口
    method: 'get',
    params,
  });
}

实现步骤

  1. 复制 order/index.vue 为基础模板
  2. 删除所有 v-hasPermi 权限指令
  3. 删除操作列(编辑价格、发货、退款等按钮)
  4. 删除导出功能
  5. 将 API 调用替换为 requestNoAuth 版本
  6. 简化订单类型筛选,只保留积分相关类型
  7. 去除 Vuex store 依赖

4.2 用户积分页面

路由/integral-external/user 参考src/views/user/list/index.vue

功能要点

基于用户列表页精简,增加 wa_users 表的积分/奖金相关字段展示,提供积分明细跳转入口。

筛选条件

筛选项 类型 说明
用户搜索 Input 姓名/手机号/用户名
时间选择 DateRangePicker 注册时间范围

表格列

字段 来源 说明
用户ID uid CRMEB 系统用户ID
用户昵称 nickname CRMEB
手机号 phone CRMEB
系统积分 integral CRMEB CRMEB 系统积分
WA用户名 wa_username wa_users WA系统用户名
账户余额 wa_money wa_users WA账户余额
个人奖金 wa_selfBonus wa_users 可提现奖金
分享奖金 wa_shareBonus wa_users 推荐奖金
WA积分 wa_score wa_users WA系统积分
用户等级 wa_level wa_users
状态 wa_status wa_users 启用/禁用
注册时间 createTime CRMEB
操作 查看积分明细

API 方案

方案 A推荐 — 最小后端修改):前端分别调用用户列表接口和 WA 用户信息接口,在前端做数据合并。

// 复用原用户列表
export function getUserListNoAuth(params) {
  return requestNoAuth({
    url: '/admin/user/list',
    method: 'get',
    params,
  });
}

// 复用前端 WA 用户信息接口(需确认是否免认证)
export function getWaUserInfo(userId) {
  return requestNoAuth({
    url: '/api/front/wa/user/info',
    method: 'post',
    data: { userId },
  });
}

方案 B若后端配合:后端新增一个聚合接口,一次性返回 CRMEB 用户 + wa_users 的合并数据。

操作列

"查看积分明细" 按钮,点击后跳转至用户积分明细子页面,携带 uid 参数:

this.$router.push({
  path: '/integral-external/user/integral-detail',
  query: { uid: row.uid },
});

实现步骤

  1. user/list/index.vue 为参考创建精简版页面
  2. 删除所有权限指令、分组/标签/等级筛选、操作按钮(编辑、设为分销员等)
  3. 删除 Tab 切换(全部/有效/无效用户)
  4. 在表格中增加 wa_users 字段列
  5. 实现前端数据合并逻辑(逐行匹配或批量查询)
  6. 添加"查看积分明细"操作按钮
  7. 将所有 API 替换为 requestNoAuth 版本

4.3 用户积分明细子页面

路由/integral-external/user/integral-detail 参考src/views/user/integral/index.vue242 行) 后端 APIPOST /admin/user/integral/list(复用)

功能要点

该页面完整复用原积分日志页的展示逻辑,通过 URL query 参数 uid 锁定指定用户,隐藏"用户搜索"字段。

筛选条件

筛选项 类型 说明
用户ID 隐藏字段 从 URL query uid 自动获取
时间选择 DateRangePicker 日期范围

表格列(完全复用原页面)

字段 说明
ID id 记录ID
用户ID uid
用户昵称 nickName
标题 title 积分变动标题
积分变动 integral +/- 显示
剩余积分 balance 变动后余额
类型 type 增加(1)/扣减(2)
关联类型 linkType 订单/签到/系统
状态 status 订单创建/冻结期/完成/失效
备注 mark
创建时间 createTime

API 复用

export function getIntegralLogNoAuth(data) {
  return requestNoAuth({
    url: '/admin/user/integral/list',  // 直接复用原接口
    method: 'post',
    data,
  });
}

页面头部信息

在表格上方展示当前用户的积分概览卡片:

┌──────────────────────────────────────┐
│  用户:张三 (UID: 1001)               │
│  积分1,200    个人奖金350          │
│  [← 返回用户积分列表]                  │
└──────────────────────────────────────┘

字段说明:积分取自 eb_user 表的 integral 字段(BigDecimal,用户剩余积分);个人奖金取自 wa_users 表的 selfBonus 字段。

实现步骤

  1. 复制 user/integral/index.vue 作为基础
  2. 从 URL query 中读取 uid,自动注入搜索参数
  3. 隐藏"用户搜索"和"用户ID"输入框(已通过 query 锁定)
  4. 添加顶部用户信息概览卡片
  5. 添加"返回"按钮
  6. 替换 API 为 requestNoAuth 版本

5. 路由配置

5.1 新增路由模块

// src/router/modules/integralExternal.js
const EmptyLayout = () => import('@/layout/EmptyLayout');

const integralExternalRouter = {
  path: '/integral-external',
  component: EmptyLayout,
  redirect: '/integral-external/order',
  hidden: true,    // 不在侧边栏显示
  children: [
    {
      path: 'order',
      component: () => import('@/views/integral-external/order/index'),
      name: 'IntegralExternalOrder',
      meta: { title: '积分订单' },
    },
    {
      path: 'user',
      component: () => import('@/views/integral-external/user/index'),
      name: 'IntegralExternalUser',
      meta: { title: '用户积分' },
    },
    {
      path: 'user/integral-detail',
      component: () => import('@/views/integral-external/user-integral-detail/index'),
      name: 'IntegralExternalUserDetail',
      meta: { title: '用户积分明细' },
    },
  ],
};

export default integralExternalRouter;

5.2 注册路由

src/router/index.js 中将新模块加入 constantRoutes

import integralExternalRouter from './modules/integralExternal';

export const constantRoutes = [
  integralExternalRouter,   // 积分外部页面(免登录)
  storeRouter,
  orderRouter,
  // ...其余路由
];

5.3 修改权限守卫

src/permission.js 中扩展白名单:

const whiteList = ['/login', '/auth-redirect', '/integral-external'];

// 匹配逻辑改为前缀匹配
if (whiteList.some(path => to.path.startsWith(path))) {
  next();
}

6. 后端 API 影响评估

6.1 可直接复用的接口

接口 Method 免认证现状 所需改动
/admin/user/integral/list POST 需认证 需后端为外部调用新增免认证入口,或前端伪造 token
/admin/user/list GET 需认证 同上
/admin/order/list GET 需认证 同上

6.2 推荐的后端最小改动方案

按照"最小修改原则",建议后端在现有 Controller 基础上新增一套免认证的映射路径,内部直接调用相同的 Service 方法:

新路径                                   → 复用的 Service 方法
/api/external/integral/order/list       → OrderService.list()
/api/external/integral/user/list        → UserService.list()(补充 wa_users 字段)
/api/external/integral/log/list         → IntegralService.list()

只需新建一个 ExternalIntegralController,加 @RestController 免认证注解,约 50-80 行代码。

6.3 wa_users 字段集成

方案 A:后端在用户列表接口返回中直接 JOIN wa_users 表,新增字段返回。 方案 B:前端先拿用户列表,再批量查 wa_users 信息,前端做合并。

推荐方案 A后端改动更少前端实现更简单


7. 开发任务清单

Phase 1基础设施预计 0.5 天)

# 任务 文件
1.1 创建 EmptyLayout.vue 空白布局 src/layout/EmptyLayout.vue
1.2 创建 requestNoAuth.js 免认证请求实例 src/utils/requestNoAuth.js
1.3 创建 integralExternal.js 路由模块 src/router/modules/integralExternal.js
1.4 注册路由到 constantRoutes src/router/index.js
1.5 修改 permission.js 白名单 src/permission.js
1.6 创建 integralExternal.js API 文件 src/api/integralExternal.js

Phase 2积分订单页面预计 1 天)

# 任务
2.1 基于 order/index.vue 创建精简版积分订单页
2.2 去除权限校验、操作按钮、导出功能
2.3 接入 requestNoAuth 请求
2.4 测试筛选、分页、数据展示

Phase 3用户积分页面预计 1.5 天)

# 任务
3.1 基于 user/list/index.vue 创建精简版用户积分页
3.2 去除高级筛选、权限、操作按钮
3.3 增加 wa_users 字段列(奖金、积分、余额等)
3.4 实现数据合并逻辑(前端或后端)
3.5 添加"查看积分明细"跳转按钮
3.6 测试数据展示与跳转

Phase 4用户积分明细子页面预计 0.5 天)

# 任务
4.1 基于 user/integral/index.vue 创建积分明细页
4.2 通过 URL query 读取 uid 并锁定用户
4.3 添加用户积分概览卡片
4.4 添加返回按钮
4.5 接入 requestNoAuth 请求
4.6 测试分页、筛选、数据展示

Phase 5联调与验收预计 0.5 天)

# 任务
5.1 无 token 状态下完整流程测试
5.2 页面间跳转逻辑验证
5.3 后端免认证接口联调
5.4 兼容性和响应式测试

总计预估工时4 天


8. 测试方案

8.1 免登录访问测试

编号 测试场景 操作步骤 预期结果
A-01 无 token 直接访问积分订单页 清除浏览器所有 cookie/sessionStorage直接访问 /integral-external/order 页面正常加载,不跳转至 /login
A-02 无 token 直接访问用户积分页 同上,访问 /integral-external/user 页面正常加载,不跳转至 /login
A-03 无 token 直接访问积分明细页 同上,访问 /integral-external/user/integral-detail?uid=1 页面正常加载,不跳转至 /login
A-04 免登录页面不影响原有认证 无 token 访问 /order/index(原页面) 仍然正常跳转至 /login
A-05 已登录用户访问免登录页面 管理员登录后访问 /integral-external/order 页面正常加载,不受登录态影响

8.2 积分订单页面测试

编号 测试场景 操作步骤 预期结果
B-01 默认加载 进入页面 表格展示订单列表,分页信息正确
B-02 按订单状态筛选 依次点击"未支付""未发货""交易完成"等状态 表格数据按状态正确过滤,数量标签更新
B-03 按时间范围筛选 选择起止日期 仅显示时间范围内的订单
B-04 按订单号搜索 输入完整订单号,点击搜索 精确匹配到对应订单
B-05 重置筛选条件 设置筛选条件后点击重置 所有筛选项恢复默认,表格展示全部数据
B-06 分页切换 切换页码、修改每页显示数 数据正确刷新,分页器状态正确
B-07 空数据状态 搜索不存在的订单号 表格显示空状态提示,无 JS 报错
B-08 无操作列 检查表格列 不存在编辑、发货、退款等操作按钮

8.3 用户积分页面测试

编号 测试场景 操作步骤 预期结果
C-01 默认加载 进入页面 用户列表正常展示,含 CRMEB 和 wa_users 字段
C-02 wa_users 字段展示 查看表格列 个人奖金(selfBonus)、账户余额(money)等 wa_users 字段正确显示
C-03 积分字段来源验证 对比数据库 eb_user.integral 页面显示的积分与 eb_user 表一致
C-04 wa_users 无关联数据 查看无 wa_users 记录的 CRMEB 用户行 wa_users 相关列显示 -0,不报错
C-05 用户搜索 输入姓名/手机号搜索 正确过滤,支持模糊匹配
C-06 跳转积分明细 点击某用户行的"查看积分明细" 正确跳转至 /integral-external/user/integral-detail?uid=xxx
C-07 分页功能 切换页码和每页条数 数据正确刷新
C-08 无权限指令残留 审查页面 DOM 不存在 v-hasPermi 相关的隐藏元素或报错

8.4 用户积分明细子页面测试

编号 测试场景 操作步骤 预期结果
D-01 带 uid 参数加载 访问 ?uid=1001 自动加载 uid=1001 的积分明细,顶部概览卡片显示用户信息
D-02 概览卡片数据验证 对比数据库值 积分值 = eb_user.integral,个人奖金 = wa_users.selfBonus
D-03 无 uid 参数访问 访问不带 ?uid 参数的页面 页面给出"缺少用户参数"提示,或重定向至用户积分列表
D-04 无效 uid 访问 访问 ?uid=999999(不存在的用户) 表格为空,概览卡片显示空状态,无 JS 报错
D-05 时间范围筛选 选择日期范围 积分明细按时间正确过滤
D-06 积分变动显示 查看积分变动列 增加显示绿色 +,扣减显示红色 -
D-07 状态与关联类型 查看状态和关联类型列 订单创建/冻结期/完成/失效 正确渲染标签颜色;订单/签到/系统 正确显示
D-08 返回按钮 点击"返回用户积分列表" 正确跳转回 /integral-external/user
D-09 分页功能 切换页码15/30/45/60 数据正确刷新

8.5 接口与数据测试

编号 测试场景 操作步骤 预期结果
E-01 免认证接口可达性 无 token 调用各外部接口 返回 200 及正确业务数据,不返回 401
E-02 原认证接口不受影响 无 token 调用原 /admin/user/list 等接口 仍返回 401
E-03 接口仅读不写 尝试对免认证接口发送写操作请求 返回 403 或方法不允许
E-04 大数据量分页 请求 limit=60数据总量 > 1000 分页正确,响应时间 < 3s
E-05 边界参数 page=0、limit=-1、uid=null 等异常参数 接口返回友好错误信息,不产生 500
E-06 数据脱敏验证 检查返回的手机号字段 中间 4 位做掩码处理(如 138****8888

8.6 兼容性与 UI 测试

编号 测试场景 预期结果
F-01 Chrome 最新版 页面布局正常,功能正常
F-02 Firefox 最新版 页面布局正常,功能正常
F-03 Edge 最新版 页面布局正常,功能正常
F-04 1920×1080 分辨率 表格列宽合理,无横向滚动条溢出
F-05 1366×768 分辨率 表格可横向滚动,筛选栏自动换行
F-06 EmptyLayout 布局验证 页面无侧边栏、无顶部导航栏、无面包屑
F-07 加载状态 数据加载中显示 loading 动画

8.7 测试执行时间规划

阶段 内容 预计时间
冒烟测试 Phase 1 基础设施完成后,验证 A-01 ~ A-05 免登录链路 0.5h
功能测试 每个页面开发完成后,执行对应 B/C/D 组用例 每页面 1~2h
接口联调测试 后端免认证接口就绪后,执行 E 组用例 1h
回归测试 全部开发完成后,执行全量用例 2h
兼容性测试 回归通过后,执行 F 组用例 1h

9. 注意事项

  1. 安全风险:免登录页面直接暴露后台数据,建议后端对免认证接口做 IP 白名单或 API Key 鉴权。
  2. 数据脱敏:用户手机号等敏感字段建议做中间位掩码处理(如 138****8888)。
  3. 接口幂等所有免认证接口仅开放读取权限GET/查询),禁止写操作。
  4. 路由隔离:新页面使用 EmptyLayout,与管理后台主布局完全隔离,避免引入侧边栏/权限组件的副作用。
  5. 组件依赖:新页面可复用 Element UI 组件,但避免引入需要 Vuex store如用户信息、权限的业务组件。