# 杭州第一技师学院智慧校园管理系统 - AI 代码生成规范 ## 🎯 项目概述 本项目是基于 RuoYi-Vue-Plus 框架开发的智慧校园管理系统,主要用于学校的学工管理、宿舍管理、班级管理等业务场景。 - **项目名称**: 杭州第一技师学院智慧校园管理系统 - **基础框架**: RuoYi-Vue-Plus 5.4.0 - **前端**: Vue 3 + TypeScript + Element Plus + Vite - **后端**: Spring Boot 3.4.6 + MyBatis-Plus + Sa-Token - **主工程代码路径**: 管理端前端在 **`crm/web/`**,Java 后端在 **`crm/backend/`**,主工程 Python 在 **`crm/py-backend/`**;AI 生成路径说明、文档与脚本中的 `web/`、`backend/` 均指以上目录,勿假定仓库根下仍有同名顶层文件夹。 --- ## ⚠️ AI代码生成核心规则 ### 文档生成规范 - **禁止主动生成MD文档**:在代码生成过程中,除非用户明确要求,否则不要生成任何Markdown文档(.md文件) - **简洁优先原则**:如果必须生成说明文档,内容要极度简洁,只包含关键信息 - **聚焦代码实现**:将精力集中在代码生成和功能实现上,而非文档编写 - **例外情况**:仅在以下情况生成文档 - 用户明确要求生成文档 - 项目README或API文档等必要文件缺失 - 复杂功能需要关键说明(限制在50行以内) --- ## 📦 前端技术栈总结 ### 核心框架与版本 - **Vue**: 3.5.13 (使用 Composition API) - **TypeScript**: 5.8.3 - **Vite**: 6.3.2 - **Element Plus**: 2.9.8 - **Pinia**: 3.0.2 (状态管理) - **Vue Router**: 4.5.0 (路由管理) - **Axios**: 1.8.4 (HTTP请求) ### 关键工具库 - **vxe-table**: 4.13.7 (高级表格组件) - **UnoCSS**: 66.0.0 (原子化CSS框架) - **echarts**: 5.6.0 (数据可视化) - **@vueuse/core**: 13.1.0 (Vue组合式工具集) - **vue-i18n**: 11.1.3 (国际化) - **screenfull**: 6.0.2 (全屏) - **nprogress**: 0.2.0 (进度条) ### 项目结构 ``` crm/web/ ├── src/ │ ├── api/ # API接口定义 │ ├── assets/ # 静态资源 │ ├── components/ # 公共组件 │ ├── directive/ # 自定义指令 │ ├── hooks/ # 组合式函数 │ ├── lang/ # 国际化语言包 │ ├── layout/ # 布局组件 │ ├── plugins/ # 插件配置 │ ├── router/ # 路由配置 │ ├── store/ # Pinia状态管理 │ ├── utils/ # 工具函数 │ ├── views/ # 页面视图 │ └── main.ts # 入口文件 ├── vite/ # Vite插件配置 ├── index.html ├── vite.config.ts └── package.json ``` --- ## 📦 后端技术栈总结 ### 核心框架与版本 - **Spring Boot**: 3.4.6 - **JDK**: 17+ - **MyBatis**: 3.5.16 - **MyBatis-Plus**: 3.5.12 - **Sa-Token**: 1.42.0 (权限认证) - **Hutool**: 5.8.35 (工具库) ### 关键技术组件 - **Redisson**: 3.45.1 (Redis客户端,分布式锁) - **Lock4j**: 2.2.7 (分布式锁) - **dynamic-datasource**: 4.3.1 (动态多数据源) - **p6spy**: 3.9.1 (SQL性能分析) - **FastExcel**: 1.2.0 (Excel导入导出) - **SpringDoc**: 2.8.8 (API文档生成) - **Warm-Flow**: 1.7.3 (国产工作流引擎) - **SnailJob**: 1.5.0 (分布式任务调度) - **AWS S3**: 2.28.22 (对象存储) - **SMS4J**: 3.3.4 (短信发送) - **ip2region**: 2.7.0 (IP地址定位) - **MapStruct-Plus**: 1.5.0 (对象转换) ### 项目结构 ``` crm/backend/ ├── ruoyi-admin/ # 启动模块 ├── ruoyi-common/ # 通用模块 │ ├── ruoyi-common-core/ # 核心工具 │ ├── ruoyi-common-mybatis/ # 数据库配置 │ ├── ruoyi-common-redis/ # Redis配置 │ ├── ruoyi-common-satoken/ # 权限配置 │ ├── ruoyi-common-web/ # Web配置 │ ├── ruoyi-common-excel/ # Excel工具 │ └── ... # 其他通用模块 ├── ruoyi-modules/ # 业务模块 │ ├── ruoyi-system/ # 系统管理 │ ├── ruoyi-job/ # 定时任务 │ ├── ruoyi-workflow/ # 工作流 │ └── ruoyi-xg/ # 学工管理 ⭐ └── ruoyi-extend/ # 扩展模块 ├── ruoyi-monitor-admin/ # 监控中心 └── ruoyi-snailjob-server/# 任务调度服务 ``` --- ## 🎓 学工模块(ruoyi-xg)架构规范 ### 后端模块结构 ``` ruoyi-xg/ └── src/main/java/org/dromara/xg/ ├── controller/ # 控制器层 - RESTful API ├── service/ # 服务层 - 业务逻辑 │ └── impl/ # 服务实现 ├── mapper/ # 数据访问层 - MyBatis接口 ├── domain/ # 数据模型 │ ├── bo/ # Business Object - 业务对象(接收参数) │ └── vo/ # View Object - 视图对象(返回数据) ├── convert/ # 对象转换器 - MapStruct ├── config/ # 配置类 ├── utils/ # 工具类 └── listener/ # 事件监听器 ``` ### 前端模块结构 ``` crm/web/src/ ├── api/xg/ # 学工API接口定义 │ ├── student/ # 学生管理API │ ├── xsjcxx/ # 学生基础信息API │ ├── xgss/ # 学工宿舍API │ ├── studentStatistics.ts # 学生统计API │ └── README.md └── views/xg/ # 学工页面视图 ├── xsjcxx/ # 学生基础信息模块 ├── xgss/ # 学工宿舍模块 ├── studentStatistics/ # 学生统计模块 └── README.md ``` --- ## 🚀 后端开发规范(学工模块) ### 1. Controller 层规范 ```java package org.dromara.xg.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.*; import lombok.RequiredArgsConstructor; import org.dromara.common.core.domain.R; import org.dromara.common.core.validate.AddGroup; import org.dromara.common.core.validate.EditGroup; import org.dromara.common.excel.utils.ExcelUtil; import org.dromara.common.idempotent.annotation.RepeatSubmit; import org.dromara.common.log.annotation.Log; import org.dromara.common.log.enums.BusinessType; import org.dromara.common.mybatis.core.page.*; import org.dromara.common.web.core.BaseController; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; /** * XXX管理控制器 * * @author Your Name * @date 2025-01-XX */ @Validated @RequiredArgsConstructor @RestController @RequestMapping("/xg/模块名") public class XgXxxController extends BaseController { private final IXgXxxService xxxService; /** * 查询列表(分页) */ @SaCheckPermission("xg:xxx:list") @GetMapping("/list") public TableDataInfo list(XgXxxBo bo, PageQuery pageQuery) { return xxxService.queryPageList(bo, pageQuery); } /** * 获取详细信息 */ @SaCheckPermission("xg:xxx:query") @GetMapping("/{id}") public R getInfo(@NotNull(message = "主键不能为空") @PathVariable Long id) { return R.ok(xxxService.queryById(id)); } /** * 新增 */ @SaCheckPermission("xg:xxx:add") @Log(title = "XXX管理", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping() public R add(@Validated(AddGroup.class) @RequestBody XgXxxBo bo) { return toAjax(xxxService.insertByBo(bo)); } /** * 修改 */ @SaCheckPermission("xg:xxx:edit") @Log(title = "XXX管理", businessType = BusinessType.UPDATE) @RepeatSubmit() @PutMapping() public R edit(@Validated(EditGroup.class) @RequestBody XgXxxBo bo) { return toAjax(xxxService.updateByBo(bo)); } /** * 删除 */ @SaCheckPermission("xg:xxx:remove") @Log(title = "XXX管理", businessType = BusinessType.DELETE) @DeleteMapping("/{ids}") public R remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) { return toAjax(xxxService.deleteWithValidByIds(List.of(ids), true)); } /** * 导出 */ @SaCheckPermission("xg:xxx:export") @Log(title = "XXX管理", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(XgXxxBo bo, HttpServletResponse response) { List list = xxxService.queryList(bo); ExcelUtil.exportExcel(list, "XXX数据", XgXxxVo.class, response); } } ``` **关键点:** - 继承 `BaseController` 提供基础工具方法 - 使用 `@RequiredArgsConstructor` 实现构造器注入 - 使用 `@SaCheckPermission` 进行权限控制,格式:`xg:模块:操作` - 使用 `@Log` 记录操作日志 - 使用 `@RepeatSubmit` 防止重复提交 - 使用 `@Validated` 进行参数校验,分组校验使用 AddGroup/EditGroup - 分页查询返回 `TableDataInfo`,其他接口返回 `R` ### 2. Service 层规范 ```java package org.dromara.xg.service; import org.dromara.common.mybatis.core.page.*; import org.dromara.xg.domain.bo.XgXxxBo; import org.dromara.xg.domain.vo.XgXxxVo; import java.util.Collection; import java.util.List; /** * XXX管理Service接口 * * @author Your Name * @date 2025-01-XX */ public interface IXgXxxService { /** * 查询分页列表 */ TableDataInfo queryPageList(XgXxxBo bo, PageQuery pageQuery); /** * 查询列表 */ List queryList(XgXxxBo bo); /** * 根据主键查询 */ XgXxxVo queryById(Long id); /** * 新增 */ Boolean insertByBo(XgXxxBo bo); /** * 修改 */ Boolean updateByBo(XgXxxBo bo); /** * 校验并批量删除 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); } ``` **实现类规范:** ```java package org.dromara.xg.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.RequiredArgsConstructor; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.*; import org.dromara.xg.domain.XgXxx; import org.dromara.xg.domain.bo.XgXxxBo; import org.dromara.xg.domain.vo.XgXxxVo; import org.dromara.xg.mapper.XgXxxMapper; import org.dromara.xg.service.IXgXxxService; import org.springframework.stereotype.Service; import java.util.Collection; import java.util.List; /** * XXX管理Service实现 * * @author Your Name * @date 2025-01-XX */ @RequiredArgsConstructor @Service public class XgXxxServiceImpl implements IXgXxxService { private final XgXxxMapper baseMapper; /** * 构建查询条件 */ private LambdaQueryWrapper buildQueryWrapper(XgXxxBo bo) { LambdaQueryWrapper lqw = Wrappers.lambdaQueryWrapper(); lqw.like(StringUtils.isNotBlank(bo.getName()), XgXxx::getName, bo.getName()); lqw.eq(bo.getStatus() != null, XgXxx::getStatus, bo.getStatus()); lqw.between(bo.getBeginTime() != null && bo.getEndTime() != null, XgXxx::getCreateTime, bo.getBeginTime(), bo.getEndTime()); lqw.orderByDesc(XgXxx::getCreateTime); return lqw; } @Override public TableDataInfo queryPageList(XgXxxBo bo, PageQuery pageQuery) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); return TableDataInfo.build(result); } @Override public List queryList(XgXxxBo bo) { LambdaQueryWrapper lqw = buildQueryWrapper(bo); return baseMapper.selectVoList(lqw); } @Override public XgXxxVo queryById(Long id) { return baseMapper.selectVoById(id); } @Override public Boolean insertByBo(XgXxxBo bo) { XgXxx entity = MapstructUtils.convert(bo, XgXxx.class); boolean flag = baseMapper.insert(entity) > 0; if (flag) { bo.setId(entity.getId()); } return flag; } @Override public Boolean updateByBo(XgXxxBo bo) { XgXxx entity = MapstructUtils.convert(bo, XgXxx.class); return baseMapper.updateById(entity) > 0; } @Override public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { if (isValid) { // 做删除前的业务校验 } return baseMapper.deleteByIds(ids) > 0; } } ``` **关键点:** - 使用 `@RequiredArgsConstructor` 注入 Mapper - 使用 MyBatis-Plus 的 LambdaQueryWrapper 构建查询条件 - 使用 `MapstructUtils.convert` 进行对象转换 - 使用 `selectVoPage` 和 `selectVoList` 直接查询VO对象 ### 3. Domain 层规范 **Entity(实体类):** ```java package org.dromara.xg.domain; import com.baomidou.mybatisplus.annotation.*; import lombok.Data; import lombok.EqualsAndHashCode; import org.dromara.common.tenant.core.TenantEntity; import java.io.Serial; import java.time.LocalDateTime; /** * XXX实体对象 xg_xxx * * @author Your Name * @date 2025-01-XX */ @Data @EqualsAndHashCode(callSuper = true) @TableName("xg_xxx") public class XgXxx extends TenantEntity { @Serial private static final long serialVersionUID = 1L; /** * 主键ID */ @TableId(value = "id", type = IdType.ASSIGN_ID) private Long id; /** * 名称 */ private String name; /** * 状态 */ private String status; /** * 备注 */ private String remark; /** * 逻辑删除标志(0存在 1删除) */ @TableLogic private Integer delFlag; } ``` **BO(业务对象 - 接收前端参数):** ```java package org.dromara.xg.domain.bo; import io.github.linpeilie.annotations.AutoMapper; import jakarta.validation.constraints.*; import lombok.Data; import lombok.EqualsAndHashCode; import org.dromara.common.core.validate.AddGroup; import org.dromara.common.core.validate.EditGroup; import org.dromara.common.mybatis.core.domain.BaseEntity; import org.dromara.xg.domain.XgXxx; /** * XXX业务对象 xg_xxx * * @author Your Name * @date 2025-01-XX */ @Data @EqualsAndHashCode(callSuper = true) @AutoMapper(target = XgXxx.class, reverseConvertGenerate = false) public class XgXxxBo extends BaseEntity { /** * 主键ID */ @NotNull(message = "主键不能为空", groups = { EditGroup.class }) private Long id; /** * 名称 */ @NotBlank(message = "名称不能为空", groups = { AddGroup.class, EditGroup.class }) private String name; /** * 状态 */ private String status; /** * 备注 */ private String remark; } ``` **VO(视图对象 - 返回给前端):** ```java package org.dromara.xg.domain.vo; import com.alibaba.excel.annotation.ExcelProperty; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; import org.dromara.common.excel.annotation.ExcelDictFormat; import org.dromara.common.excel.convert.ExcelDictConvert; import org.dromara.xg.domain.XgXxx; import java.io.Serial; import java.io.Serializable; import java.time.LocalDateTime; /** * XXX视图对象 xg_xxx * * @author Your Name * @date 2025-01-XX */ @Data @AutoMapper(target = XgXxx.class) public class XgXxxVo implements Serializable { @Serial private static final long serialVersionUID = 1L; /** * 主键ID */ @ExcelProperty(value = "ID") private Long id; /** * 名称 */ @ExcelProperty(value = "名称") private String name; /** * 状态 */ @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) @ExcelDictFormat(dictType = "sys_normal_disable") private String status; /** * 备注 */ @ExcelProperty(value = "备注") private String remark; /** * 创建时间 */ @ExcelProperty(value = "创建时间") private LocalDateTime createTime; } ``` ### 4. Mapper 层规范 ```java package org.dromara.xg.mapper; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.xg.domain.XgXxx; import org.dromara.xg.domain.vo.XgXxxVo; /** * XXX管理Mapper接口 * * @author Your Name * @date 2025-01-XX */ public interface XgXxxMapper extends BaseMapperPlus { // 自定义SQL方法在这里定义 } ``` **对应的 XML(如需自定义SQL):** ```xml ``` --- ## 🎨 前端开发规范(学工模块) ### 1. API 接口定义规范 ```typescript // crm/web/src/api/xg/xxx.ts import request from '@/utils/request' /** * 查询参数接口 */ export interface XxxQuery { pageNum?: number pageSize?: number name?: string status?: string beginTime?: string endTime?: string } /** * 表单数据接口 */ export interface XxxForm { id?: number name: string status: string remark?: string } /** * 视图对象接口 */ export interface XxxVO { id: number name: string status: string remark?: string createTime: string updateTime: string } /** * 查询列表 */ export function listXxx(query: XxxQuery) { return request({ url: '/xg/xxx/list', method: 'get', params: query }) } /** * 查询详细 */ export function getXxx(id: number) { return request({ url: `/xg/xxx/${id}`, method: 'get' }) } /** * 新增 */ export function addXxx(data: XxxForm) { return request({ url: '/xg/xxx', method: 'post', data: data }) } /** * 修改 */ export function updateXxx(data: XxxForm) { return request({ url: '/xg/xxx', method: 'put', data: data }) } /** * 删除 */ export function delXxx(ids: number | number[]) { return request({ url: `/xg/xxx/${ids}`, method: 'delete' }) } /** * 导出 */ export function exportXxx(query: XxxQuery) { return request({ url: '/xg/xxx/export', method: 'post', data: query, responseType: 'blob' }) } ``` **关键点:** - 接口定义使用 TypeScript interface - Query 参数用于列表查询(GET请求的params) - Form 用于新增/修改(POST/PUT请求的data) - VO 用于展示数据 - 导出接口需要设置 `responseType: 'blob'` ### 2. 列表页面规范 ```vue ``` **关键点:** - 使用 ` ``` --- ## 📝 开发流程指南 ### 1. 新建学工功能模块完整流程 #### 后端开发步骤: 1. **创建数据库表**(表名格式:`xg_模块名`) 2. **创建 Entity 实体类**(`domain/XgXxx.java`) 3. **创建 VO 视图对象**(`domain/vo/XgXxxVo.java`) 4. **创建 BO 业务对象**(`domain/bo/XgXxxBo.java`) 5. **创建 Mapper 接口**(`mapper/XgXxxMapper.java`) 6. **创建 Mapper XML**(`resources/mapper/xg/XgXxxMapper.xml`,如需自定义SQL) 7. **创建 Service 接口**(`service/IXgXxxService.java`) 8. **创建 Service 实现**(`service/impl/XgXxxServiceImpl.java`) 9. **创建 Controller 控制器**(`controller/XgXxxController.java`) 10. **在菜单管理中配置菜单和权限** #### 前端开发步骤: 1. **创建 API 接口文件**(`api/xg/xxx.ts`) 2. **创建页面文件**(`views/xg/xxx/index.vue`) 3. **配置路由**(通过后端菜单管理配置,前端动态加载) 4. **测试功能** ### 2. 使用代码生成器(推荐) 框架提供了强大的代码生成器,可以一键生成所有代码: 1. 登录系统,进入 **系统工具 -> 代码生成** 2. 点击 **导入表**,选择要生成的数据库表 3. 点击 **编辑**,配置生成信息: - 基本信息:包名、模块名、作者等 - 字段信息:字段类型、显示类型、是否必填等 - 生成信息:生成模板、前端路径等 4. 点击 **生成代码**,下载代码包 5. 将生成的代码解压到对应目录 6. 重启后端服务,刷新前端页面 --- ## 🎯 学工模块常见业务场景 ### 1. 学生信息管理 - **表命名**: `xg_student`, `xg_student_msg` - **权限前缀**: `xg:student` - **API路径**: `/xg/student` - **页面路径**: `views/xg/xsjcxx`(学生基础信息) ### 2. 宿舍管理 - **表命名**: `xg_dorm_*`(校区、楼栋、房间、床位等) - **权限前缀**: `xg:dorm` - **API路径**: `/xg/dorm` - **页面路径**: `views/xg/xgss`(学工宿舍) ### 3. 班级管理 - **表命名**: `xg_class_*` - **权限前缀**: `xg:class` - **API路径**: `/xg/class` - **页面路径**: `views/xg/class` ### 4. 统计分析 - **表命名**: 可直接查询其他表统计 - **权限前缀**: `xg:statistics` - **API路径**: `/xg/statistics` 或 `/xg/studentStatistics` - **页面路径**: `views/xg/studentStatistics` --- ## 🔧 常用工具类和方法 ### 后端常用工具 **字符串工具 - StringUtils** ```java import org.dromara.common.core.utils.StringUtils; StringUtils.isNotBlank(str) // 判断字符串不为空 StringUtils.isBlank(str) // 判断字符串为空 StringUtils.isEmpty(str) // 判断字符串是否为null或空串 ``` **对象转换 - MapstructUtils** ```java import org.dromara.common.core.utils.MapstructUtils; // BO 转 Entity XgStudent entity = MapstructUtils.convert(bo, XgStudent.class); // Entity 转 VO XgStudentVo vo = MapstructUtils.convert(entity, XgStudentVo.class); // List 转换 List voList = MapstructUtils.convert(entityList, XgStudentVo.class); ``` **日期工具 - DateUtils** ```java import org.dromara.common.core.utils.DateUtils; DateUtils.parseDate(str) // 解析日期字符串 DateUtils.parseDateToStr(date) // 日期转字符串 DateUtils.getNowDate() // 获取当前日期 ``` **Excel导出 - ExcelUtil** ```java import org.dromara.common.excel.utils.ExcelUtil; ExcelUtil.exportExcel(list, "标题", XgXxxVo.class, response); ``` ### 前端常用工具 **日期格式化** ```typescript import { parseTime } from '@/utils/ruoyi' parseTime(new Date()) // 格式化日期时间 parseTime(date, '{y}-{m}-{d}') // 自定义格式 ``` **权限判断** ```typescript import { hasPermi, hasRole } from '@/utils/permission' hasPermi(['xg:student:edit']) // 判断是否有权限 hasRole(['admin']) // 判断是否有角色 ``` **字典标签** ```vue ``` **文件下载** ```typescript proxy?.$download('api/url', params, 'filename.xlsx') ``` --- ## 🚨 注意事项 ### 后端开发注意事项 1. **权限注解必须添加**:所有 Controller 方法都必须添加 `@SaCheckPermission` 注解 2. **操作日志记录**:重要操作(增删改)必须添加 `@Log` 注解 3. **防重复提交**:新增/修改操作建议添加 `@RepeatSubmit` 注解 4. **参数校验**:使用 `@Validated` 和校验注解(@NotNull、@NotBlank等) 5. **事务管理**:涉及多表操作的 Service 方法要添加 `@Transactional` 注解 6. **逻辑删除**:删除操作优先使用逻辑删除(delFlag字段) 7. **租户隔离**:继承 `TenantEntity` 实现多租户数据隔离 8. **SQL注入防护**:使用 MyBatis-Plus 的 Wrapper 构建查询条件,避免字符串拼接 ### 前端开发注意事项 1. **权限控制**:所有操作按钮必须添加 `v-hasPermi` 指令 2. **表单校验**:表单提交前必须进行前端校验 3. **加载状态**:异步操作要显示 loading 状态 4. **错误处理**:API 调用要用 try-catch 捕获异常 5. **代码规范**:使用 TypeScript,定义好接口类型 6. **组件复用**:相同功能的组件要抽取为公共组件 7. **国际化**:涉及到文本的地方考虑国际化支持 8. **响应式布局**:页面要考虑不同屏幕尺寸的适配 --- ## 🎨 Web UI 强制规范(bx/bx-web,Fresh Mint 对齐) > 本节用于 `bx/bx-web` 前端界面改造与新页面开发,视觉与交互以 `bx/docs/web-admin-ui-spec-fresh-mint.md` 为唯一权威;如与历史样式冲突,以本节和规范文档为准。 ### 1. 视觉 Token 与基础参数(强制) - 主色与语义色:`--primary: #10b981`、`--primary-dark: #059669`、`--primary-bg: #ecfdf5`、`--text: #1e293b`、`--text-muted: #64748b`、`--border: #d9e8e2`、`--table-head: #f8fafc` - 正文:`font-size: 14px`、`line-height: 1.5` - 圆角:面板/大弹窗 `10px`,按钮/输入 `8px`,行内操作按钮 `6px` - 卡片阴影:`0 1px 3px rgba(0,0,0,0.05)` ### 2. 页面骨架与列表区(强制) - 统一结构:`page-head -> panel -> filter-block -> list-toolbar -> list-body/list-wrap -> pagination(list-pager-bar)` - 列表工具栏:仅第一个主动作使用主色实心按钮,其余使用中性描边 - 操作列必须 `fixed="right"`,并设置足够宽度,禁止按钮换行/截断 - 分页条必须与表格同容器,`margin-top: 0`,顶部单分割线,禁止脱节 ### 3. 筛选区规则(强制) - 使用网格筛选:默认 4 列,<=1100px 2 列,<=560px 1 列 - 筛选 label:11px,次级色;控件高度统一 36px - “更多筛选”展开区与操作行之间只用间距,不加横向分割线 - 查询/重置/展开更多按钮必须带 loading 状态(与请求态一致) ### 4. 弹窗与详情查看(强制) - 详情弹窗优先采用:`hero(标题+状态+摘要) + section 分块 + kv 网格` - 详情信息区统一两列键值布局,自适应降为单列;禁止同页混用无规则单列/三列 - 审批流区域统一 `max-height + overflow-y:auto` - 查看弹窗底部仅保留“关闭/返回”类动作,不混入提交语义按钮 - 长文本默认使用“最多 3 行 + 展开/收起”组件,避免拉长弹窗 ### 5. 表格型详情区块(强制) - 诸如“冲抵记录/冲抵明细/流水”等区块必须复用统一组件(标题+表格+空态) - 空数据必须展示统一空态,不允许直接隐藏整个区块导致信息断层 ### 6. 表单弹窗规则(强制) - 新增/编辑弹窗默认两列表单(`label-position="top"`),长文本字段跨整行 - footer 按钮统一:取消(中性)/确定(主色),图标与文字间距 6px - 长表单校验失败时需滚动定位到首个错误项(平滑滚动) ### 7. 交互与可访问性(强制) - 图片预览、下载、附件区块需统一行为与样式,不得各页自定义分叉 - 关键按钮与分页切换必须可键盘访问,焦点态清晰可见 - 颜色语义统一:success=已完成,warning=待处理,danger=异常,info=中性 ### 8. 改造执行与验收(强制) - 改造顺序:Token -> 骨架 -> 组件(筛选/按钮/表格/弹窗)-> 页面微调 - 每次 UI 改造必须至少覆盖:字号、间距、边框、按钮层级、断点自适应 - 禁止“只改局部页面样式不抽共用组件”;重复结构优先组件化 ## 📱 BX Mobile UI 强制规范(bx/bx-mobile,Fresh Mint 对齐) > 本节用于 `bx/bx-mobile`(Vant 4 + Vue 3)移动端页面开发与改造。视觉与交互以移动端规范文档 `bx/docs/mobile-ui-spec-fresh-mint.md` 为权威,如与历史页面冲突,以本节和移动端规范文档为准。 ### 1. 设计 Token 与主题映射(强制) - 统一使用 `src/styles/index.css` 中 token,不允许页面内硬编码主色(`#00c98d`、`#10b981` 等)覆盖全局语义。 - 颜色语义固定:`success=通过/完成`、`warning=待处理`、`danger=异常/驳回`、`info=进行中`、`muted=草稿/中性`。 - Vant 主题色必须对齐 token:`van-button--primary`、`van-tabs__line`、`van-tabbar-item--active`、`van-nav-bar` 等保持统一薄荷主色链。 ### 2. 页面骨架与安全区(强制) - 页面容器统一使用 `.page` 或同等结构,遵循 `padding: 12px 16px 80px` 的内容节奏。 - 底部操作区/底栏必须包含 `env(safe-area-inset-bottom)`,避免 iPhone 刘海屏/底部手势区遮挡。 - 全宽组件(`van-nav-bar`、`van-search`、`van-tabs`、`van-pull-refresh`)按全局样式贴边,不在业务页重复写负 margin。 ### 3. 卡片与列表规范(强制) - 业务列表统一卡片化:白底、`12px` 圆角、`1px` 边框、轻阴影,信息密度优先“标题 + 状态 + 金额 + 时间”。 - 可点击卡片必须有按下反馈(缩放或底色变化),状态条/左侧强调线使用语义色,不得随页面自定义颜色体系。 - 卡片内操作按钮遵循“首要操作主色,其余中性/危险”规则;异步按钮必须有 loading 与禁用态。 ### 4. 表单与交互反馈(强制) - 输入控件默认高度 42-46px,`label` 在上、输入在下;错误态必须有红色边框和明确文案。 - 登录/提交类按钮必须防重复点击(loading + disabled);失败反馈优先“字段错误态 + toast”组合。 - 密码框、树形选择、费用项联动等交互组件需支持“可逆操作”(清空、收起、回退)与状态回显。 ### 5. 首页与导航入口(强制) - 首页使用“欢迎区 + 菜单卡片 + 待办区”三级层次,禁止菜单入口直接堆叠为无分组长列表。 - 菜单宫格支持消息红点、待办计数,红点只用于需要用户处理的业务入口。 - 顶部欢迎区可包含汇总数据(如本月金额、审批进度),强调信息不超过 2-3 个,避免视觉噪音。 ### 6. 弹层与底部 Sheet(强制) - 底部选择器(如一级/二级费用项)统一使用 bottom sheet:遮罩 + 顶部标题栏 + 主体双栏 + 底部确认动作。 - 选择器必须支持关键词检索和已选路径回显;确认按钮在未完成选择时禁用。 - 弹层圆角、阴影、遮罩透明度与全局保持一致,禁止页面私有“另一个风格”的弹层。 ### 7. 移动端验收清单(强制) - 至少覆盖:配色统一、卡片层级、按钮 loading、错误态、安全区、窄屏可读性。 - 真机验收至少覆盖 iOS/Android 各 1 台(或对应模拟器),重点检查底部操作栏、输入焦点和滚动穿透。 - 新增页面时优先复用已有公共样式/结构(`card`、`status-tag`、`apply-list-item`、`bottom-action-bar`),避免重复造样式。 ### 学工模块特殊注意 1. **学生隐私保护**:身份证号、手机号等敏感信息需要脱敏处理 2. **数据权限控制**:根据用户角色(辅导员、班主任等)限制数据访问范围 3. **批量操作优化**:大量学生数据的批量导入/导出要考虑性能优化 4. **工作流集成**:涉及审批流程的功能需要集成工作流引擎 5. **数据统计性能**:统计分析功能要注意查询性能,必要时使用缓存 --- ## 📚 参考资源 ### 官方文档 - **RuoYi-Vue-Plus 文档**: https://plus-doc.dromara.org - **Vue 3 文档**: https://cn.vuejs.org - **Element Plus 文档**: https://element-plus.org/zh-CN - **MyBatis-Plus 文档**: https://baomidou.com - **Sa-Token 文档**: https://sa-token.cc ### 框架特色功能文档 - **多租户**: https://plus-doc.dromara.org/#/ruoyi-vue-plus/framework/tenant - **数据权限**: https://plus-doc.dromara.org/#/ruoyi-vue-plus/framework/data_permission - **数据脱敏**: https://plus-doc.dromara.org/#/ruoyi-vue-plus/framework/sensitive - **工作流**: https://plus-doc.dromara.org/#/ruoyi-vue-plus/framework/workflow - **代码生成器**: https://plus-doc.dromara.org/#/ruoyi-vue-plus/other/generator --- ## 🎓 总结 遵循本规范文件,AI可以: 1. **理解项目整体架构**:前后端分离、模块化设计 2. **快速生成标准代码**:Controller、Service、Mapper、Vue页面等 3. **保持代码风格统一**:命名规范、注解使用、权限控制等 4. **处理学工业务场景**:学生管理、宿舍管理、统计分析等 5. **避免常见错误**:权限遗漏、参数校验缺失、SQL注入等 **开发原则**: - ✅ 代码规范统一 - ✅ 安全性优先 - ✅ 性能优化考虑 - ✅ 用户体验良好 - ✅ 可维护性强 **生成代码时的核心要求**: 1. 严格遵循本文档的命名规范和代码结构 2. 必须包含完整的权限控制和参数校验 3. 前后端接口定义要保持一致 4. 注释要清晰完整 5. 考虑学工业务的特殊性(隐私保护、数据权限等)