Snapshot friend_back worktree for local merge
Source HEAD: 9d7e220f14
Includes uncommitted project changes and new project files.
Align shared text line endings and executable flags with Friendship-and-chat-api.
Normalize new text to LF; exclude .workbuddy local assistant memory.
Original friend_back checkout is unchanged.
This commit is contained in:
1 parent
9d7e220f14
commit
04bac15e59
30 files changed
+811
-4
No files matched your search
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""骑遇骑行记录:建表 + 模拟数据(chat_v1 库)。可重复执行(幂等:表已存在跳过,模拟数据按标题去重)。"""
|
||||
import json
|
||||
import math
|
||||
import pymysql
|
||||
|
||||
DB = dict(host='139.224.25.207', port=3306, user='chat_v1',
|
||||
password='BpJ2Ebt4zMPjBcCL', database='chat_v1', charset='utf8mb4',
|
||||
connect_timeout=15)
|
||||
|
||||
DDL = [
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `member_ride_record` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
|
||||
`user_id` bigint(20) NOT NULL COMMENT '骑手编号 member_user.id',
|
||||
`title` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '战报标题',
|
||||
`road_name` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '路线名(如:南昆山)',
|
||||
`corner_name` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '弯道名(如:观音潭右弯),空表示非跑山记录',
|
||||
`distance_km` decimal(8,1) NOT NULL COMMENT '里程(公里)',
|
||||
`duration_sec` int(11) NOT NULL COMMENT '骑行时长(秒)',
|
||||
`top_speed_kmh` decimal(5,1) NOT NULL COMMENT '极速(km/h)',
|
||||
`curve_count` int(11) NOT NULL DEFAULT '0' COMMENT '过弯次数',
|
||||
`max_lean` decimal(4,1) NOT NULL COMMENT '最大压弯角度(度)',
|
||||
`track_json` mediumtext COLLATE utf8mb4_unicode_ci COMMENT '轨迹点 JSON [{lat,lng,speed}],仅详情接口返回',
|
||||
`like_count` int(11) NOT NULL DEFAULT '0' COMMENT '点赞数(冗余计数)',
|
||||
`report_count` int(11) NOT NULL DEFAULT '0' COMMENT '被举报次数',
|
||||
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '状态:0 正常 1 已下架',
|
||||
`tenant_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '租户编号',
|
||||
`creator` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user` (`user_id`),
|
||||
KEY `idx_rank` (`road_name`, `corner_name`, `max_lean`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='骑遇骑行记录(战报)'
|
||||
""",
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS `member_ride_record_like` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
|
||||
`record_id` bigint(20) NOT NULL COMMENT '战报编号 member_ride_record.id',
|
||||
`user_id` bigint(20) NOT NULL COMMENT '点赞人编号 member_user.id',
|
||||
`tenant_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '租户编号',
|
||||
`creator` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_record_user` (`record_id`, `user_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='骑遇骑行战报点赞'
|
||||
""",
|
||||
]
|
||||
|
||||
# (user_id, title, road, corner, km, sec, top, curves, max_lean, days_ago, like_user_ids)
|
||||
MOCK = [
|
||||
(131, '南昆山 63 连弯,今天左弯终于不虚了', '南昆山', '观音潭右弯', 87, 5760, 138, 63, 52.0, 1, [133, 132, 134]),
|
||||
(133, '清晨跑山,观音潭右弯刷出个人最佳', '南昆山', '观音潭右弯', 84, 5400, 132, 58, 49.5, 2, [131, 129]),
|
||||
(129, '压弯一时爽,一直压弯一直爽', '南昆山', '观音潭右弯', 86, 5900, 129, 61, 46.0, 4, [131]),
|
||||
(132, '第一次跑南昆山,右弯还是不敢深压', '南昆山', '观音潭右弯', 88, 6300, 112, 57, 33.5, 5, [134]),
|
||||
(131, '连续 S 弯练车,大腿已废', '南昆山', '连续 S 弯', 52, 3900, 118, 41, 44.5, 1, [133, 129]),
|
||||
(133, 'S 弯 41 连过,人车合一', '南昆山', '连续 S 弯', 52, 3950, 112, 41, 40.0, 3, [131, 134, 132]),
|
||||
(129, '大夫山夜骑放风,发卡弯有点意思', '大夫山', '发卡弯', 44, 3660, 105, 38, 43.0, 1, [131, 133]),
|
||||
(131, '大夫山发卡弯,极速压到 43 度', '大夫山', '发卡弯', 43, 3500, 108, 35, 43.2, 3, [133]),
|
||||
(134, '傍晚放风,夕阳配弯道,舒服', '大夫山', '发卡弯', 44, 3800, 98, 36, 29.0, 4, [132]),
|
||||
(131, '罗浮山风门坳长弯,全程 6 档', '罗浮山', '风门坳长弯', 121, 7680, 121, 22, 39.0, 2, [133, 129]),
|
||||
(133, '风门坳长弯磨膝体验,就一次', '罗浮山', '风门坳长弯', 118, 7500, 126, 20, 47.5, 6, [131]),
|
||||
(129, '周末摩旅,156 公里赶到营地', '', '', 156, 7680, 121, 22, 25.0, 3, [131, 133, 132, 134]),
|
||||
(133, '市区通勤顺路兜风,绿道休闲骑', '', '', 32, 3000, 85, 12, 18.5, 1, [131]),
|
||||
(132, '新手第一份战报,求带飞', '', '', 26, 2700, 76, 9, 15.0, 2, [134]),
|
||||
]
|
||||
|
||||
|
||||
def track_points(seed: int) -> str:
|
||||
"""生成一个小环形轨迹 JSON(约 60 点),让战报详情有图可画。"""
|
||||
r = 0.004 + (seed % 7) * 0.0004
|
||||
pts = []
|
||||
n = 60
|
||||
for i in range(n):
|
||||
t = i / n * math.pi * 4
|
||||
radius = r + r * 0.35 * math.sin(t * 2.3 + seed)
|
||||
lat = 23.17 + seed * 0.002 + radius * math.cos(t)
|
||||
lng = 113.36 + seed * 0.003 + radius * 1.4 * math.sin(t)
|
||||
speed = round(40 + 60 * (0.5 + 0.5 * math.sin(t * 1.7 + seed)), 1)
|
||||
pts.append({'lat': round(lat, 6), 'lng': round(lng, 6), 'speed': speed})
|
||||
return json.dumps(pts, separators=(',', ':'))
|
||||
|
||||
|
||||
def main():
|
||||
conn = pymysql.connect(**DB)
|
||||
cur = conn.cursor()
|
||||
|
||||
for ddl in DDL:
|
||||
cur.execute(ddl)
|
||||
conn.commit()
|
||||
print('DDL ok')
|
||||
|
||||
inserted = 0
|
||||
for idx, (uid, title, road, corner, km, sec, top, curves, lean, days_ago, likers) in enumerate(MOCK):
|
||||
cur.execute("SELECT id FROM member_ride_record WHERE title=%s AND deleted=0", (title,))
|
||||
if cur.fetchone():
|
||||
print('skip (exists):', title)
|
||||
continue
|
||||
cur.execute(
|
||||
"""INSERT INTO member_ride_record
|
||||
(user_id, title, road_name, corner_name, distance_km, duration_sec,
|
||||
top_speed_kmh, curve_count, max_lean, track_json, like_count, report_count,
|
||||
status, tenant_id, creator, create_time)
|
||||
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,0,0,1,%s,
|
||||
DATE_SUB(NOW(), INTERVAL %s DAY) - INTERVAL %s HOUR)""",
|
||||
(uid, title, road, corner, km, sec, top, curves, lean,
|
||||
track_points(idx), len(likers), uid, days_ago, (idx * 3) % 20))
|
||||
record_id = cur.lastrowid
|
||||
for liker in likers:
|
||||
cur.execute(
|
||||
"""INSERT IGNORE INTO member_ride_record_like
|
||||
(record_id, user_id, tenant_id, creator, create_time)
|
||||
VALUES (%s,%s,1,%s, DATE_SUB(NOW(), INTERVAL 1 DAY))""",
|
||||
(record_id, liker, uid))
|
||||
inserted += 1
|
||||
print('inserted:', title)
|
||||
conn.commit()
|
||||
|
||||
cur.execute("SELECT COUNT(*) FROM member_ride_record WHERE deleted=0")
|
||||
print('total records:', cur.fetchone()[0])
|
||||
cur.execute("SELECT road_name, corner_name, COUNT(*) FROM member_ride_record "
|
||||
"WHERE deleted=0 AND corner_name<>'' GROUP BY road_name, corner_name")
|
||||
for r in cur.fetchall():
|
||||
print('board:', r)
|
||||
conn.close()
|
||||
print('done, inserted =', inserted)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,17 @@
|
||||
-- 后台菜单与授权:子账号管理 + 会员管理拆分(男号/女号)
|
||||
-- 执行库:chat_v1
|
||||
-- 1) 新增菜单(幂等:先删后插)
|
||||
DELETE FROM system_menu WHERE id IN (5810, 5820, 5821);
|
||||
INSERT INTO system_menu (id, name, permission, type, sort, parent_id, path, icon, component, component_name, status, visible, keep_alive, always_show, creator, updater, deleted)
|
||||
VALUES
|
||||
(5810, '子账号管理', 'system:sub-account:manage', 2, 20, 0, '/sub-account', 'ep:user', 'system/subaccount/index', 'SystemSubAccount', 0, b'1', b'1', b'1', '1', '1', b'0'),
|
||||
(5820, '男号管理', 'member:user:query', 2, 1, 2262, 'male-user', 'ep:male', 'member/user/male', 'MemberUserMale', 0, b'1', b'1', b'1', '1', '1', b'0'),
|
||||
(5821, '女号管理', 'member:user:query', 2, 2, 2262, 'female-user', 'ep:female', 'member/user/female', 'MemberUserFemale', 0, b'1', b'1', b'1', '1', '1', b'0');
|
||||
|
||||
-- 2) 授权给「APP管理员」角色(AppHolder 当前使用的角色)
|
||||
DELETE FROM system_role_menu WHERE role_id = 158 AND menu_id IN (5810, 5820, 5821);
|
||||
INSERT INTO system_role_menu (role_id, menu_id, creator, updater, deleted, tenant_id)
|
||||
VALUES
|
||||
(158, 5810, '1', '1', b'0', 1),
|
||||
(158, 5820, '1', '1', b'0', 1),
|
||||
(158, 5821, '1', '1', b'0', 1);
|
||||
@@ -0,0 +1,17 @@
|
||||
-- 子账号管理:holder 与 子账号/专属角色 的绑定关系
|
||||
-- 执行位置:chat_v1 库
|
||||
CREATE TABLE IF NOT EXISTS `system_sub_account` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
|
||||
`holder_user_id` bigint NOT NULL COMMENT '管理者用户编号(system_users.id)',
|
||||
`sub_user_id` bigint NOT NULL COMMENT '子账号用户编号(system_users.id)',
|
||||
`role_id` bigint NOT NULL COMMENT '子账号专属角色编号(system_role.id)',
|
||||
`creator` varchar(64) NULL DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updater` varchar(64) NULL DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
|
||||
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_holder_user_id` (`holder_user_id`),
|
||||
KEY `idx_sub_user_id` (`sub_user_id`)
|
||||
) ENGINE = InnoDB COMMENT '后台子账号表';
|
||||
+6
@@ -41,6 +41,12 @@ public class MemberUserPageReqVO extends PageParam {
|
||||
@Schema(description = "用户分组编号", example = "1")
|
||||
private Long groupId;
|
||||
|
||||
@Schema(description = "用户 Code(App 我的页面展示的 ID)", example = "924199")
|
||||
private String userCode;
|
||||
|
||||
@Schema(description = "性别:1 男 2 女", example = "1")
|
||||
private Integer sex;
|
||||
|
||||
// TODO 芋艿:注册用户类型;
|
||||
|
||||
// TODO 芋艿:登录用户类型;
|
||||
|
||||
+2
@@ -92,6 +92,8 @@ public interface MemberUserMapper extends BaseMapperX<MemberUserDO> {
|
||||
.betweenIfPresent(MemberUserDO::getCreateTime, reqVO.getCreateTime())
|
||||
.eqIfPresent(MemberUserDO::getLevelId, reqVO.getLevelId())
|
||||
.eqIfPresent(MemberUserDO::getGroupId, reqVO.getGroupId())
|
||||
.eqIfPresent(MemberUserDO::getUserCode, reqVO.getUserCode())
|
||||
.eqIfPresent(MemberUserDO::getSex, reqVO.getSex())
|
||||
.apply(StrUtil.isNotEmpty(tagIdSql), tagIdSql)
|
||||
.orderByDesc(MemberUserDO::getId));
|
||||
}
|
||||
|
||||
+21
@@ -63,6 +63,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
|
||||
import cn.iocoder.yudao.module.member.dal.mysql.recent.RecentMapper;
|
||||
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
@@ -83,6 +84,14 @@ public class RecentServiceImpl implements RecentService {
|
||||
@Resource
|
||||
private RecentMapper recentMapper;
|
||||
@Resource
|
||||
private MemberUserMapper memberUserMapper;
|
||||
|
||||
/**
|
||||
* 首页(广场/附近)用户列表不可见账号:这些手机号的用户不会出现在首页用户列表中。
|
||||
* 如需增减隐藏账号,改这个列表即可。
|
||||
*/
|
||||
private static final List<String> SQUARE_HIDDEN_MOBILES = Arrays.asList("13311615193", "18800000001");
|
||||
@Resource
|
||||
private OperationMapper operationMapper;
|
||||
|
||||
@Resource
|
||||
@@ -497,6 +506,18 @@ public class RecentServiceImpl implements RecentService {
|
||||
RecentPageReqVO resultQuery = BeanUtil.toBean(bean, RecentPageReqVO.class);
|
||||
resultQuery.setSceneBizType(bean.getScene().getType());
|
||||
quickBeforeQuery(operationUser, operationCfg, resultQuery);
|
||||
// 首页不可见账号:按手机号定位,合并进排除列表(广场/附近所有 tab 均不出现)
|
||||
List<Long> excludeIds = resultQuery.getExcludeUserIdList() != null
|
||||
? new ArrayList<>(resultQuery.getExcludeUserIdList()) : new ArrayList<>();
|
||||
for (String hiddenMobile : SQUARE_HIDDEN_MOBILES) {
|
||||
MemberUserDO hiddenUser = memberUserMapper.selectByMobile(hiddenMobile);
|
||||
if (hiddenUser != null && !excludeIds.contains(hiddenUser.getId())) {
|
||||
excludeIds.add(hiddenUser.getId());
|
||||
}
|
||||
}
|
||||
if (!excludeIds.isEmpty()) {
|
||||
resultQuery.setExcludeUserIdList(excludeIds);
|
||||
}
|
||||
// 广场-最近
|
||||
if (ObjectUtil.equals(bean.getScene(), MemberRecentSceneEnum.SQUARE_NEW_TIME)) {
|
||||
resultQuery.setDistanceIsNotNull(true);
|
||||
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
+6
@@ -167,4 +167,10 @@ public interface ErrorCodeConstants {
|
||||
// ========== 站内信发送 1-002-028-000 ==========
|
||||
ErrorCode NOTIFY_SEND_TEMPLATE_PARAM_MISS = new ErrorCode(1_002_028_000, "模板参数({})缺失");
|
||||
|
||||
// ========== 子账号管理 1-002-030-000 =========
|
||||
ErrorCode SUB_ACCOUNT_NOT_EXISTS = new ErrorCode(1_002_030_000, "子账号不存在");
|
||||
ErrorCode SUB_ACCOUNT_NOT_OWNER = new ErrorCode(1_002_030_001, "无权操作该子账号");
|
||||
ErrorCode SUB_ACCOUNT_MENU_EMPTY = new ErrorCode(1_002_030_002, "请至少勾选一个当前账号拥有的菜单");
|
||||
ErrorCode SUB_ACCOUNT_HOLDER_MENU_EMPTY = new ErrorCode(1_002_030_003, "当前账号未拥有任何菜单,无法创建子账号");
|
||||
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.subaccount;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.subaccount.vo.*;
|
||||
import cn.iocoder.yudao.module.system.service.subaccount.SubAccountService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
/**
|
||||
* 后台子账号管理 Controller
|
||||
*
|
||||
* 供 AppHolder 管理自己的子账号:创建、分配菜单、禁用、重置密码、删除。
|
||||
*/
|
||||
@Tag(name = "管理后台 - 子账号管理")
|
||||
@RestController
|
||||
@RequestMapping("/system/sub-account")
|
||||
@Validated
|
||||
public class SubAccountController {
|
||||
|
||||
@Resource
|
||||
private SubAccountService subAccountService;
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "获得子账号列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:sub-account:manage')")
|
||||
public CommonResult<List<SubAccountRespVO>> getSubAccountList() {
|
||||
return success(subAccountService.getSubAccountList());
|
||||
}
|
||||
|
||||
@GetMapping("/menu-list")
|
||||
@Operation(summary = "获得当前账号拥有的菜单(用于给子账号勾选)")
|
||||
@PreAuthorize("@ss.hasPermission('system:sub-account:manage')")
|
||||
public CommonResult<List<SubAccountMenuRespVO>> getHolderMenuList() {
|
||||
return success(subAccountService.getHolderMenuList());
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建子账号")
|
||||
@PreAuthorize("@ss.hasPermission('system:sub-account:manage')")
|
||||
public CommonResult<Long> createSubAccount(@Valid @RequestBody SubAccountCreateReqVO reqVO) {
|
||||
return success(subAccountService.createSubAccount(reqVO, reqVO.getPassword()));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改子账号(昵称 + 可见菜单)")
|
||||
@PreAuthorize("@ss.hasPermission('system:sub-account:manage')")
|
||||
public CommonResult<Boolean> updateSubAccount(@RequestParam("userId") Long userId,
|
||||
@Valid @RequestBody SubAccountSaveReqVO reqVO) {
|
||||
subAccountService.updateSubAccount(userId, reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-status")
|
||||
@Operation(summary = "修改子账号状态")
|
||||
@PreAuthorize("@ss.hasPermission('system:sub-account:manage')")
|
||||
public CommonResult<Boolean> updateSubAccountStatus(@Valid @RequestBody SubAccountUpdateStatusReqVO reqVO) {
|
||||
subAccountService.updateSubAccountStatus(reqVO.getUserId(), reqVO.getStatus());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/reset-password")
|
||||
@Operation(summary = "重置子账号密码")
|
||||
@PreAuthorize("@ss.hasPermission('system:sub-account:manage')")
|
||||
public CommonResult<Boolean> resetSubAccountPassword(@Valid @RequestBody SubAccountResetPasswordReqVO reqVO) {
|
||||
subAccountService.resetSubAccountPassword(reqVO.getUserId(), reqVO.getPassword());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除子账号")
|
||||
@Parameter(name = "userId", description = "子账号用户编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('system:sub-account:manage')")
|
||||
public CommonResult<Boolean> deleteSubAccount(@RequestParam("userId") Long userId) {
|
||||
subAccountService.deleteSubAccount(userId);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.subaccount.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
@Schema(description = "管理后台 - 子账号创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SubAccountCreateReqVO extends SubAccountSaveReqVO {
|
||||
|
||||
@Schema(description = "登录密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
|
||||
@Length(min = 4, max = 16, message = "密码长度为 4-16 位")
|
||||
private String password;
|
||||
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.subaccount.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - 子账号可用菜单 Response VO")
|
||||
@Data
|
||||
public class SubAccountMenuRespVO {
|
||||
|
||||
@Schema(description = "菜单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2262")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "父菜单编号", example = "0")
|
||||
private Long parentId;
|
||||
|
||||
@Schema(description = "菜单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "会员中心")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "菜单类型:1 目录 2 菜单 3 按钮", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "显示顺序", example = "1")
|
||||
private Integer sort;
|
||||
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.subaccount.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
@Schema(description = "管理后台 - 子账号重置密码 Request VO")
|
||||
@Data
|
||||
public class SubAccountResetPasswordReqVO {
|
||||
|
||||
@Schema(description = "子账号用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
@NotNull(message = "子账号编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "新密码", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
|
||||
@NotBlank(message = "新密码不能为空")
|
||||
@Size(min = 4, max = 16, message = "密码长度为 4-16 位")
|
||||
private String password;
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.subaccount.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
@Schema(description = "管理后台 - 子账号 Response VO")
|
||||
@Data
|
||||
public class SubAccountRespVO {
|
||||
|
||||
@Schema(description = "记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "子账号用户编号(system_users.id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "登录账号", requiredMode = Schema.RequiredMode.REQUIRED, example = "suboperator")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "昵称", example = "运营小号")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "状态:0 开启 1 禁用", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "最后登录时间")
|
||||
private LocalDateTime loginDate;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "可见菜单编号列表")
|
||||
private Set<Long> menuIds;
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.subaccount.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.util.Set;
|
||||
|
||||
@Schema(description = "管理后台 - 子账号创建/修改 Request VO")
|
||||
@Data
|
||||
public class SubAccountSaveReqVO {
|
||||
|
||||
@Schema(description = "子账号用户名(创建必填,字母+数字 4-30 位)", example = "suboperator")
|
||||
@Size(min = 4, max = 30, message = "用户账号长度为 4-30 个字符")
|
||||
private String username;
|
||||
|
||||
@Schema(description = "子账号昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "运营小号")
|
||||
@NotBlank(message = "子账号昵称不能为空")
|
||||
@Size(max = 30, message = "子账号昵称长度不能超过30个字符")
|
||||
private String nickname;
|
||||
|
||||
@Schema(description = "菜单编号列表(必须在当前登录账号拥有的菜单范围内)", example = "[2262, 2317]")
|
||||
private Set<Long> menuIds;
|
||||
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.subaccount.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 子账号状态修改 Request VO")
|
||||
@Data
|
||||
public class SubAccountUpdateStatusReqVO {
|
||||
|
||||
@Schema(description = "子账号用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
|
||||
@NotNull(message = "子账号编号不能为空")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "状态:0 开启 1 禁用", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package cn.iocoder.yudao.module.system.dal.dataobject.subaccount;
|
||||
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 后台子账号 DO
|
||||
*
|
||||
* AppHolder 创建的子账号与专属角色的绑定关系。
|
||||
* 子账号登录后台后可见的菜单 = 其专属角色被分配的菜单(由 holder 分配)。
|
||||
*/
|
||||
@TableName("system_sub_account")
|
||||
@KeySequence("system_sub_account_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SubAccountDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 管理者(holder)用户编号,system_users.id
|
||||
*/
|
||||
private Long holderUserId;
|
||||
/**
|
||||
* 子账号用户编号,system_users.id
|
||||
*/
|
||||
private Long subUserId;
|
||||
/**
|
||||
* 子账号专属角色编号,system_role.id
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.system.dal.mysql.subaccount;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.subaccount.SubAccountDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 后台子账号 Mapper
|
||||
*/
|
||||
@Mapper
|
||||
public interface SubAccountMapper extends BaseMapperX<SubAccountDO> {
|
||||
|
||||
default List<SubAccountDO> selectListByHolderUserId(Long holderUserId) {
|
||||
return selectList(new LambdaQueryWrapperX<SubAccountDO>()
|
||||
.eq(SubAccountDO::getHolderUserId, holderUserId)
|
||||
.orderByDesc(SubAccountDO::getId));
|
||||
}
|
||||
|
||||
default SubAccountDO selectBySubUserId(Long subUserId) {
|
||||
return selectOne(SubAccountDO::getSubUserId, subUserId);
|
||||
}
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
package cn.iocoder.yudao.module.system.service.subaccount;
|
||||
|
||||
import cn.iocoder.yudao.module.system.controller.admin.subaccount.vo.SubAccountMenuRespVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.subaccount.vo.SubAccountRespVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.subaccount.vo.SubAccountSaveReqVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 后台子账号 Service 接口
|
||||
*
|
||||
* AppHolder 在自己的权限范围内创建子账号,并分配子账号可见的菜单。
|
||||
*/
|
||||
public interface SubAccountService {
|
||||
|
||||
/**
|
||||
* 获得当前登录账号(holder)的子账号列表
|
||||
*
|
||||
* @return 子账号列表
|
||||
*/
|
||||
List<SubAccountRespVO> getSubAccountList();
|
||||
|
||||
/**
|
||||
* 获得当前登录账号(holder)拥有的菜单(用于给子账号勾选)
|
||||
*
|
||||
* @return 菜单列表
|
||||
*/
|
||||
List<SubAccountMenuRespVO> getHolderMenuList();
|
||||
|
||||
/**
|
||||
* 创建子账号(用户名 + 昵称 + 密码 + 可见菜单)
|
||||
*
|
||||
* @param reqVO 创建信息(password 需要传)
|
||||
* @return 子账号用户编号
|
||||
*/
|
||||
Long createSubAccount(SubAccountSaveReqVO reqVO, String password);
|
||||
|
||||
/**
|
||||
* 修改子账号(昵称 + 可见菜单)
|
||||
*
|
||||
* @param userId 子账号用户编号
|
||||
* @param reqVO 修改信息
|
||||
*/
|
||||
void updateSubAccount(Long userId, SubAccountSaveReqVO reqVO);
|
||||
|
||||
/**
|
||||
* 修改子账号状态(禁用后无法登录后台)
|
||||
*
|
||||
* @param userId 子账号用户编号
|
||||
* @param status 状态
|
||||
*/
|
||||
void updateSubAccountStatus(Long userId, Integer status);
|
||||
|
||||
/**
|
||||
* 重置子账号密码
|
||||
*
|
||||
* @param userId 子账号用户编号
|
||||
* @param password 新密码
|
||||
*/
|
||||
void resetSubAccountPassword(Long userId, String password);
|
||||
|
||||
/**
|
||||
* 删除子账号(连同专属角色)
|
||||
*
|
||||
* @param userId 子账号用户编号
|
||||
*/
|
||||
void deleteSubAccount(Long userId);
|
||||
|
||||
}
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
package cn.iocoder.yudao.module.system.service.subaccount;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.permission.vo.role.RoleSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.subaccount.vo.SubAccountMenuRespVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.subaccount.vo.SubAccountRespVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.subaccount.vo.SubAccountSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.subaccount.SubAccountDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.subaccount.SubAccountMapper;
|
||||
import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
|
||||
import cn.iocoder.yudao.module.system.service.permission.MenuService;
|
||||
import cn.iocoder.yudao.module.system.service.permission.PermissionService;
|
||||
import cn.iocoder.yudao.module.system.service.permission.RoleService;
|
||||
import cn.iocoder.yudao.module.system.service.tenant.TenantService;
|
||||
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
||||
|
||||
/**
|
||||
* 后台子账号 Service 实现类
|
||||
*/
|
||||
@Service
|
||||
@Validated
|
||||
public class SubAccountServiceImpl implements SubAccountService {
|
||||
|
||||
@Resource
|
||||
private SubAccountMapper subAccountMapper;
|
||||
@Resource
|
||||
private AdminUserService userService;
|
||||
@Resource
|
||||
private RoleService roleService;
|
||||
@Resource
|
||||
private PermissionService permissionService;
|
||||
@Resource
|
||||
private MenuService menuService;
|
||||
@Resource
|
||||
private TenantService tenantService;
|
||||
|
||||
@Override
|
||||
public List<SubAccountRespVO> getSubAccountList() {
|
||||
Long holderUserId = getLoginUserId();
|
||||
List<SubAccountDO> mappings = subAccountMapper.selectListByHolderUserId(holderUserId);
|
||||
List<SubAccountRespVO> result = new ArrayList<>();
|
||||
for (SubAccountDO mapping : mappings) {
|
||||
AdminUserDO user = userService.getUser(mapping.getSubUserId());
|
||||
if (user == null) { // 用户已被删除,跳过
|
||||
continue;
|
||||
}
|
||||
SubAccountRespVO vo = BeanUtils.toBean(mapping, SubAccountRespVO.class);
|
||||
vo.setUserId(user.getId());
|
||||
vo.setUsername(user.getUsername());
|
||||
vo.setNickname(user.getNickname());
|
||||
vo.setStatus(user.getStatus());
|
||||
vo.setLoginDate(user.getLoginDate());
|
||||
vo.setMenuIds(permissionService.getRoleMenuListByRoleId(mapping.getRoleId()));
|
||||
result.add(vo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SubAccountMenuRespVO> getHolderMenuList() {
|
||||
Set<Long> holderMenuIds = getHolderMenuIds(getLoginUserId());
|
||||
if (CollUtil.isEmpty(holderMenuIds)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
List<MenuDO> menus = menuService.getMenuList(holderMenuIds);
|
||||
menus = menuService.filterDisableMenus(menus);
|
||||
List<SubAccountMenuRespVO> result = new ArrayList<>();
|
||||
for (MenuDO menu : menus) {
|
||||
SubAccountMenuRespVO vo = new SubAccountMenuRespVO();
|
||||
vo.setId(menu.getId());
|
||||
vo.setParentId(menu.getParentId());
|
||||
vo.setName(menu.getName());
|
||||
vo.setType(menu.getType());
|
||||
vo.setSort(menu.getSort());
|
||||
result.add(vo);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createSubAccount(SubAccountSaveReqVO reqVO, String password) {
|
||||
Long holderUserId = getLoginUserId();
|
||||
// 1. 校验账号唯一
|
||||
if (userService.getUserByUsername(reqVO.getUsername()) != null) {
|
||||
throw exception(USER_USERNAME_EXISTS);
|
||||
}
|
||||
// 2. 校验并过滤菜单:只能授予 holder 自己拥有的菜单
|
||||
Set<Long> menuIds = filterMenusByHolder(reqVO.getMenuIds(), holderUserId);
|
||||
// 3. 创建子账号用户
|
||||
UserSaveReqVO userReqVO = new UserSaveReqVO();
|
||||
userReqVO.setUsername(reqVO.getUsername());
|
||||
userReqVO.setNickname(reqVO.getNickname());
|
||||
userReqVO.setPassword(password);
|
||||
userReqVO.setRemark("AppHolder 子账号");
|
||||
Long subUserId = userService.createUser(userReqVO);
|
||||
// 4. 创建专属角色并分配菜单
|
||||
Long roleId = createSubRole(subUserId, reqVO.getNickname());
|
||||
permissionService.assignRoleMenu(roleId, menuIds);
|
||||
// 5. 绑定角色
|
||||
permissionService.assignUserRole(subUserId, CollUtil.newHashSet(roleId));
|
||||
// 6. 记录绑定关系
|
||||
SubAccountDO mapping = new SubAccountDO();
|
||||
mapping.setHolderUserId(holderUserId);
|
||||
mapping.setSubUserId(subUserId);
|
||||
mapping.setRoleId(roleId);
|
||||
subAccountMapper.insert(mapping);
|
||||
return subUserId;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateSubAccount(Long userId, SubAccountSaveReqVO reqVO) {
|
||||
SubAccountDO mapping = validateOwner(userId);
|
||||
// 1. 更新昵称(username 不允许修改,密码走独立接口)
|
||||
AdminUserDO user = userService.getUser(userId);
|
||||
UserSaveReqVO userReqVO = new UserSaveReqVO();
|
||||
userReqVO.setId(userId);
|
||||
userReqVO.setUsername(user.getUsername());
|
||||
userReqVO.setNickname(reqVO.getNickname());
|
||||
userService.updateUser(userReqVO);
|
||||
// 2. 更新可见菜单
|
||||
Set<Long> menuIds = filterMenusByHolder(reqVO.getMenuIds(), mapping.getHolderUserId());
|
||||
permissionService.assignRoleMenu(mapping.getRoleId(), menuIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSubAccountStatus(Long userId, Integer status) {
|
||||
validateOwner(userId);
|
||||
userService.updateUserStatus(userId, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetSubAccountPassword(Long userId, String password) {
|
||||
validateOwner(userId);
|
||||
userService.updateUserPassword(userId, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteSubAccount(Long userId) {
|
||||
SubAccountDO mapping = validateOwner(userId);
|
||||
// 1. 删除用户
|
||||
userService.deleteUser(userId);
|
||||
// 2. 删除专属角色
|
||||
roleService.deleteRole(mapping.getRoleId());
|
||||
// 3. 删除绑定关系
|
||||
subAccountMapper.deleteById(mapping.getId());
|
||||
}
|
||||
|
||||
private Long createSubRole(Long subUserId, String nickname) {
|
||||
RoleSaveReqVO roleReqVO = new RoleSaveReqVO();
|
||||
roleReqVO.setName("子账号-" + nickname);
|
||||
roleReqVO.setCode("sub_acc_" + subUserId + "_" + RandomUtil.randomString(6).toLowerCase());
|
||||
roleReqVO.setSort(999);
|
||||
roleReqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
roleReqVO.setRemark("AppHolder 子账号专属角色");
|
||||
return roleService.createRole(roleReqVO, RoleTypeEnum.CUSTOM.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验当前登录人是否为该子账号的管理者,并返回绑定关系
|
||||
*/
|
||||
private SubAccountDO validateOwner(Long subUserId) {
|
||||
SubAccountDO mapping = subAccountMapper.selectBySubUserId(subUserId);
|
||||
if (mapping == null) {
|
||||
throw exception(SUB_ACCOUNT_NOT_EXISTS);
|
||||
}
|
||||
if (!mapping.getHolderUserId().equals(getLoginUserId())) {
|
||||
throw exception(SUB_ACCOUNT_NOT_OWNER);
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得 holder 拥有的菜单编号集合(其所有角色菜单的并集)
|
||||
*/
|
||||
private Set<Long> getHolderMenuIds(Long holderUserId) {
|
||||
Set<Long> roleIds = permissionService.getUserRoleIdListByUserId(holderUserId);
|
||||
if (CollUtil.isEmpty(roleIds)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
return permissionService.getRoleMenuListByRoleId(roleIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将请求的菜单过滤为 holder 自己拥有的菜单;若过滤后为空则报错
|
||||
*/
|
||||
private Set<Long> filterMenusByHolder(Set<Long> requestMenuIds, Long holderUserId) {
|
||||
Set<Long> holderMenuIds = getHolderMenuIds(holderUserId);
|
||||
if (CollUtil.isEmpty(holderMenuIds)) {
|
||||
throw exception(SUB_ACCOUNT_HOLDER_MENU_EMPTY);
|
||||
}
|
||||
Set<Long> menuIds = new HashSet<>();
|
||||
if (CollUtil.isNotEmpty(requestMenuIds)) {
|
||||
tenantService.handleTenantMenu(menuIds0 -> {
|
||||
for (Long menuId : requestMenuIds) {
|
||||
if (holderMenuIds.contains(menuId) && menuIds0.contains(menuId)) {
|
||||
menuIds.add(menuId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (CollUtil.isEmpty(menuIds)) {
|
||||
throw exception(SUB_ACCOUNT_MENU_EMPTY);
|
||||
}
|
||||
return menuIds;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -50,12 +50,12 @@ spring:
|
||||
master:
|
||||
url: jdbc:mysql://139.224.25.207:3306/chat_v1?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
|
||||
username: chat_v1
|
||||
password: BpJ2Ebt4zMPjBcCL
|
||||
password: rfBzbFFdW4kepybz
|
||||
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
|
||||
lazy: true # 开启懒加载,保证启动速度
|
||||
url: jdbc:mysql://139.224.25.207:3306/chat_v1?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例
|
||||
username: chat_v1
|
||||
password: BpJ2Ebt4zMPjBcCL
|
||||
password: rfBzbFFdW4kepybz
|
||||
|
||||
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
|
||||
redis:
|
||||
|
||||
@@ -47,12 +47,12 @@ spring:
|
||||
master:
|
||||
url: jdbc:mysql://127.0.0.1:3306/chat_v1?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true
|
||||
username: chat_v1
|
||||
password: BpJ2Ebt4zMPjBcCL
|
||||
password: rfBzbFFdW4kepybz
|
||||
slave: # 模拟从库,可根据自己需要修改
|
||||
lazy: true # 开启懒加载,保证启动速度
|
||||
url: jdbc:mysql://192.168.0.7:3306/chat_v1?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true&nullCatalogMeansCurrent=true
|
||||
username: chat_v1
|
||||
password: BpJ2Ebt4zMPjBcCL
|
||||
password: rfBzbFFdW4kepybz
|
||||
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
|
||||
redis:
|
||||
host: 127.0.0.1 # 地址
|
||||
|
||||
Reference in new issue
Block a user