For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 为夜市用户(userType=3)提供摊位管理能力,包括创建摊位、管理摊位主账号。
Architecture: 在现有 PosStore 和 InfoUser 模型上扩展,PosStore 新增 isStall 字段标识摊位,InfoUser 新增 storeId 字段关联摊位主到摊位。后端新增摊位管理 Controller,前端商家端新增摊位管理菜单页面。
Tech Stack: Java / Spring Boot / MyBatis / MySQL / Vue 2 / Element UI
Language/Version: Java 8+, Vue 2 Primary Dependencies: RuoYi framework, MyBatis, Element UI Storage: MySQL Testing: 手动测试(项目无自动化测试框架) Target Platform: Web (商家管理后台) Project Type: Web application (前后端分离)
注意事项:
isNightMarket(Integer) 和 nightMarketId(Long) 字段,可用于关联夜市address、longitude、latitude 字段,已有夜市地址支持specs/001-food-stall/
├── spec.md # 需求文档
└── plan.md # 本文件(实施计划)
foodie_server/
├── ruoyi-admin/src/main/java/com/ruoyi/app/
│ ├── mendian/PosStoreController.java # [修改] 现有店铺 Controller
│ ├── stall/StallController.java # [新建] 摊位管理 Controller
│ └── user/InfoUserController.java # [修改] 用户注册(可能复用)
├── ruoyi-system/src/main/java/com/ruoyi/system/
│ ├── domain/
│ │ ├── PosStore.java # [修改] 新增 isStall 字段
│ │ └── InfoUser.java # [修改] 新增 storeId 字段
│ ├── mapper/
│ │ ├── PosStoreMapper.java # [修改] 查询方法
│ │ ├── PosStoreMapper.xml # [修改] SQL 语句
│ │ ├── InfoUserMapper.java # [修改] 查询方法
│ │ └── InfoUserMapper.xml # [修改] SQL 语句
│ └── service/
│ ├── IPosStoreService.java # [修改] 接口方法
│ ├── impl/PosStoreServiceImpl.java # [修改] 实现方法
│ ├── IInfoUserService.java # [修改] 接口方法
│ └── impl/InfoUserServiceImpl.java # [修改] 实现方法
foodie-store/ # 商家前端
├── src/
│ ├── api/stall.js # [新建] 摊位管理 API
│ ├── views/
│ │ └── StallManage.vue # [新建] 摊位管理页面
│ ├── components/
│ │ └── Aside.vue # [修改] 侧边栏菜单
│ └── router/index.js # [修改] 路由配置
Files:
ruoyi-system/src/main/resources/mapper/chanting/PosStoreMapper.xmlModify: ruoyi-system/src/main/java/com/ruoyi/system/domain/PosStore.java
[ ] Step 1: 执行 SQL 添加字段
ALTER TABLE pos_store ADD COLUMN is_stall TINYINT DEFAULT 0 COMMENT '是否摊位 0=店铺 1=摊位';
[ ] Step 2: PosStore.java 新增 isStall 字段
在 PosStore.java 中添加:
/** 是否摊位 0=店铺 1=摊位 */
private Integer isStall;
添加 getter/setter:
public Integer getIsStall() { return isStall; }
public void setIsStall(Integer isStall) { this.isStall = isStall; }
在 PosStoreResult resultMap 中添加:
<result property="isStall" column="is_stall"/>
在 selectPosStoreVo 中添加 is_stall 字段。
在 insertPosStore 中添加:
<if test="isStall != null">is_stall,</if>
...
<if test="isStall != null">#{isStall},</if>
在 updatePosStore 中添加:
<if test="isStall != null">is_stall = #{isStall},</if>
在 selectPosStoreList 的 where 中添加:
<if test="isStall != null"> and is_stall = #{isStall}</if>
启动项目,确认 PosStore 相关接口正常工作。
Files:
ruoyi-system/src/main/resources/mapper/system/InfoUserMapper.xmlModify: ruoyi-system/src/main/java/com/ruoyi/system/domain/InfoUser.java
[ ] Step 1: 执行 SQL 添加字段
ALTER TABLE info_user ADD COLUMN store_id BIGINT DEFAULT NULL COMMENT '关联摊位ID(摊位主使用)';
[ ] Step 2: InfoUser.java 新增 storeId 字段
/** 关联摊位ID(摊位主使用) */
private Long storeId;
添加 getter/setter。
在 resultMap 中添加 store_id 映射,在 insert/update/select 中添加 storeId 字段支持。
启动项目,确认 InfoUser 相关接口正常工作。
Files:
Create: ruoyi-admin/src/main/java/com/ruoyi/app/stall/StallController.java
[ ] Step 1: 创建 StallController.java
提供以下接口:
@RestController
@RequestMapping("/stall")
public class StallController extends BaseController {
/** 获取当前夜市用户的摊位列表(isStall=1) */
@GetMapping("/list")
public AjaxResult getStallList(@Auth InfoUser user) {
PosStore query = new PosStore();
query.setUserId(user.getUserId());
query.setIsStall(1);
return AjaxResult.success(posStoreService.selectPosStoreList(query));
}
/** 创建摊位(复用 PosStore,isStall=1) */
@PostMapping("/add")
@Transactional
public AjaxResult addStall(@Auth InfoUser user, @RequestBody PosStore posStore) {
posStore.setUserId(user.getUserId());
posStore.setIsStall(1);
posStoreService.insertPosStore(posStore);
return AjaxResult.success(posStore);
}
/** 为摊位创建摊位主账号 */
@PostMapping("/addOwner")
public AjaxResult addStallOwner(@Auth InfoUser user, @RequestBody InfoUser stallOwner) {
// 校验摊位属于当前夜市用户
// 设置 userType=4, storeId, 加密密码
// 创建用户
return AjaxResult.success();
}
/** 获取摊位下的摊位主列表 */
@GetMapping("/owners")
public AjaxResult getStallOwners(@RequestParam Long storeId) {
// 查询 userType=4, storeId=storeId 的用户列表
return AjaxResult.success();
}
/** 删除/禁用摊位主 */
@PutMapping("/disableOwner")
public AjaxResult disableStallOwner(@RequestParam Long userId) {
// 设置 status=1(禁用)
return AjaxResult.success();
}
}
InfoUserMapper.xml 中添加:
<select id="selectStallOwnersByStoreId" parameterType="Long" resultMap="InfoUserResult">
<include refid="selectInfoUserVo"/>
where store_id = #{storeId} and user_type = '4' and del_flag = '0'
</select>
使用 Postman/浏览器测试各接口。
Files:
Create: E:\QtwCode\foodie\foodie-store\src\api\stall.js
[ ] Step 1: 创建 stall.js
import request from '@/router/request'
// 获取摊位列表
export function getStallList() {
return request({ url: '/stall/list', method: 'get' })
}
// 创建摊位
export function addStall(data) {
return request({ url: '/stall/add', method: 'post', data })
}
// 获取摊位主列表
export function getStallOwners(storeId) {
return request({ url: '/stall/owners', method: 'get', params: { storeId } })
}
// 创建摊位主
export function addStallOwner(data) {
return request({ url: '/stall/addOwner', method: 'post', data })
}
// 禁用摊位主
export function disableStallOwner(userId) {
return request({ url: '/stall/disableOwner', method: 'put', params: { userId } })
}
Files:
E:\QtwCode\foodie\foodie-store\src\views\StallManage.vueE:\QtwCode\foodie\foodie-store\src\router\index.jsModify: E:\QtwCode\foodie\foodie-store\src\components\Aside.vue
[ ] Step 1: 创建 StallManage.vue 页面
页面包含:
[ ] Step 2: 修改 router/index.js 添加摊位管理路由
{
path: '/stall-manage',
name: 'StallManage',
component: () => import('@/views/StallManage.vue')
}
[ ] Step 3: 修改 Aside.vue 添加「摊位管理」菜单项
在侧边栏菜单中添加摊位管理入口,仅夜市用户(userType=3)可见。
启动前端项目,登录夜市用户账号,验证:
Files:
ruoyi-system/src/main/resources/mapper/system/UserWalletMapper.xmlruoyi-system/src/main/java/com/ruoyi/system/domain/UserWallet.javaModify: ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserWalletServiceImpl.java
[ ] Step 1: 执行 SQL 添加字段
ALTER TABLE user_wallet ADD COLUMN store_id BIGINT DEFAULT NULL COMMENT '关联摊位id,非摊位钱包为NULL';
[ ] Step 2: UserWallet.java 新增 storeId 字段
/** 关联摊位id,非摊位钱包为NULL */
private Long storeId;
[ ] Step 3: UserWalletMapper.xml 更新
在 resultMap 中添加 store_id 映射,在 insert/update/select 中添加 storeId 字段支持。
在 addStall 方法中,创建摊位后自动创建摊位钱包:
// 创建摊位后,自动创建摊位钱包
UserWallet wallet = new UserWallet();
wallet.setStoreId(posStore.getId());
wallet.setPointsWallet(0L);
wallet.setBalanceWallet(BigDecimal.ZERO);
wallet.setBlockedFunds(BigDecimal.ZERO);
userWalletService.insertUserWallet(wallet);
所有通过 user_id 查钱包的地方加上 store_id IS NULL 条件,避免查到摊位钱包。新增通过 store_id 查摊位钱包的方法。
创建摊位后确认摊位钱包自动创建,查询用户钱包不包含摊位钱包。
根据实现过程中确认的细节更新需求文档。
[ ] Step 2: 提交代码
git add -A
git commit -m "feat: 夜市摊位管理功能 — 创建摊位、管理摊位主账号"