| | |
| | | |
| | | | 模块 | 目录 | 说明 | 端口 | |
| | | | --- | --- | --- | --- | |
| | | | 网关 | `ruoyi-gateway` | 统一入口、路由转发、鉴权与限流 | 8080 | |
| | | | 网关 | `ruoyi-gateway` | 统一入口、路由转发、鉴权与限流 | 8085 | |
| | | | 认证服务 | `ruoyi-auth` | 登录、注册、令牌签发 | 9200 | |
| | | | 系统服务 | `ruoyi-modules/ruoyi-system` | 用户 / 角色 / 菜单 / 部门 / 字典 / 日志等 | 9201 | |
| | | | 代码生成 | `ruoyi-modules/ruoyi-gen` | 前后端代码一键生成 | 9202 | |
| | | | 定时任务 | `ruoyi-modules/ruoyi-job` | Quartz 任务调度 | 9203 | |
| | | | 用户服务 | `ruoyi-modules/ruoyi-user` | C 端会员用户(`account_user`,网关前缀 `/account`) | 9210 | |
| | | | 文件服务 | `ruoyi-modules/ruoyi-file` | 本地 / MinIO 文件上传下载 | 9300 | |
| | | | 监控服务 | `ruoyi-visual/ruoyi-monitor` | Spring Boot Admin 服务监控 | 9100 | |
| | | |
| | |
| | | |
| | | - `docker/`:Nacos、MySQL、Redis、Nginx 及各服务的容器化配置,编排文件为 `docker/docker-compose.yml` |
| | | - `docker/deploy.sh`、`docker/copy.sh`:一键部署与拷贝脚本 |
| | | - `bin/`:各服务的本地启动脚本(`run-gateway.bat`、`run-auth.bat`、`run-modules-*.bat`、`run-monitor.bat`) |
| | | - `bin/`:本地启动脚本 |
| | | - `start-all.bat`、`stop-all.bat`:一键启动/停止 Nacos、Redis 与全部服务(Windows) |
| | | - `run-gateway.bat`、`run-auth.bat`、`run-modules-*.bat`、`run-monitor.bat`:单服务前台启动 |
| | | - `sql/`:初始化脚本 |
| | | - `ry_20260417.sql`:业务库(`ry-cloud`) |
| | | - `ry_config_20260918.sql`:Nacos 配置库 |
| | | - `hugray_account_20261009.sql`:会员库 `hugray-account` 的 `account_user` 表 |
| | | - `hugray_menu_account_20261009.sql`:用户服务菜单(`hugray` 库 `sys_menu`) |
| | | - `quartz.sql`:定时任务表 |
| | | - `ry_seata_20210128.sql`:Seata 事务表 |
| | | |
| | |
| | | ruoyi-gateway → ruoyi-auth → ruoyi-modules/ruoyi-system → ... → ruoyi-visual/ruoyi-monitor |
| | | ``` |
| | | |
| | | Windows 下可直接双击 `hugray-server/bin/start-all.bat`:脚本会自动拉起 Nacos、Redis,再依次启动全部 8 个服务并等待网关就绪;端口已被占用的服务自动跳过,因此可重复执行。停止用 `stop-all.bat`(Redis 作为常驻中间件不在此列)。两者的路径配置都在文件顶部的「配置区」,换机器时改那里即可。 |
| | | |
| | | ### 4. 启动管理后台前端 |
| | | |
| | | ```bash |
| | |
| | | | 服务 | 端口 | |
| | | | --- | --- | |
| | | | 管理后台前端(开发) | 80 | |
| | | | 网关 ruoyi-gateway | 8080 | |
| | | | 网关 ruoyi-gateway | 8085 | |
| | | | 认证 ruoyi-auth | 9200 | |
| | | | 系统 ruoyi-system | 9201 | |
| | | | 代码生成 ruoyi-gen | 9202 | |
| | | | 定时任务 ruoyi-job | 9203 | |
| | | | 用户服务 ruoyi-user | 9210 | |
| | | | 文件服务 ruoyi-file | 9300 | |
| | | | 监控 ruoyi-monitor | 9100 | |
| | | | Nacos | 8848 / 9848 / 9849 | |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 注意:本前端对接的是 hugray-server 微服务网关,路径必须带云网关前缀 |
| | | // (校验码由网关自身提供 /code,认证走 /auth/**,用户与菜单走 /system/**), |
| | | // 不能使用 RuoYi 单体版的 /login、/getInfo、/getRouters 等写法。 |
| | | |
| | | // 登录方法 |
| | | export function login(username, password, code, uuid) { |
| | | const data = { |
| | |
| | | uuid |
| | | } |
| | | return request({ |
| | | url: '/login', |
| | | url: '/auth/login', |
| | | headers: { |
| | | isToken: false, |
| | | repeatSubmit: false |
| | |
| | | // 注册方法 |
| | | export function register(data) { |
| | | return request({ |
| | | url: '/register', |
| | | url: '/auth/register', |
| | | headers: { |
| | | isToken: false |
| | | }, |
| | |
| | | // 获取用户详细信息 |
| | | export function getInfo() { |
| | | return request({ |
| | | url: '/getInfo', |
| | | url: '/system/user/getInfo', |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | // 解锁屏幕 |
| | | export function unlockScreen(password) { |
| | | return request({ |
| | | url: '/unlockscreen', |
| | | url: '/auth/unlockscreen', |
| | | method: 'post', |
| | | data: { password } |
| | | }) |
| | |
| | | // 退出方法 |
| | | export function logout() { |
| | | return request({ |
| | | url: '/logout', |
| | | method: 'post' |
| | | url: '/auth/logout', |
| | | method: 'delete' |
| | | }) |
| | | } |
| | | |
| | | // 获取验证码 |
| | | export function getCodeImg() { |
| | | return request({ |
| | | url: '/captchaImage', |
| | | url: '/code', |
| | | headers: { |
| | | isToken: false |
| | | }, |
| | |
| | | // 获取路由 |
| | | export const getRouters = () => { |
| | | return request({ |
| | | url: '/getRouters', |
| | | url: '/system/menu/getRouters', |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 注意:本前端对接 hugray-server 云网关,路径与 RuoYi 单体版不同。 |
| | | // 查询定时任务调度列表 |
| | | export function listJob(query) { |
| | | return request({ |
| | | url: '/monitor/job/list', |
| | | url: '/schedule/job/list', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | |
| | | // 查询定时任务调度详细 |
| | | export function getJob(jobId) { |
| | | return request({ |
| | | url: '/monitor/job/' + jobId, |
| | | url: '/schedule/job/' + jobId, |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | // 新增定时任务调度 |
| | | export function addJob(data) { |
| | | return request({ |
| | | url: '/monitor/job', |
| | | url: '/schedule/job', |
| | | method: 'post', |
| | | data: data |
| | | }) |
| | |
| | | // 修改定时任务调度 |
| | | export function updateJob(data) { |
| | | return request({ |
| | | url: '/monitor/job', |
| | | url: '/schedule/job', |
| | | method: 'put', |
| | | data: data |
| | | }) |
| | |
| | | // 删除定时任务调度 |
| | | export function delJob(jobId) { |
| | | return request({ |
| | | url: '/monitor/job/' + jobId, |
| | | url: '/schedule/job/' + jobId, |
| | | method: 'delete' |
| | | }) |
| | | } |
| | |
| | | status |
| | | } |
| | | return request({ |
| | | url: '/monitor/job/changeStatus', |
| | | url: '/schedule/job/changeStatus', |
| | | method: 'put', |
| | | data: data |
| | | }) |
| | |
| | | jobGroup |
| | | } |
| | | return request({ |
| | | url: '/monitor/job/run', |
| | | url: '/schedule/job/run', |
| | | method: 'put', |
| | | data: data |
| | | }) |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 注意:本前端对接 hugray-server 云网关,路径与 RuoYi 单体版不同。 |
| | | // 查询调度日志列表 |
| | | export function listJobLog(query) { |
| | | return request({ |
| | | url: '/monitor/jobLog/list', |
| | | url: '/schedule/job/log/list', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | |
| | | // 删除调度日志 |
| | | export function delJobLog(jobLogId) { |
| | | return request({ |
| | | url: '/monitor/jobLog/' + jobLogId, |
| | | url: '/schedule/job/log/' + jobLogId, |
| | | method: 'delete' |
| | | }) |
| | | } |
| | |
| | | // 清空调度日志 |
| | | export function cleanJobLog() { |
| | | return request({ |
| | | url: '/monitor/jobLog/clean', |
| | | url: '/schedule/job/log/clean', |
| | | method: 'delete' |
| | | }) |
| | | } |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 注意:本前端对接 hugray-server 云网关,路径与 RuoYi 单体版不同。 |
| | | // 查询登录日志列表 |
| | | export function list(query) { |
| | | return request({ |
| | | url: '/monitor/logininfor/list', |
| | | url: '/system/logininfor/list', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | |
| | | // 删除登录日志 |
| | | export function delLogininfor(infoId) { |
| | | return request({ |
| | | url: '/monitor/logininfor/' + infoId, |
| | | url: '/system/logininfor/' + infoId, |
| | | method: 'delete' |
| | | }) |
| | | } |
| | |
| | | // 解锁用户登录状态 |
| | | export function unlockLogininfor(userName) { |
| | | return request({ |
| | | url: '/monitor/logininfor/unlock/' + userName, |
| | | url: '/system/logininfor/unlock/' + userName, |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | // 清空登录日志 |
| | | export function cleanLogininfor() { |
| | | return request({ |
| | | url: '/monitor/logininfor/clean', |
| | | url: '/system/logininfor/clean', |
| | | method: 'delete' |
| | | }) |
| | | } |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 注意:本前端对接 hugray-server 云网关,路径与 RuoYi 单体版不同。 |
| | | // 查询在线用户列表 |
| | | export function list(query) { |
| | | return request({ |
| | | url: '/monitor/online/list', |
| | | url: '/system/online/list', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | |
| | | // 强退用户 |
| | | export function forceLogout(tokenId) { |
| | | return request({ |
| | | url: '/monitor/online/' + tokenId, |
| | | url: '/system/online/' + tokenId, |
| | | method: 'delete' |
| | | }) |
| | | } |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 注意:本前端对接 hugray-server 云网关,路径与 RuoYi 单体版不同。 |
| | | // 查询操作日志列表 |
| | | export function list(query) { |
| | | return request({ |
| | | url: '/monitor/operlog/list', |
| | | url: '/system/operlog/list', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | |
| | | // 删除操作日志 |
| | | export function delOperlog(operId) { |
| | | return request({ |
| | | url: '/monitor/operlog/' + operId, |
| | | url: '/system/operlog/' + operId, |
| | | method: 'delete' |
| | | }) |
| | | } |
| | |
| | | // 清空操作日志 |
| | | export function cleanOperlog() { |
| | | return request({ |
| | | url: '/monitor/operlog/clean', |
| | | url: '/system/operlog/clean', |
| | | method: 'delete' |
| | | }) |
| | | } |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 注意:本前端对接 hugray-server 云网关,路径与 RuoYi 单体版不同。 |
| | | // 查询生成表数据 |
| | | export function listTable(query) { |
| | | return request({ |
| | | url: '/tool/gen/list', |
| | | url: '/code/gen/list', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | |
| | | // 查询db数据库列表 |
| | | export function listDbTable(query) { |
| | | return request({ |
| | | url: '/tool/gen/db/list', |
| | | url: '/code/gen/db/list', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | |
| | | // 查询表详细信息 |
| | | export function getGenTable(tableId) { |
| | | return request({ |
| | | url: '/tool/gen/' + tableId, |
| | | url: '/code/gen/' + tableId, |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | // 修改代码生成信息 |
| | | export function updateGenTable(data) { |
| | | return request({ |
| | | url: '/tool/gen', |
| | | url: '/code/gen', |
| | | method: 'put', |
| | | data: data |
| | | }) |
| | |
| | | // 导入表 |
| | | export function importTable(data) { |
| | | return request({ |
| | | url: '/tool/gen/importTable', |
| | | url: '/code/gen/importTable', |
| | | method: 'post', |
| | | params: data |
| | | }) |
| | |
| | | // 创建表 |
| | | export function createTable(data) { |
| | | return request({ |
| | | url: '/tool/gen/createTable', |
| | | url: '/code/gen/createTable', |
| | | method: 'post', |
| | | params: data |
| | | }) |
| | |
| | | // 预览生成代码 |
| | | export function previewTable(tableId) { |
| | | return request({ |
| | | url: '/tool/gen/preview/' + tableId, |
| | | url: '/code/gen/preview/' + tableId, |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | // 删除表数据 |
| | | export function delTable(tableId) { |
| | | return request({ |
| | | url: '/tool/gen/' + tableId, |
| | | url: '/code/gen/' + tableId, |
| | | method: 'delete' |
| | | }) |
| | | } |
| | |
| | | // 生成代码(自定义路径) |
| | | export function genCode(tableName) { |
| | | return request({ |
| | | url: '/tool/gen/genCode/' + tableName, |
| | | url: '/code/gen/genCode/' + tableName, |
| | | method: 'get' |
| | | }) |
| | | } |
| | |
| | | // 同步数据库 |
| | | export function synchDb(tableName) { |
| | | return request({ |
| | | url: '/tool/gen/synchDb/' + tableName, |
| | | url: '/code/gen/synchDb/' + tableName, |
| | | method: 'get' |
| | | }) |
| | | } |
| New file |
| | |
| | | import request from '@/utils/request' |
| | | |
| | | // 注意:本前端对接的是 hugray-server 云网关,会员服务挂在 /account 前缀下 |
| | | // (网关 StripPrefix=1 剥掉 /account 后落到 ruoyi-user 服务的 /user/**), |
| | | // 不能照抄 RuoYi 单体版的写法。 |
| | | |
| | | // 查询会员列表 |
| | | export function listUser(query) { |
| | | return request({ |
| | | url: '/account/user/list', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | | } |
| | | |
| | | // 查询会员详细 |
| | | export function getUser(userId) { |
| | | return request({ |
| | | url: '/account/user/' + userId, |
| | | method: 'get' |
| | | }) |
| | | } |
| | | |
| | | // 新增会员 |
| | | export function addUser(data) { |
| | | return request({ |
| | | url: '/account/user', |
| | | method: 'post', |
| | | data: data |
| | | }) |
| | | } |
| | | |
| | | // 修改会员 |
| | | export function updateUser(data) { |
| | | return request({ |
| | | url: '/account/user', |
| | | method: 'put', |
| | | data: data |
| | | }) |
| | | } |
| | | |
| | | // 删除会员 |
| | | export function delUser(userId) { |
| | | return request({ |
| | | url: '/account/user/' + userId, |
| | | method: 'delete' |
| | | }) |
| | | } |
| | |
| | | const uuid = userInfo.uuid |
| | | return new Promise((resolve, reject) => { |
| | | login(username, password, code, uuid).then(res => { |
| | | setToken(res.token) |
| | | this.token = res.token |
| | | setToken(res.data.access_token) |
| | | this.token = res.data.access_token |
| | | useLockStore().unlockScreen() |
| | | resolve() |
| | | }).catch(error => { |
| New file |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch"> |
| | | <el-form-item label="用户名" prop="userName"> |
| | | <el-input |
| | | v-model="queryParams.userName" |
| | | placeholder="请输入用户名" |
| | | clearable |
| | | style="width: 200px" |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="手机号" prop="phone"> |
| | | <el-input |
| | | v-model="queryParams.phone" |
| | | placeholder="请输入手机号" |
| | | clearable |
| | | style="width: 200px" |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="昵称" prop="nickname"> |
| | | <el-input |
| | | v-model="queryParams.nickname" |
| | | placeholder="请输入昵称" |
| | | clearable |
| | | style="width: 200px" |
| | | @keyup.enter="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="状态" prop="status"> |
| | | <el-select v-model="queryParams.status" placeholder="会员状态" clearable style="width: 200px"> |
| | | <el-option |
| | | v-for="dict in sys_normal_disable" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="创建时间" style="width: 308px"> |
| | | <el-date-picker |
| | | v-model="dateRange" |
| | | value-format="YYYY-MM-DD" |
| | | type="daterange" |
| | | range-separator="-" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | ></el-date-picker> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">重置</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="primary" |
| | | plain |
| | | icon="Plus" |
| | | @click="handleAdd" |
| | | v-hasPermi="['account:user:add']" |
| | | >新增</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="success" |
| | | plain |
| | | icon="Edit" |
| | | :disabled="single" |
| | | @click="handleUpdate" |
| | | v-hasPermi="['account:user:edit']" |
| | | >修改</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="danger" |
| | | plain |
| | | icon="Delete" |
| | | :disabled="multiple" |
| | | @click="handleDelete" |
| | | v-hasPermi="['account:user:remove']" |
| | | >删除</el-button> |
| | | </el-col> |
| | | <el-col :span="1.5"> |
| | | <el-button |
| | | type="warning" |
| | | plain |
| | | icon="Download" |
| | | @click="handleExport" |
| | | v-hasPermi="['account:user:export']" |
| | | >导出</el-button> |
| | | </el-col> |
| | | <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar> |
| | | </el-row> |
| | | |
| | | <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="会员ID" align="center" prop="userId" width="90" /> |
| | | <el-table-column label="用户名" align="center" prop="userName" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="手机号" align="center" prop="phone" width="130" /> |
| | | <el-table-column label="昵称" align="center" prop="nickname" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="性别" align="center" prop="gender" width="80"> |
| | | <template #default="scope"> |
| | | <dict-tag :options="sys_user_sex" :value="scope.row.gender" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="状态" align="center" prop="status" width="80"> |
| | | <template #default="scope"> |
| | | <dict-tag :options="sys_normal_disable" :value="scope.row.status" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="创建时间" align="center" prop="createTime" width="180"> |
| | | <template #default="scope"> |
| | | <span>{{ parseTime(scope.row.createTime) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="180" align="center" class-name="small-padding fixed-width"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['account:user:edit']">修改</el-button> |
| | | <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['account:user:remove']">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination |
| | | v-show="total > 0" |
| | | :total="total" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | @pagination="getList" |
| | | /> |
| | | |
| | | <!-- 添加或修改会员对话框 --> |
| | | <el-dialog :title="title" v-model="open" width="600px" append-to-body> |
| | | <el-form ref="userRef" :model="form" :rules="rules" label-width="80px"> |
| | | <el-form-item label="用户名" prop="userName"> |
| | | <el-input v-model="form.userName" placeholder="请输入用户名" maxlength="64" /> |
| | | </el-form-item> |
| | | <el-form-item label="手机号" prop="phone"> |
| | | <el-input v-model="form.phone" placeholder="请输入手机号" maxlength="20" /> |
| | | </el-form-item> |
| | | <el-form-item label="密码" prop="password"> |
| | | <el-input |
| | | v-model="form.password" |
| | | type="password" |
| | | show-password |
| | | maxlength="20" |
| | | :placeholder="form.userId ? '留空则不修改密码' : '请输入密码'" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="昵称" prop="nickname"> |
| | | <el-input v-model="form.nickname" placeholder="请输入昵称" maxlength="64" /> |
| | | </el-form-item> |
| | | <el-form-item label="头像地址" prop="avatar"> |
| | | <el-input v-model="form.avatar" placeholder="请输入头像图片地址" maxlength="255" /> |
| | | </el-form-item> |
| | | <el-form-item label="性别" prop="gender"> |
| | | <el-radio-group v-model="form.gender"> |
| | | <el-radio |
| | | v-for="dict in sys_user_sex" |
| | | :key="dict.value" |
| | | :value="dict.value" |
| | | >{{ dict.label }}</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="生日" prop="birthday"> |
| | | <el-date-picker |
| | | v-model="form.birthday" |
| | | type="date" |
| | | value-format="YYYY-MM-DD" |
| | | placeholder="选择日期" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="状态" prop="status"> |
| | | <el-radio-group v-model="form.status"> |
| | | <el-radio |
| | | v-for="dict in sys_normal_disable" |
| | | :key="dict.value" |
| | | :value="dict.value" |
| | | >{{ dict.label }}</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | <el-form-item label="备注" prop="remark"> |
| | | <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" maxlength="500" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">确 定</el-button> |
| | | <el-button @click="cancel">取 消</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup name="AccountUser"> |
| | | import { listUser, addUser, delUser, getUser, updateUser } from "@/api/user/account" |
| | | |
| | | const { proxy } = getCurrentInstance() |
| | | const { sys_user_sex, sys_normal_disable } = useDict("sys_user_sex", "sys_normal_disable") |
| | | |
| | | const userList = ref([]) |
| | | const open = ref(false) |
| | | const loading = ref(true) |
| | | const showSearch = ref(true) |
| | | const ids = ref([]) |
| | | const single = ref(true) |
| | | const multiple = ref(true) |
| | | const total = ref(0) |
| | | const title = ref("") |
| | | const dateRange = ref([]) |
| | | |
| | | const data = reactive({ |
| | | form: {}, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | userName: undefined, |
| | | phone: undefined, |
| | | nickname: undefined, |
| | | status: undefined |
| | | }, |
| | | rules: { |
| | | userName: [{ required: true, message: "用户名不能为空", trigger: "blur" }], |
| | | // 新增时密码必填;修改时留空表示不改,故用自定义校验 |
| | | password: [{ |
| | | validator: (rule, value, callback) => { |
| | | if (!form.value.userId && !value) { |
| | | callback(new Error("密码不能为空")) |
| | | } else { |
| | | callback() |
| | | } |
| | | }, |
| | | trigger: "blur" |
| | | }] |
| | | } |
| | | }) |
| | | |
| | | const { queryParams, form, rules } = toRefs(data) |
| | | |
| | | /** 查询会员列表 */ |
| | | function getList() { |
| | | loading.value = true |
| | | listUser(proxy.addDateRange(queryParams.value, dateRange.value)).then(response => { |
| | | userList.value = response.rows |
| | | total.value = response.total |
| | | loading.value = false |
| | | }) |
| | | } |
| | | |
| | | /** 取消按钮 */ |
| | | function cancel() { |
| | | open.value = false |
| | | reset() |
| | | } |
| | | |
| | | /** 表单重置 */ |
| | | function reset() { |
| | | form.value = { |
| | | userId: undefined, |
| | | userName: undefined, |
| | | phone: undefined, |
| | | password: undefined, |
| | | nickname: undefined, |
| | | avatar: undefined, |
| | | gender: "2", |
| | | birthday: undefined, |
| | | status: "0", |
| | | remark: undefined |
| | | } |
| | | proxy.resetForm("userRef") |
| | | } |
| | | |
| | | /** 搜索按钮操作 */ |
| | | function handleQuery() { |
| | | queryParams.value.pageNum = 1 |
| | | getList() |
| | | } |
| | | |
| | | /** 重置按钮操作 */ |
| | | function resetQuery() { |
| | | dateRange.value = [] |
| | | proxy.resetForm("queryRef") |
| | | handleQuery() |
| | | } |
| | | |
| | | /** 多选框选中数据 */ |
| | | function handleSelectionChange(selection) { |
| | | ids.value = selection.map(item => item.userId) |
| | | single.value = selection.length != 1 |
| | | multiple.value = !selection.length |
| | | } |
| | | |
| | | /** 新增按钮操作 */ |
| | | function handleAdd() { |
| | | reset() |
| | | open.value = true |
| | | title.value = "添加会员" |
| | | } |
| | | |
| | | /** 修改按钮操作 */ |
| | | function handleUpdate(row) { |
| | | reset() |
| | | const userId = row.userId || ids.value |
| | | getUser(userId).then(response => { |
| | | form.value = response.data |
| | | // 接口不回传密码,避免把 hash 回填到输入框后又被当成新密码提交 |
| | | form.value.password = undefined |
| | | open.value = true |
| | | title.value = "修改会员" |
| | | }) |
| | | } |
| | | |
| | | /** 提交按钮 */ |
| | | function submitForm() { |
| | | proxy.$refs["userRef"].validate(valid => { |
| | | if (valid) { |
| | | if (form.value.userId != undefined) { |
| | | updateUser(form.value).then(() => { |
| | | proxy.$modal.msgSuccess("修改成功") |
| | | open.value = false |
| | | getList() |
| | | }) |
| | | } else { |
| | | addUser(form.value).then(() => { |
| | | proxy.$modal.msgSuccess("新增成功") |
| | | open.value = false |
| | | getList() |
| | | }) |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | |
| | | /** 删除按钮操作 */ |
| | | function handleDelete(row) { |
| | | const userIds = row.userId || ids.value |
| | | proxy.$modal.confirm('是否确认删除会员编号为"' + userIds + '"的数据项?').then(function() { |
| | | return delUser(userIds) |
| | | }).then(() => { |
| | | getList() |
| | | proxy.$modal.msgSuccess("删除成功") |
| | | }).catch(() => {}) |
| | | } |
| | | |
| | | /** 导出按钮操作 */ |
| | | function handleExport() { |
| | | proxy.download("account/user/export", { |
| | | ...queryParams.value |
| | | }, `account_user_${new Date().getTime()}.xlsx`) |
| | | } |
| | | |
| | | getList() |
| | | </script> |
| | |
| | | import path from 'path' |
| | | import createVitePlugins from './vite/plugins' |
| | | |
| | | const baseUrl = 'http://localhost:8080' // 后端接口 |
| | | const baseUrl = 'http://localhost:8085' // 后端接口 |
| | | |
| | | // https://vitejs.dev/config/ |
| | | export default defineConfig(({ mode, command }) => { |
| New file |
| | |
| | | @echo off |
| | | setlocal enabledelayedexpansion |
| | | |
| | | rem ============================================================ |
| | | rem Hugray ±¾µØÒ»¼üÆô¶¯£ºNacos -> Redis -> 8 ¸ö΢·þÎñ |
| | | rem ÒÑÕ¼ÓõĶ˿ڻáÌø¹ý£¬¿ÉÖØ¸´Ö´ÐУ¨Ãݵȣ© |
| | | rem ============================================================ |
| | | |
| | | rem ---------------------- ÅäÖÃÇø ---------------------- |
| | | set "JAVA_HOME=D:\jdk-17.0.9" |
| | | set "NACOS_HOME=F:\nacos-3.0.2\nacos" |
| | | set "REDIS_HOME=C:\Users\Admin\Desktop\redis" |
| | | rem ---------------------------------------------------- |
| | | |
| | | set "SERVER_DIR=%~dp0.." |
| | | set "LOG_DIR=%SERVER_DIR%\logs" |
| | | set "JAVA=%JAVA_HOME%\bin\java.exe" |
| | | |
| | | if not exist "%JAVA%" ( |
| | | echo [´íÎó] δÕÒµ½ JDK£º%JAVA% |
| | | echo ÇëÐ޸ı¾½Å±¾¡¸ÅäÖÃÇø¡¹ÖÐµÄ JAVA_HOME |
| | | pause |
| | | exit /b 1 |
| | | ) |
| | | |
| | | cd /d "%SERVER_DIR%" |
| | | if not exist "%LOG_DIR%" md "%LOG_DIR%" |
| | | |
| | | echo. |
| | | echo ============ Hugray ±¾µØ¿ª·¢»·¾³Æô¶¯ ============ |
| | | echo JDK : %JAVA_HOME% |
| | | echo ÈÕÖ¾ : %LOG_DIR% |
| | | echo ================================================ |
| | | echo. |
| | | |
| | | rem ---------- 1. Nacos ---------- |
| | | call :port_in_use 8848 |
| | | if not errorlevel 1 ( |
| | | echo [Ìø¹ý] Nacos ÒÑÔÚÔËÐÐ |
| | | ) else ( |
| | | if not exist "%NACOS_HOME%\bin\startup.cmd" ( |
| | | echo [´íÎó] δÕÒµ½ Nacos£º%NACOS_HOME%\bin\startup.cmd |
| | | pause |
| | | exit /b 1 |
| | | ) |
| | | echo [Æô¶¯] Nacos -^> %NACOS_HOME% |
| | | rem ²»ÒªÓà start + startup.cmd£ºstart »áÈÃ×Ó½ø³Ì¼Ì³Ð±¾½Å±¾±»Öض¨ÏòµÄ stdin£¨³£Îª nul£©£¬ |
| | | rem startup.cmd ĩβµÄ pause Òò¶øÁ¢¼´·µ»Ø¡¢¿ØÖÆÌ¨ËæÖ®¹Ø±Õ£¬Nacos »á±»Á¬´øÉ±µô¡£ |
| | | rem ¸ÄÓà Start-Process£¬×Ó½ø³ÌÄõ½¶ÀÁ¢¿ØÖÆÌ¨£¬Nacos ÉúÃüÖÜÆÚÓë±¾½Å±¾½âñî¡£ |
| | | powershell -NoProfile -Command "Start-Process -FilePath '%NACOS_HOME%\bin\startup.cmd' -ArgumentList '-m','standalone' -WindowStyle Hidden" |
| | | ) |
| | | |
| | | echo [µÈ´ý] Nacos 8848 ¾ÍÐ÷ ... |
| | | call :wait_port 8848 120 |
| | | if errorlevel 1 ( |
| | | echo [´íÎó] Nacos 120 ÃëÄÚδ¾ÍÐ÷£¬Çë²é¿´ %NACOS_HOME%\logs |
| | | pause |
| | | exit /b 1 |
| | | ) |
| | | echo [¾ÍÐ÷] Nacos |
| | | |
| | | rem ---------- 2. Redis ---------- |
| | | call :port_in_use 6379 |
| | | if not errorlevel 1 ( |
| | | echo [Ìø¹ý] Redis ÒÑÔÚÔËÐÐ |
| | | ) else ( |
| | | if not exist "%REDIS_HOME%\redis-server.exe" ( |
| | | echo [¾¯¸æ] δÕÒµ½ Redis£º%REDIS_HOME%\redis-server.exe£¬Ìø¹ý |
| | | ) else ( |
| | | echo [Æô¶¯] Redis -^> %REDIS_HOME% |
| | | powershell -NoProfile -Command "Start-Process -FilePath '%REDIS_HOME%\redis-server.exe' -ArgumentList '%REDIS_HOME%\redis.windows.conf' -WorkingDirectory '%REDIS_HOME%' -WindowStyle Hidden" |
| | | call :wait_port 6379 20 |
| | | if errorlevel 1 echo [¾¯¸æ] Redis Æô¶¯½ÏÂý£¬ÇëÉÔºóÈ·ÈÏ |
| | | ) |
| | | ) |
| | | |
| | | rem ---------- 3. ΢·þÎñ£¨gateway ·Å×îºó£¬µÈËüÆðÀ´¼´¿ÉÅж¨ÕûÌå¾ÍÐ÷£© ---------- |
| | | echo. |
| | | echo ---------- Æô¶¯Î¢·þÎñ ---------- |
| | | call :start_service "ruoyi-auth" "ruoyi-auth" "ruoyi-auth.jar" 9200 |
| | | call :start_service "ruoyi-system" "ruoyi-modules\ruoyi-system" "ruoyi-modules-system.jar" 9201 |
| | | call :start_service "ruoyi-gen" "ruoyi-modules\ruoyi-gen" "ruoyi-modules-gen.jar" 9202 |
| | | call :start_service "ruoyi-job" "ruoyi-modules\ruoyi-job" "ruoyi-modules-job.jar" 9203 |
| | | call :start_service "ruoyi-file" "ruoyi-modules\ruoyi-file" "ruoyi-modules-file.jar" 9300 |
| | | call :start_service "ruoyi-user" "ruoyi-modules\ruoyi-user" "ruoyi-modules-user.jar" 9210 |
| | | call :start_service "ruoyi-monitor" "ruoyi-visual\ruoyi-monitor" "ruoyi-visual-monitor.jar" 9100 |
| | | call :start_service "ruoyi-gateway" "ruoyi-gateway" "ruoyi-gateway.jar" 8085 |
| | | |
| | | echo. |
| | | echo ---------- µÈ´ýÍø¹Ø¾ÍÐ÷ ---------- |
| | | call :wait_port 8085 120 |
| | | if errorlevel 1 ( |
| | | echo [¾¯¸æ] Íø¹Ø 8085 δÔÚ 120 ÃëÄÚ¾ÍÐ÷£¬Çë²é¿´ %LOG_DIR%\ruoyi-gateway.err.log |
| | | ) else ( |
| | | echo [¾ÍÐ÷] Íø¹Ø http://localhost:8085 |
| | | ) |
| | | |
| | | echo. |
| | | echo ============ Æô¶¯Íê³É ============ |
| | | echo Nacos ¿ØÖÆÌ¨ : http://localhost:8082 |
| | | echo Íø¹Ø : http://localhost:8085 |
| | | echo ¹ÜÀíºǫ́ : ¼û hugray-admin Ŀ¼£¨npm run dev£© |
| | | echo ֹͣȫ²¿ : bin\stop-all.bat |
| | | echo ================================ |
| | | echo. |
| | | pause |
| | | exit /b 0 |
| | | |
| | | |
| | | rem ============================================================ |
| | | rem ×Ó¹ý³Ì |
| | | rem ============================================================ |
| | | |
| | | rem :port_in_use <¶Ë¿Ú> -- errorlevel 0 ±íʾ¶Ë¿ÚÒѱ»¼àÌý |
| | | :port_in_use |
| | | netstat -an | findstr /C:":%~1 " | findstr /C:"LISTENING" >nul 2>&1 |
| | | exit /b %errorlevel% |
| | | |
| | | rem :wait_port <¶Ë¿Ú> <³¬Ê±ÃëÊý> -- errorlevel 0 ±íʾÒѾÍÐ÷ |
| | | :wait_port |
| | | set /a _waited=0 |
| | | :wait_port_loop |
| | | call :port_in_use %~1 |
| | | if not errorlevel 1 exit /b 0 |
| | | set /a _waited+=1 |
| | | if !_waited! GEQ %~2 exit /b 1 |
| | | rem ÑÓʱÓà ping£ºtimeout ÔÚ stdin ±»Öض¨Ïòʱ»áÖ±½ÓÍ˳ö£¬¿¿²»×¡£» |
| | | rem ¼Ó¾ø¶Ô·¾¶ÊÇΪÁ˱ÜÃâ Git Bash µÈ»·¾³°ÑͬÃû¹¤¾ß»ì½ø PATH |
| | | "%SystemRoot%\System32\ping.exe" -n 2 -w 1000 127.0.0.1 >nul |
| | | goto :wait_port_loop |
| | | |
| | | rem :start_service <Ãû³Æ> <Ä£¿éÏà¶ÔĿ¼> <jar ÎļþÃû> <¶Ë¿Ú> |
| | | :start_service |
| | | call :port_in_use %~4 |
| | | if not errorlevel 1 ( |
| | | echo [Ìø¹ý] %~1 - ¶Ë¿Ú %~4 Òѱ»Õ¼Óà |
| | | exit /b 0 |
| | | ) |
| | | set "_dir=%SERVER_DIR%\%~2\target" |
| | | set "_jar=%_dir%\%~3" |
| | | if not exist "%_jar%" ( |
| | | echo [´íÎó] %~1 - δÕÒµ½ %_jar% |
| | | echo ÇëÏÈÖ´ÐÐ bin\package.bat ¹¹½¨ |
| | | exit /b 1 |
| | | ) |
| | | echo [Æô¶¯] %~1 - ¶Ë¿Ú %~4 |
| | | powershell -NoProfile -Command "Start-Process -FilePath '%JAVA%' -ArgumentList '-Dfile.encoding=UTF-8','-Xms512m','-Xmx1024m','-XX:MetaspaceSize=128m','-XX:MaxMetaspaceSize=512m','-jar','%_jar%' -WorkingDirectory '%_dir%' -RedirectStandardOutput '%LOG_DIR%\%~1.out.log' -RedirectStandardError '%LOG_DIR%\%~1.err.log' -WindowStyle Hidden" |
| | | exit /b 0 |
| New file |
| | |
| | | @echo off |
| | | setlocal enabledelayedexpansion |
| | | |
| | | rem ============================================================ |
| | | rem Hugray ±¾µØÒ»¼üÍ£Ö¹£ºÎ¢·þÎñ + Nacos |
| | | rem Redis Ϊ³£×¤Öмä¼þ£¬²»ÔÚ±¾½Å±¾Í£Ö¹·¶Î§ÄÚ |
| | | rem ============================================================ |
| | | |
| | | echo. |
| | | echo ============ Hugray ±¾µØ¿ª·¢»·¾³Í£Ö¹ ============ |
| | | echo. |
| | | |
| | | rem ÏÈÍ£Íø¹Ø£¬ÔÙÍ£ÒµÎñ·þÎñ£¬×îºóÍ£ Nacos |
| | | for %%p in (8085 9200 9201 9202 9203 9210 9300 9100 8848) do ( |
| | | call :kill_port %%p |
| | | ) |
| | | |
| | | echo. |
| | | echo ============ Í£Ö¹Íê³É ============ |
| | | echo Redis ÈÔÔÚÔËÐУ¨ÈçÐèÍ£Ö¹ÇëÊÖ¶¯½áÊø½ø³Ì£© |
| | | echo ================================ |
| | | echo. |
| | | pause |
| | | exit /b 0 |
| | | |
| | | |
| | | rem :kill_port <¶Ë¿Ú> -- ½áÊø¼àÌý¸Ã¶Ë¿ÚµÄ½ø³Ì |
| | | :kill_port |
| | | for /f "tokens=5" %%a in ('netstat -ano ^| findstr /C:":%~1 " ^| findstr /C:"LISTENING"') do ( |
| | | echo [Í£Ö¹] ¶Ë¿Ú %~1 - PID %%a |
| | | taskkill /F /PID %%a >nul 2>&1 |
| | | ) |
| | | exit /b 0 |
| | |
| | | # Tomcat |
| | | server: |
| | | port: 8080 |
| | | port: 8085 |
| | | |
| | | # Spring |
| | | spring: |
| | |
| | | <module>ruoyi-gen</module> |
| | | <module>ruoyi-job</module> |
| | | <module>ruoyi-file</module> |
| | | <module>ruoyi-user</module> |
| | | </modules> |
| | | |
| | | <artifactId>ruoyi-modules</artifactId> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| | | xmlns="http://maven.apache.org/POM/4.0.0" |
| | | xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| | | <parent> |
| | | <groupId>com.ruoyi</groupId> |
| | | <artifactId>ruoyi-modules</artifactId> |
| | | <version>3.6.8</version> |
| | | </parent> |
| | | <modelVersion>4.0.0</modelVersion> |
| | | |
| | | <artifactId>ruoyi-modules-user</artifactId> |
| | | |
| | | <description> |
| | | ruoyi-modules-user用户服务(C端会员) |
| | | </description> |
| | | |
| | | <dependencies> |
| | | |
| | | <!-- SpringCloud Alibaba Nacos --> |
| | | <dependency> |
| | | <groupId>com.alibaba.cloud</groupId> |
| | | <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- SpringCloud Alibaba Nacos Config --> |
| | | <dependency> |
| | | <groupId>com.alibaba.cloud</groupId> |
| | | <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- SpringCloud Alibaba Sentinel --> |
| | | <dependency> |
| | | <groupId>com.alibaba.cloud</groupId> |
| | | <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- SpringBoot Actuator --> |
| | | <dependency> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-starter-actuator</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- Mysql Connector --> |
| | | <dependency> |
| | | <groupId>com.mysql</groupId> |
| | | <artifactId>mysql-connector-j</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- RuoYi Common DataSource --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <artifactId>ruoyi-common-datasource</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- RuoYi Common DataScope --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <artifactId>ruoyi-common-datascope</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- RuoYi Common Log --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <artifactId>ruoyi-common-log</artifactId> |
| | | </dependency> |
| | | |
| | | <!-- RuoYi Common Swagger --> |
| | | <dependency> |
| | | <groupId>com.ruoyi</groupId> |
| | | <artifactId>ruoyi-common-swagger</artifactId> |
| | | </dependency> |
| | | |
| | | </dependencies> |
| | | |
| | | <!-- finalName 固定为 artifactId,jar 名必须与 bin/start-all.bat 里的写法一致 --> |
| | | <build> |
| | | <finalName>${project.artifactId}</finalName> |
| | | <plugins> |
| | | <plugin> |
| | | <groupId>org.springframework.boot</groupId> |
| | | <artifactId>spring-boot-maven-plugin</artifactId> |
| | | <executions> |
| | | <execution> |
| | | <goals> |
| | | <goal>repackage</goal> |
| | | </goals> |
| | | </execution> |
| | | </executions> |
| | | </plugin> |
| | | </plugins> |
| | | </build> |
| | | |
| | | </project> |
| New file |
| | |
| | | package com.ruoyi.user; |
| | | |
| | | import org.springframework.boot.SpringApplication; |
| | | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| | | import com.ruoyi.common.security.annotation.EnableCustomConfig; |
| | | import com.ruoyi.common.security.annotation.EnableRyFeignClients; |
| | | |
| | | /** |
| | | * 用户服务(C端会员) |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @EnableCustomConfig |
| | | @EnableRyFeignClients |
| | | @SpringBootApplication |
| | | public class RuoYiUserApplication |
| | | { |
| | | public static void main(String[] args) |
| | | { |
| | | SpringApplication.run(RuoYiUserApplication.class, args); |
| | | System.out.println("(♥◠‿◠)ノ゙ 用户服务启动成功 ლ(´ڡ`ლ)゙ \n" + |
| | | " .-------. ____ __ \n" + |
| | | " | _ _ \\ \\ \\ / / \n" + |
| | | " | ( ' ) | \\ _. / ' \n" + |
| | | " |(_ o _) / _( )_ .' \n" + |
| | | " | (_,_).' __ ___(_ o _)' \n" + |
| | | " | |\\ \\ | || |(_,_)' \n" + |
| | | " | | \\ `' /| `-' / \n" + |
| | | " | | \\ / \\ / \n" + |
| | | " ''-' `'-' `-..-' "); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.user.controller; |
| | | |
| | | import java.util.List; |
| | | import jakarta.servlet.http.HttpServletResponse; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.DeleteMapping; |
| | | import org.springframework.web.bind.annotation.GetMapping; |
| | | import org.springframework.web.bind.annotation.PathVariable; |
| | | import org.springframework.web.bind.annotation.PostMapping; |
| | | import org.springframework.web.bind.annotation.PutMapping; |
| | | import org.springframework.web.bind.annotation.RequestBody; |
| | | import org.springframework.web.bind.annotation.RequestMapping; |
| | | import org.springframework.web.bind.annotation.RestController; |
| | | import com.ruoyi.common.core.utils.StringUtils; |
| | | import com.ruoyi.common.core.utils.poi.ExcelUtil; |
| | | import com.ruoyi.common.core.web.controller.BaseController; |
| | | import com.ruoyi.common.core.web.domain.AjaxResult; |
| | | import com.ruoyi.common.core.web.page.TableDataInfo; |
| | | import com.ruoyi.common.log.annotation.Log; |
| | | import com.ruoyi.common.log.enums.BusinessType; |
| | | import com.ruoyi.common.security.annotation.RequiresPermissions; |
| | | import com.ruoyi.common.security.utils.SecurityUtils; |
| | | import com.ruoyi.user.domain.AccountUser; |
| | | import com.ruoyi.user.service.IAccountUserService; |
| | | |
| | | /** |
| | | * 会员用户 信息操作处理 |
| | | * |
| | | * 网关前缀 /account 由 StripPrefix=1 剥掉,故此处映射为 /user, |
| | | * 外部实际路径是 /account/user/**。 |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @RestController |
| | | @RequestMapping("/user") |
| | | public class AccountUserController extends BaseController |
| | | { |
| | | @Autowired |
| | | private IAccountUserService accountUserService; |
| | | |
| | | /** |
| | | * 查询会员列表 |
| | | */ |
| | | @RequiresPermissions("account:user:list") |
| | | @GetMapping("/list") |
| | | public TableDataInfo list(AccountUser accountUser) |
| | | { |
| | | startPage(); |
| | | List<AccountUser> list = accountUserService.selectAccountUserList(accountUser); |
| | | return getDataTable(list); |
| | | } |
| | | |
| | | /** |
| | | * 导出会员列表 |
| | | */ |
| | | @RequiresPermissions("account:user:export") |
| | | @Log(title = "会员管理", businessType = BusinessType.EXPORT) |
| | | @PostMapping("/export") |
| | | public void export(HttpServletResponse response, AccountUser accountUser) |
| | | { |
| | | List<AccountUser> list = accountUserService.selectAccountUserList(accountUser); |
| | | ExcelUtil<AccountUser> util = new ExcelUtil<AccountUser>(AccountUser.class); |
| | | util.exportExcel(response, list, "会员数据"); |
| | | } |
| | | |
| | | /** |
| | | * 获取会员详细信息 |
| | | */ |
| | | @RequiresPermissions("account:user:query") |
| | | @GetMapping(value = "/{userId}") |
| | | public AjaxResult getInfo(@PathVariable Long userId) |
| | | { |
| | | return success(accountUserService.selectAccountUserById(userId)); |
| | | } |
| | | |
| | | /** |
| | | * 新增会员 |
| | | */ |
| | | @RequiresPermissions("account:user:add") |
| | | @Log(title = "会员管理", businessType = BusinessType.INSERT) |
| | | @PostMapping |
| | | public AjaxResult add(@Validated @RequestBody AccountUser accountUser) |
| | | { |
| | | if (!accountUserService.checkUsernameUnique(accountUser)) |
| | | { |
| | | return error("新增会员'" + accountUser.getUserName() + "'失败,用户名已存在"); |
| | | } |
| | | if (!accountUserService.checkPhoneUnique(accountUser)) |
| | | { |
| | | return error("新增会员'" + accountUser.getUserName() + "'失败,手机号已存在"); |
| | | } |
| | | if (StringUtils.isEmpty(accountUser.getPassword())) |
| | | { |
| | | return error("密码不能为空"); |
| | | } |
| | | accountUser.setCreateBy(SecurityUtils.getUsername()); |
| | | return toAjax(accountUserService.insertAccountUser(accountUser)); |
| | | } |
| | | |
| | | /** |
| | | * 修改会员 |
| | | */ |
| | | @RequiresPermissions("account:user:edit") |
| | | @Log(title = "会员管理", businessType = BusinessType.UPDATE) |
| | | @PutMapping |
| | | public AjaxResult edit(@Validated @RequestBody AccountUser accountUser) |
| | | { |
| | | if (!accountUserService.checkUsernameUnique(accountUser)) |
| | | { |
| | | return error("修改会员'" + accountUser.getUserName() + "'失败,用户名已存在"); |
| | | } |
| | | if (!accountUserService.checkPhoneUnique(accountUser)) |
| | | { |
| | | return error("修改会员'" + accountUser.getUserName() + "'失败,手机号已存在"); |
| | | } |
| | | accountUser.setUpdateBy(SecurityUtils.getUsername()); |
| | | return toAjax(accountUserService.updateAccountUser(accountUser)); |
| | | } |
| | | |
| | | /** |
| | | * 删除会员 |
| | | */ |
| | | @RequiresPermissions("account:user:remove") |
| | | @Log(title = "会员管理", businessType = BusinessType.DELETE) |
| | | @DeleteMapping("/{userIds}") |
| | | public AjaxResult remove(@PathVariable Long[] userIds) |
| | | { |
| | | return toAjax(accountUserService.deleteAccountUserByIds(userIds)); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.user.domain; |
| | | |
| | | import java.util.Date; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import jakarta.validation.constraints.Size; |
| | | import org.apache.commons.lang3.builder.ToStringBuilder; |
| | | import org.apache.commons.lang3.builder.ToStringStyle; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import com.fasterxml.jackson.annotation.JsonProperty; |
| | | import com.ruoyi.common.core.annotation.Excel; |
| | | import com.ruoyi.common.core.annotation.Excel.ColumnType; |
| | | import com.ruoyi.common.core.web.domain.BaseEntity; |
| | | |
| | | /** |
| | | * C端会员用户表 account_user |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public class AccountUser extends BaseEntity |
| | | { |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | /** 会员ID */ |
| | | @Excel(name = "会员ID", cellType = ColumnType.NUMERIC) |
| | | private Long userId; |
| | | |
| | | /** |
| | | * 用户名 |
| | | * |
| | | * 注意:属性名刻意用驼峰 userName,与上游 SysUser.userName 一致。网关的 AuthFilter 会 |
| | | * 给每个转发请求加上请求头 username=<登录名>(SecurityConstants.DETAILS_USERNAME), |
| | | * 而 Spring 6+ 的 @ModelAttribute 会把请求头一并绑定到命令对象——若此处叫 username, |
| | | * 列表/导出接口在未显式传参时会被注入当前登录名,导致查询结果被静默过滤(实测列表恒为空)。 |
| | | */ |
| | | @Excel(name = "用户名") |
| | | private String userName; |
| | | |
| | | /** 手机号 */ |
| | | @Excel(name = "手机号") |
| | | private String phone; |
| | | |
| | | /** 密码(BCrypt 存储)。只入不出,避免密码随响应回传 */ |
| | | @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) |
| | | private String password; |
| | | |
| | | /** 昵称 */ |
| | | @Excel(name = "昵称") |
| | | private String nickname; |
| | | |
| | | /** 头像地址 */ |
| | | private String avatar; |
| | | |
| | | /** 性别(0男 1女 2未知,对齐 sys_user_sex 字典) */ |
| | | @Excel(name = "性别", readConverterExp = "0=男,1=女,2=未知") |
| | | private String gender; |
| | | |
| | | /** 生日 */ |
| | | @JsonFormat(pattern = "yyyy-MM-dd") |
| | | @Excel(name = "生日", width = 30, dateFormat = "yyyy-MM-dd") |
| | | private Date birthday; |
| | | |
| | | /** 状态(0正常 1停用) */ |
| | | @Excel(name = "状态", readConverterExp = "0=正常,1=停用") |
| | | private String status; |
| | | |
| | | /** 删除标志(0存在 2删除) */ |
| | | private String delFlag; |
| | | |
| | | public Long getUserId() |
| | | { |
| | | return userId; |
| | | } |
| | | |
| | | public void setUserId(Long userId) |
| | | { |
| | | this.userId = userId; |
| | | } |
| | | |
| | | @NotBlank(message = "用户名不能为空") |
| | | @Size(min = 0, max = 64, message = "用户名长度不能超过64个字符") |
| | | public String getUserName() |
| | | { |
| | | return userName; |
| | | } |
| | | |
| | | public void setUserName(String userName) |
| | | { |
| | | this.userName = userName; |
| | | } |
| | | |
| | | @Size(min = 0, max = 20, message = "手机号长度不能超过20个字符") |
| | | public String getPhone() |
| | | { |
| | | return phone; |
| | | } |
| | | |
| | | public void setPhone(String phone) |
| | | { |
| | | this.phone = phone; |
| | | } |
| | | |
| | | @Size(min = 0, max = 20, message = "密码长度必须在5到20个字符之间") |
| | | public String getPassword() |
| | | { |
| | | return password; |
| | | } |
| | | |
| | | public void setPassword(String password) |
| | | { |
| | | this.password = password; |
| | | } |
| | | |
| | | @Size(min = 0, max = 64, message = "昵称长度不能超过64个字符") |
| | | public String getNickname() |
| | | { |
| | | return nickname; |
| | | } |
| | | |
| | | public void setNickname(String nickname) |
| | | { |
| | | this.nickname = nickname; |
| | | } |
| | | |
| | | public String getAvatar() |
| | | { |
| | | return avatar; |
| | | } |
| | | |
| | | public void setAvatar(String avatar) |
| | | { |
| | | this.avatar = avatar; |
| | | } |
| | | |
| | | public String getGender() |
| | | { |
| | | return gender; |
| | | } |
| | | |
| | | public void setGender(String gender) |
| | | { |
| | | this.gender = gender; |
| | | } |
| | | |
| | | public Date getBirthday() |
| | | { |
| | | return birthday; |
| | | } |
| | | |
| | | public void setBirthday(Date birthday) |
| | | { |
| | | this.birthday = birthday; |
| | | } |
| | | |
| | | public String getStatus() |
| | | { |
| | | return status; |
| | | } |
| | | |
| | | public void setStatus(String status) |
| | | { |
| | | this.status = status; |
| | | } |
| | | |
| | | public String getDelFlag() |
| | | { |
| | | return delFlag; |
| | | } |
| | | |
| | | public void setDelFlag(String delFlag) |
| | | { |
| | | this.delFlag = delFlag; |
| | | } |
| | | |
| | | @Override |
| | | public String toString() { |
| | | return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) |
| | | .append("userId", getUserId()) |
| | | .append("userName", getUserName()) |
| | | .append("phone", getPhone()) |
| | | .append("nickname", getNickname()) |
| | | .append("avatar", getAvatar()) |
| | | .append("gender", getGender()) |
| | | .append("birthday", getBirthday()) |
| | | .append("status", getStatus()) |
| | | .append("delFlag", getDelFlag()) |
| | | .append("createBy", getCreateBy()) |
| | | .append("createTime", getCreateTime()) |
| | | .append("updateBy", getUpdateBy()) |
| | | .append("updateTime", getUpdateTime()) |
| | | .append("remark", getRemark()) |
| | | .toString(); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.user.mapper; |
| | | |
| | | import java.util.List; |
| | | import com.ruoyi.user.domain.AccountUser; |
| | | |
| | | /** |
| | | * 会员用户 数据层 |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public interface AccountUserMapper |
| | | { |
| | | /** |
| | | * 根据会员ID查询 |
| | | */ |
| | | public AccountUser selectAccountUserById(Long userId); |
| | | |
| | | /** |
| | | * 根据用户名查询(查重用) |
| | | */ |
| | | public AccountUser selectAccountUserByUsername(String userName); |
| | | |
| | | /** |
| | | * 根据手机号查询(查重用) |
| | | */ |
| | | public AccountUser selectAccountUserByPhone(String phone); |
| | | |
| | | /** |
| | | * 查询会员列表 |
| | | */ |
| | | public List<AccountUser> selectAccountUserList(AccountUser accountUser); |
| | | |
| | | /** |
| | | * 新增会员 |
| | | */ |
| | | public int insertAccountUser(AccountUser accountUser); |
| | | |
| | | /** |
| | | * 修改会员 |
| | | */ |
| | | public int updateAccountUser(AccountUser accountUser); |
| | | |
| | | /** |
| | | * 逻辑删除会员 |
| | | */ |
| | | public int deleteAccountUserById(Long userId); |
| | | |
| | | /** |
| | | * 批量逻辑删除会员 |
| | | */ |
| | | public int deleteAccountUserByIds(Long[] userIds); |
| | | } |
| New file |
| | |
| | | package com.ruoyi.user.service; |
| | | |
| | | import java.util.List; |
| | | import com.ruoyi.user.domain.AccountUser; |
| | | |
| | | /** |
| | | * 会员用户 业务层 |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | public interface IAccountUserService |
| | | { |
| | | /** |
| | | * 根据会员ID查询 |
| | | */ |
| | | public AccountUser selectAccountUserById(Long userId); |
| | | |
| | | /** |
| | | * 查询会员列表 |
| | | */ |
| | | public List<AccountUser> selectAccountUserList(AccountUser accountUser); |
| | | |
| | | /** |
| | | * 校验用户名是否唯一 |
| | | * |
| | | * @return true 唯一,false 已存在 |
| | | */ |
| | | public boolean checkUsernameUnique(AccountUser accountUser); |
| | | |
| | | /** |
| | | * 校验手机号是否唯一 |
| | | */ |
| | | public boolean checkPhoneUnique(AccountUser accountUser); |
| | | |
| | | /** |
| | | * 新增会员(密码加密后落库) |
| | | */ |
| | | public int insertAccountUser(AccountUser accountUser); |
| | | |
| | | /** |
| | | * 修改会员(密码为空则不改密码) |
| | | */ |
| | | public int updateAccountUser(AccountUser accountUser); |
| | | |
| | | /** |
| | | * 批量逻辑删除会员 |
| | | */ |
| | | public int deleteAccountUserByIds(Long[] userIds); |
| | | } |
| New file |
| | |
| | | package com.ruoyi.user.service.impl; |
| | | |
| | | import java.util.List; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import com.ruoyi.common.core.constant.UserConstants; |
| | | import com.ruoyi.common.core.utils.StringUtils; |
| | | import com.ruoyi.common.security.utils.SecurityUtils; |
| | | import com.ruoyi.user.domain.AccountUser; |
| | | import com.ruoyi.user.mapper.AccountUserMapper; |
| | | import com.ruoyi.user.service.IAccountUserService; |
| | | |
| | | /** |
| | | * 会员用户 业务层实现 |
| | | * |
| | | * @author ruoyi |
| | | */ |
| | | @Service |
| | | public class AccountUserServiceImpl implements IAccountUserService |
| | | { |
| | | @Autowired |
| | | private AccountUserMapper accountUserMapper; |
| | | |
| | | @Override |
| | | public AccountUser selectAccountUserById(Long userId) |
| | | { |
| | | return accountUserMapper.selectAccountUserById(userId); |
| | | } |
| | | |
| | | @Override |
| | | public List<AccountUser> selectAccountUserList(AccountUser accountUser) |
| | | { |
| | | return accountUserMapper.selectAccountUserList(accountUser); |
| | | } |
| | | |
| | | @Override |
| | | public boolean checkUsernameUnique(AccountUser accountUser) |
| | | { |
| | | Long userId = StringUtils.isNull(accountUser.getUserId()) ? -1L : accountUser.getUserId(); |
| | | AccountUser info = accountUserMapper.selectAccountUserByUsername(accountUser.getUserName()); |
| | | if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) |
| | | { |
| | | return UserConstants.NOT_UNIQUE; |
| | | } |
| | | return UserConstants.UNIQUE; |
| | | } |
| | | |
| | | @Override |
| | | public boolean checkPhoneUnique(AccountUser accountUser) |
| | | { |
| | | // 手机号非必填,为空时不做唯一性校验,否则会与库里其它空手机号记录相撞 |
| | | if (StringUtils.isEmpty(accountUser.getPhone())) |
| | | { |
| | | return UserConstants.UNIQUE; |
| | | } |
| | | Long userId = StringUtils.isNull(accountUser.getUserId()) ? -1L : accountUser.getUserId(); |
| | | AccountUser info = accountUserMapper.selectAccountUserByPhone(accountUser.getPhone()); |
| | | if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) |
| | | { |
| | | return UserConstants.NOT_UNIQUE; |
| | | } |
| | | return UserConstants.UNIQUE; |
| | | } |
| | | |
| | | @Override |
| | | public int insertAccountUser(AccountUser accountUser) |
| | | { |
| | | accountUser.setPassword(SecurityUtils.encryptPassword(accountUser.getPassword())); |
| | | return accountUserMapper.insertAccountUser(accountUser); |
| | | } |
| | | |
| | | @Override |
| | | public int updateAccountUser(AccountUser accountUser) |
| | | { |
| | | // 不为空才加密;为空时保持 null,mapper 的 <if> 会跳过该列,原密码不受影响 |
| | | if (StringUtils.isNotEmpty(accountUser.getPassword())) |
| | | { |
| | | accountUser.setPassword(SecurityUtils.encryptPassword(accountUser.getPassword())); |
| | | } |
| | | return accountUserMapper.updateAccountUser(accountUser); |
| | | } |
| | | |
| | | @Override |
| | | public int deleteAccountUserByIds(Long[] userIds) |
| | | { |
| | | return accountUserMapper.deleteAccountUserByIds(userIds); |
| | | } |
| | | } |
| New file |
| | |
| | | Spring Boot Version: ${spring-boot.version} |
| | | Spring Application Name: ${spring.application.name} |
| | | _ |
| | | (_) |
| | | _ __ _ _ ___ _ _ _ ______ __ _ ___ _ __ |
| | | | '__|| | | | / _ \ | | | || ||______| / _` | / _ \| '_ \ |
| | | | | | |_| || (_) || |_| || | | (_| || __/| | | | |
| | | |_| \__,_| \___/ \__, ||_| \__, | \___||_| |_| |
| | | __/ | __/ | |
| | | |___/ |___/ |
| New file |
| | |
| | | # Tomcat |
| | | server: |
| | | port: 9210 |
| | | |
| | | # Spring |
| | | spring: |
| | | application: |
| | | # 应用名称 |
| | | name: ruoyi-user |
| | | profiles: |
| | | # 环境配置 |
| | | active: dev |
| | | cloud: |
| | | nacos: |
| | | discovery: |
| | | # 服务注册地址 |
| | | server-addr: 127.0.0.1:8848 |
| | | config: |
| | | # 配置中心地址 |
| | | server-addr: 127.0.0.1:8848 |
| | | config: |
| | | # 配置文件格式 |
| | | file-extension: yml |
| | | # 数据源、mybatis、springdoc 全在 Nacos,此处只声明要加载哪两份配置 |
| | | import: |
| | | - nacos:application-${spring.profiles.active}.${spring.config.file-extension} |
| | | - nacos:${spring.application.name}-${spring.profiles.active}.${spring.config.file-extension} |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <configuration scan="true" scanPeriod="60 seconds" debug="false"> |
| | | <!-- 日志存放路径 --> |
| | | <property name="log.path" value="logs/ruoyi-user" /> |
| | | <!-- 日志输出格式 --> |
| | | <property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> |
| | | |
| | | <!-- 控制台输出 --> |
| | | <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> |
| | | <encoder> |
| | | <pattern>${log.pattern}</pattern> |
| | | </encoder> |
| | | </appender> |
| | | |
| | | <!-- 系统日志输出 --> |
| | | <appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
| | | <file>${log.path}/info.log</file> |
| | | <!-- 循环政策:基于时间创建日志文件 --> |
| | | <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
| | | <!-- 日志文件名格式 --> |
| | | <fileNamePattern>${log.path}/info.%d{yyyy-MM-dd}.log</fileNamePattern> |
| | | <!-- 日志最大的历史 60天 --> |
| | | <maxHistory>60</maxHistory> |
| | | </rollingPolicy> |
| | | <encoder> |
| | | <pattern>${log.pattern}</pattern> |
| | | </encoder> |
| | | <filter class="ch.qos.logback.classic.filter.LevelFilter"> |
| | | <!-- 过滤的级别 --> |
| | | <level>INFO</level> |
| | | <!-- 匹配时的操作:接收(记录) --> |
| | | <onMatch>ACCEPT</onMatch> |
| | | <!-- 不匹配时的操作:拒绝(不记录) --> |
| | | <onMismatch>DENY</onMismatch> |
| | | </filter> |
| | | </appender> |
| | | |
| | | <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
| | | <file>${log.path}/error.log</file> |
| | | <!-- 循环政策:基于时间创建日志文件 --> |
| | | <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
| | | <!-- 日志文件名格式 --> |
| | | <fileNamePattern>${log.path}/error.%d{yyyy-MM-dd}.log</fileNamePattern> |
| | | <!-- 日志最大的历史 60天 --> |
| | | <maxHistory>60</maxHistory> |
| | | </rollingPolicy> |
| | | <encoder> |
| | | <pattern>${log.pattern}</pattern> |
| | | </encoder> |
| | | <filter class="ch.qos.logback.classic.filter.LevelFilter"> |
| | | <!-- 过滤的级别 --> |
| | | <level>ERROR</level> |
| | | <!-- 匹配时的操作:接收(记录) --> |
| | | <onMatch>ACCEPT</onMatch> |
| | | <!-- 不匹配时的操作:拒绝(不记录) --> |
| | | <onMismatch>DENY</onMismatch> |
| | | </filter> |
| | | </appender> |
| | | |
| | | <!-- 系统模块日志级别控制 --> |
| | | <logger name="com.ruoyi" level="info" /> |
| | | <!-- Spring日志级别控制 --> |
| | | <logger name="org.springframework" level="warn" /> |
| | | |
| | | <root level="info"> |
| | | <appender-ref ref="console" /> |
| | | </root> |
| | | |
| | | <!--系统操作日志--> |
| | | <root level="info"> |
| | | <appender-ref ref="file_info" /> |
| | | <appender-ref ref="file_error" /> |
| | | </root> |
| | | </configuration> |
| New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8" ?> |
| | | <!DOCTYPE mapper |
| | | PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" |
| | | "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| | | <mapper namespace="com.ruoyi.user.mapper.AccountUserMapper"> |
| | | |
| | | <resultMap type="AccountUser" id="AccountUserResult"> |
| | | <id property="userId" column="user_id" /> |
| | | <result property="userName" column="username" /> |
| | | <result property="phone" column="phone" /> |
| | | <result property="password" column="password" /> |
| | | <result property="nickname" column="nickname" /> |
| | | <result property="avatar" column="avatar" /> |
| | | <result property="gender" column="gender" /> |
| | | <result property="birthday" column="birthday" /> |
| | | <result property="status" column="status" /> |
| | | <result property="delFlag" column="del_flag" /> |
| | | <result property="createBy" column="create_by" /> |
| | | <result property="createTime" column="create_time" /> |
| | | <result property="updateBy" column="update_by" /> |
| | | <result property="updateTime" column="update_time" /> |
| | | <result property="remark" column="remark" /> |
| | | </resultMap> |
| | | |
| | | <sql id="selectAccountUserVo"> |
| | | select user_id, username, phone, password, nickname, avatar, gender, birthday, status, del_flag, create_by, create_time, update_by, update_time, remark |
| | | from account_user |
| | | </sql> |
| | | |
| | | <select id="selectAccountUserList" parameterType="AccountUser" resultMap="AccountUserResult"> |
| | | <include refid="selectAccountUserVo"/> |
| | | <where> |
| | | del_flag = '0' |
| | | <if test="userName != null and userName != ''"> and username like concat('%', #{userName}, '%')</if> |
| | | <if test="phone != null and phone != ''"> and phone like concat('%', #{phone}, '%')</if> |
| | | <if test="nickname != null and nickname != ''"> and nickname like concat('%', #{nickname}, '%')</if> |
| | | <if test="gender != null and gender != ''"> and gender = #{gender}</if> |
| | | <if test="status != null and status != ''"> and status = #{status}</if> |
| | | <if test="params.beginTime != null and params.beginTime != ''"> |
| | | and date_format(create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') |
| | | </if> |
| | | <if test="params.endTime != null and params.endTime != ''"> |
| | | and date_format(create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') |
| | | </if> |
| | | </where> |
| | | order by user_id desc |
| | | </select> |
| | | |
| | | <select id="selectAccountUserById" parameterType="Long" resultMap="AccountUserResult"> |
| | | <include refid="selectAccountUserVo"/> |
| | | where del_flag = '0' and user_id = #{userId} |
| | | </select> |
| | | |
| | | <select id="selectAccountUserByUsername" parameterType="String" resultMap="AccountUserResult"> |
| | | <include refid="selectAccountUserVo"/> |
| | | where del_flag = '0' and username = #{userName} |
| | | </select> |
| | | |
| | | <select id="selectAccountUserByPhone" parameterType="String" resultMap="AccountUserResult"> |
| | | <include refid="selectAccountUserVo"/> |
| | | where del_flag = '0' and phone = #{phone} |
| | | </select> |
| | | |
| | | <insert id="insertAccountUser" parameterType="AccountUser" useGeneratedKeys="true" keyProperty="userId"> |
| | | insert into account_user( |
| | | <if test="userName != null and userName != ''">username,</if> |
| | | <if test="phone != null and phone != ''">phone,</if> |
| | | <if test="password != null and password != ''">password,</if> |
| | | <if test="nickname != null and nickname != ''">nickname,</if> |
| | | <if test="avatar != null and avatar != ''">avatar,</if> |
| | | <if test="gender != null and gender != ''">gender,</if> |
| | | <if test="birthday != null">birthday,</if> |
| | | <if test="status != null and status != ''">status,</if> |
| | | <if test="remark != null">remark,</if> |
| | | <if test="createBy != null and createBy != ''">create_by,</if> |
| | | create_time |
| | | )values( |
| | | <if test="userName != null and userName != ''">#{userName},</if> |
| | | <if test="phone != null and phone != ''">#{phone},</if> |
| | | <if test="password != null and password != ''">#{password},</if> |
| | | <if test="nickname != null and nickname != ''">#{nickname},</if> |
| | | <if test="avatar != null and avatar != ''">#{avatar},</if> |
| | | <if test="gender != null and gender != ''">#{gender},</if> |
| | | <if test="birthday != null">#{birthday},</if> |
| | | <if test="status != null and status != ''">#{status},</if> |
| | | <if test="remark != null">#{remark},</if> |
| | | <if test="createBy != null and createBy != ''">#{createBy},</if> |
| | | sysdate() |
| | | ) |
| | | </insert> |
| | | |
| | | <update id="updateAccountUser" parameterType="AccountUser"> |
| | | update account_user |
| | | <set> |
| | | <if test="userName != null and userName != ''">username = #{userName},</if> |
| | | <if test="phone != null and phone != ''">phone = #{phone},</if> |
| | | <if test="password != null and password != ''">password = #{password},</if> |
| | | <if test="nickname != null">nickname = #{nickname},</if> |
| | | <if test="avatar != null">avatar = #{avatar},</if> |
| | | <if test="gender != null and gender != ''">gender = #{gender},</if> |
| | | <if test="birthday != null">birthday = #{birthday},</if> |
| | | <if test="status != null and status != ''">status = #{status},</if> |
| | | <if test="remark != null">remark = #{remark},</if> |
| | | <if test="updateBy != null">update_by = #{updateBy},</if> |
| | | update_time = sysdate() |
| | | </set> |
| | | where user_id = #{userId} and del_flag = '0' |
| | | </update> |
| | | |
| | | <!-- 逻辑删除:保留行,仅置删除标志 --> |
| | | <update id="deleteAccountUserById" parameterType="Long"> |
| | | update account_user set del_flag = '2' where user_id = #{userId} |
| | | </update> |
| | | |
| | | <update id="deleteAccountUserByIds" parameterType="Long"> |
| | | update account_user set del_flag = '2' where user_id in |
| | | <foreach item="userId" collection="array" open="(" separator="," close=")"> |
| | | #{userId} |
| | | </foreach> |
| | | </update> |
| | | |
| | | </mapper> |
| New file |
| | |
| | | -- ---------------------------- |
| | | -- C 端会员用户表(ruoyi-user 用户服务) |
| | | -- |
| | | -- 目标库 hugray-account 由使用方预先创建(utf8mb4)。 |
| | | -- 注意:库名含连字符,任何引用都必须用反引号。 |
| | | -- ---------------------------- |
| | | |
| | | USE `hugray-account`; |
| | | |
| | | DROP TABLE IF EXISTS `account_user`; |
| | | CREATE TABLE `account_user` ( |
| | | `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '会员ID', |
| | | `username` varchar(64) NOT NULL COMMENT '用户名', |
| | | `phone` varchar(20) DEFAULT NULL COMMENT '手机号', |
| | | `password` varchar(100) DEFAULT NULL COMMENT '密码(BCrypt)', |
| | | `nickname` varchar(64) DEFAULT NULL COMMENT '昵称', |
| | | `avatar` varchar(255) DEFAULT NULL COMMENT '头像地址', |
| | | `gender` char(1) DEFAULT '2' COMMENT '性别(0男 1女 2未知,对齐 sys_user_sex 字典)', |
| | | `birthday` date DEFAULT NULL COMMENT '生日', |
| | | `status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)', |
| | | `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 2删除)', |
| | | `create_by` varchar(64) DEFAULT '' COMMENT '创建者', |
| | | `create_time` datetime DEFAULT NULL COMMENT '创建时间', |
| | | `update_by` varchar(64) DEFAULT '' COMMENT '更新者', |
| | | `update_time` datetime DEFAULT NULL COMMENT '更新时间', |
| | | `remark` varchar(500) DEFAULT NULL COMMENT '备注', |
| | | PRIMARY KEY (`user_id`), |
| | | -- 刻意不加 username 唯一索引:删除是逻辑删除(del_flag=2),残留行会永久占用用户名, |
| | | -- 与「服务层只校验 del_flag='0' 的记录」冲突,导致新增时报 500。此处对齐上游 |
| | | -- sys_user 的做法(ry_20260417.sql 中 sys_user 仅有主键),唯一性由 |
| | | -- AccountUserServiceImpl.checkUsernameUnique 单一权威保证。 |
| | | KEY `idx_account_user_username` (`username`), |
| | | KEY `idx_account_user_phone` (`phone`) |
| | | ) ENGINE=InnoDB AUTO_INCREMENT=100 DEFAULT CHARSET=utf8mb4 COMMENT='C端会员用户表'; |
| New file |
| | |
| | | -- ---------------------------- |
| | | -- 用户服务(C 端会员)菜单 |
| | | -- |
| | | -- 目标库为业务库 hugray(与 sys_menu 同库)。 |
| | | -- 号段取 2100~2106:现有最大 menu_id 为 1060,此段与之不冲突。 |
| | | -- |
| | | -- 不需要写 sys_role_menu:超级管理员在 SysMenuServiceImpl 里走 |
| | | -- selectMenuTreeAll() / selectMenuList() 全量返回,与角色菜单表无关。 |
| | | -- 若要授权给非 admin 角色,再自行插 sys_role_menu。 |
| | | -- ---------------------------- |
| | | |
| | | USE `hugray`; |
| | | |
| | | -- 可重复执行:先清掉本号段,再插入 |
| | | DELETE FROM `sys_menu` WHERE `menu_id` BETWEEN 2100 AND 2106; |
| | | |
| | | INSERT INTO `sys_menu` |
| | | (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `route_name`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) |
| | | VALUES |
| | | (2100, '用户服务', 0, 5, 'user', NULL, NULL, '', 1, 0, 'M', '0', '0', '', 'user', 'admin', sysdate(), '', NULL, '用户服务目录'), |
| | | (2101, '会员管理', 2100, 1, 'account', 'user/account/index', NULL, '', 1, 0, 'C', '0', '0', 'account:user:list', 'peoples', 'admin', sysdate(), '', NULL, '会员管理菜单'), |
| | | (2102, '会员查询', 2101, 1, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'account:user:query', '#', 'admin', sysdate(), '', NULL, ''), |
| | | (2103, '会员新增', 2101, 2, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'account:user:add', '#', 'admin', sysdate(), '', NULL, ''), |
| | | (2104, '会员修改', 2101, 3, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'account:user:edit', '#', 'admin', sysdate(), '', NULL, ''), |
| | | (2105, '会员删除', 2101, 4, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'account:user:remove','#', 'admin', sysdate(), '', NULL, ''), |
| | | (2106, '会员导出', 2101, 5, '', NULL, NULL, '', 1, 0, 'F', '0', '0', 'account:user:export','#', 'admin', sysdate(), '', NULL, ''); |