perms;
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/vue-admin/src/styles/variables.module.scss:
--------------------------------------------------------------------------------
1 | /* stylelint-disable property-no-unknown */
2 | :export {
3 | sidebar-width: $sidebar-width;
4 | navbar-height: $navbar-height;
5 | menu-background: $menu-background;
6 | menu-text: $menu-text;
7 | menu-active-text: $menu-active-text;
8 | menu-hover: $menu-hover;
9 | sub-menu-background: $sub-menu-background;
10 | sub-menu-active-text: $sub-menu-active-text;
11 | sub-menu-hover: $sub-menu-hover;
12 | }
13 | /* stylelint-enable property-no-unknown */
14 |
--------------------------------------------------------------------------------
/youlai-auth/src/main/java/com/youlai/auth/model/CaptchaResult.java:
--------------------------------------------------------------------------------
1 | package com.youlai.auth.model;
2 |
3 | import lombok.Builder;
4 | import lombok.Data;
5 |
6 | /**
7 | * 验证码响应对象
8 | *
9 | * @author haoxr
10 | * @since 3.1.0
11 | */
12 |
13 | @Builder
14 | @Data
15 | public class CaptchaResult {
16 |
17 | /**
18 | * 验证码唯一标识(用于从Redis获取验证码Code)
19 | */
20 | private String captchaId;
21 |
22 | /**
23 | * 验证码图片Base64字符串
24 | */
25 | private String captchaBase64;
26 | }
27 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/query/RolePageQuery.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.query;
2 |
3 | import com.youlai.common.base.BasePageQuery;
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 | import lombok.Data;
6 |
7 | /**
8 | * 角色分页查询实体
9 | *
10 | * @author haoxr
11 | * @since 2022/6/3
12 | *
13 | */
14 | @Data
15 | public class RolePageQuery extends BasePageQuery {
16 |
17 | @Schema(description="关键字(角色名称/角色编码)")
18 | private String keywords;
19 | }
20 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/language.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/youlai-common/common-core/src/main/java/com/youlai/common/constant/SystemConstants.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.constant;
2 |
3 | /**
4 | * 系统常量
5 | *
6 | * @author haoxr
7 | * @since 2021/10/30
8 | */
9 | public interface SystemConstants {
10 |
11 | /**
12 | * 根部门ID
13 | */
14 | Long ROOT_NODE_ID = 0L;
15 |
16 |
17 | /**
18 | * 系统默认密码
19 | */
20 | String DEFAULT_PASSWORD = "123456";
21 |
22 | /**
23 | * 超级管理员角色编码
24 | */
25 | String ROOT_ROLE_CODE = "ROOT";
26 | }
27 |
--------------------------------------------------------------------------------
/youlai-gateway/src/main/java/com/youlai/gateway/GatewayApplication.java:
--------------------------------------------------------------------------------
1 | package com.youlai.gateway;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 |
7 | @SpringBootApplication
8 | @EnableDiscoveryClient
9 | public class GatewayApplication {
10 | public static void main(String[] args) {
11 | SpringApplication.run(GatewayApplication.class, args);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/SystemApplication.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
6 |
7 | @SpringBootApplication
8 | @EnableDiscoveryClient
9 | public class SystemApplication {
10 | public static void main(String[] args) {
11 | SpringApplication.run(SystemApplication.class, args);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/query/DictPageQuery.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.query;
2 |
3 |
4 | import com.youlai.common.base.BasePageQuery;
5 | import io.swagger.v3.oas.annotations.media.Schema;
6 | import lombok.Data;
7 |
8 | @Schema(description ="字典数据项分页查询对象")
9 | @Data
10 | public class DictPageQuery extends BasePageQuery {
11 |
12 | @Schema(description="关键字(字典项名称)")
13 | private String keywords;
14 |
15 | @Schema(description="字典类型编码")
16 | private String typeCode;
17 | }
18 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/query/DeptQuery.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.query;
2 |
3 | import io.swagger.v3.oas.annotations.media.Schema;
4 | import lombok.Data;
5 |
6 | /**
7 | * 部门查询对象
8 | *
9 | * @author haoxr
10 | * @since 2022/6/11
11 | */
12 | @Schema(description ="部门分页查询对象")
13 | @Data
14 | public class DeptQuery {
15 |
16 | @Schema(description="关键字(部门名称)")
17 | private String keywords;
18 |
19 | @Schema(description="状态(1->正常;0->禁用)")
20 | private Integer status;
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/query/MenuQuery.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.query;
2 |
3 | import io.swagger.v3.oas.annotations.media.Schema;
4 | import lombok.Data;
5 |
6 | /**
7 | * 菜单查询对象
8 | *
9 | * @author haoxr
10 | * @since 2022/10/28
11 | */
12 | @Schema(description ="部门分页查询对象")
13 | @Data
14 | public class MenuQuery {
15 |
16 | @Schema(description="关键字(菜单名称)")
17 | private String keywords;
18 |
19 | @Schema(description="状态(1->显示;0->隐藏)")
20 | private Integer status;
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/youlai-auth/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jre
2 | MAINTAINER youlai youlaitech@163.com
3 |
4 | RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \&& echo 'Asia/Shanghai' >/etc/timezone
5 |
6 | # /tmp 目录作为容器数据卷目录,SpringBoot内嵌Tomcat容器默认使用/tmp作为工作目录,任何向 /tmp 中写入的信息不会记录进容器存储层,从而保证容器存储层的无状态化
7 | # 在宿主机的/var/lib/docker目录下创建一个临时文件并把它链接到容器中的/tmp目录
8 | VOLUME /tmp
9 |
10 | # 复制jar到镜像
11 | ADD target/youlai-auth.jar app.jar
12 |
13 | ENTRYPOINT ["java", "-Xmx128m", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"]
14 |
15 | EXPOSE 8000
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/youlai-auth/src/main/resources/bootstrap-prod.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 9000
3 |
4 | spring:
5 | mvc:
6 | path-match:
7 | matching-strategy: ant_path_matcher
8 | cloud:
9 | nacos:
10 | # 注册中心
11 | discovery:
12 | server-addr: http://localhost:8848
13 | namespace: youlai-cloud
14 | # 配置中心
15 | config:
16 | server-addr: http://localhost:8848
17 | namespace: youlai-cloud
18 | file-extension: yaml
19 | shared-configs[0]:
20 | data-id: youlai-common.yaml
21 | refresh: true
--------------------------------------------------------------------------------
/youlai-common/common-web/src/main/java/com/youlai/common/web/annotation/PreventDuplicateResubmit.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.web.annotation;
2 |
3 |
4 | import java.lang.annotation.*;
5 |
6 | /**
7 | * 防重提交注解
8 | *
9 | * @author haoxr
10 | * @since 2023/5/9
11 | */
12 | @Target(ElementType.METHOD)
13 | @Retention(RetentionPolicy.RUNTIME)
14 | @Documented
15 | @Inherited
16 | public @interface PreventDuplicateResubmit {
17 |
18 | /**
19 | * 防重提交锁过期时间(秒)
20 | *
21 | * 默认5秒内不允许重复提交
22 | */
23 | int expire() default 5;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/youlai-gateway/src/main/resources/bootstrap-prod.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 9999
3 |
4 | spring:
5 | main:
6 | allow-bean-definition-overriding: true
7 | application:
8 | name: youlai-gateway
9 | cloud:
10 | nacos:
11 | discovery:
12 | server-addr: http://localhost:8848
13 | namespace: youlai-cloud
14 | config:
15 | server-addr: http://localhost:8848
16 | file-extension: yaml
17 | namespace: youlai-cloud
18 | shared-configs[0]:
19 | data-id: youlai-common.yaml
20 | refresh: true
21 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/mapper/SysRoleMapper.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.youlai.system.model.entity.SysRole;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | import java.util.Set;
8 |
9 | @Mapper
10 | public interface SysRoleMapper extends BaseMapper {
11 |
12 |
13 | /**
14 | * 获取最大范围的数据权限
15 | *
16 | * @param roles
17 | * @return
18 | */
19 | Integer getMaxDataRangeDataScope(Set roles);
20 | }
21 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/refresh.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vue-admin/src/lang/index.ts:
--------------------------------------------------------------------------------
1 | import { createI18n } from "vue-i18n";
2 | import { useAppStoreHook } from "@/store/modules/app";
3 | // 本地语言包
4 | import enLocale from "./package/en";
5 | import zhCnLocale from "./package/zh-cn";
6 |
7 | const appStore = useAppStoreHook();
8 |
9 | const messages = {
10 | "zh-cn": {
11 | ...zhCnLocale,
12 | },
13 | en: {
14 | ...enLocale,
15 | },
16 | };
17 |
18 | const i18n = createI18n({
19 | legacy: false,
20 | locale: appStore.language,
21 | messages: messages,
22 | globalInjection: true,
23 | });
24 |
25 | export default i18n;
26 |
--------------------------------------------------------------------------------
/youlai-common/common-core/src/main/java/com/youlai/common/constant/ProductConstants.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.constant;
2 |
3 | /**
4 | * 商品模块常量
5 | *
6 | * @author haoxr
7 | * @since 2021/02/28
8 | */
9 | public interface ProductConstants {
10 |
11 | /**
12 | * 订单锁定的商品列表key前缀
13 | */
14 | String ORDER_LOCKED_SKUS_PREFIX = "order:locked:skus:";
15 |
16 | /**
17 | * 商品分布式锁key前缀
18 | */
19 | String SKU_LOCK_PREFIX = "product:sku:lock:";
20 |
21 | /**
22 | * 临时规格ID前缀
23 | */
24 | String SPEC_TEMP_ID_PREFIX = "tid_";
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/query/PermPageQuery.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.query;
2 |
3 | import com.youlai.common.base.BasePageQuery;
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 | import lombok.Data;
6 |
7 | /**
8 | * 权限分页查询对象
9 | *
10 | * @author haoxr
11 | * @since 2022/1/14 22:22
12 | */
13 | @Data
14 | @Schema
15 | public class PermPageQuery extends BasePageQuery {
16 |
17 | @Schema(description="权限名称")
18 | private String name;
19 |
20 | @Schema(description="菜单ID")
21 | private Long menuId;
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/vo/DictPageVO.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.vo;
2 |
3 |
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 | import lombok.Data;
6 |
7 | @Schema(description ="字典分页对象")
8 | @Data
9 | public class DictPageVO {
10 |
11 | @Schema(description="字典ID")
12 | private Long id;
13 |
14 | @Schema(description="字典名称")
15 | private String name;
16 |
17 | @Schema(description="字典值")
18 | private String value;
19 |
20 | @Schema(description="状态(1:启用;0:禁用)")
21 | private Integer status;
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/youlai-common/common-core/src/main/java/com/youlai/common/base/BasePageQuery.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.base;
2 |
3 | import io.swagger.v3.oas.annotations.media.Schema;
4 | import lombok.Data;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * 基础分页请求对象
10 | *
11 | * @author huawei
12 | * @since 2021/2/28
13 | */
14 | @Data
15 | @Schema
16 | public class BasePageQuery implements Serializable {
17 |
18 | @Schema(description = "页码", example = "1")
19 | private int pageNum = 1;
20 |
21 | @Schema(description = "每页记录数", example = "10")
22 | private int pageSize = 10;
23 | }
24 |
--------------------------------------------------------------------------------
/youlai-auth/src/main/java/com/youlai/auth/oauth2/extension/captcha/CaptchaParameterNames.java:
--------------------------------------------------------------------------------
1 | package com.youlai.auth.oauth2.extension.captcha;
2 |
3 | /**
4 | * 验证码模式请求参数名
5 | *
6 | * @author Ray Hao
7 | * @since 3.0.0
8 | */
9 |
10 | public class CaptchaParameterNames {
11 |
12 | /**
13 | * 验证码ID
14 | */
15 | public static final String CAPTCHA_ID = "captchaId";
16 |
17 |
18 | /**
19 | * 验证码 Code
20 | */
21 | public static final String CAPTCHA_CODE = "captchaCode";
22 |
23 |
24 |
25 |
26 | private CaptchaParameterNames() {
27 | }
28 |
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/youlai-common/common-core/src/main/java/com/youlai/common/constant/OrderConstants.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.constant;
2 |
3 | /**
4 | * 订单常量
5 | *
6 | * @author haoxr
7 | * @since 2021/03/16
8 | */
9 | public interface OrderConstants {
10 |
11 | /**
12 | * 会员购物车缓存KEY前缀
13 | */
14 | String MEMBER_CART_PREFIX = "MEMBER:CART:";
15 |
16 | /**
17 | * 订单防重提交锁KEY前缀
18 | */
19 | String ORDER_RESUBMIT_LOCK_PREFIX = "ORDER:RESUBMIT_LOCK:";
20 |
21 |
22 | /**
23 | * 订单锁前缀
24 | *
25 | */
26 | String ORDER_LOCK_PREFIX = "ORDER:LOCK:";
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/youlai-gateway/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM openjdk:8-jre
2 | MAINTAINER youlai youlaitech@163.com
3 |
4 |
5 | RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \&& echo 'Asia/Shanghai' >/etc/timezone
6 |
7 | # /tmp 目录作为容器数据卷目录,SpringBoot内嵌Tomcat容器默认使用/tmp作为工作目录,任何向 /tmp 中写入的信息不会记录进容器存储层,从而保证容器存储层的无状态化
8 | # 在宿主机的/var/lib/docker目录下创建一个临时文件并把它链接到容器中的/tmp目录
9 | VOLUME /tmp
10 |
11 | # 复制jar至镜像
12 | ADD target/youlai-gateway.jar app.jar
13 |
14 | ENTRYPOINT ["java", "-Xmx128m", "-Djava.security.egd=file:/dev/./urandom","-Dcsp.sentinel.app.type=1", "-jar", "/app.jar"]
15 |
16 | EXPOSE 9999
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/vo/DictTypePageVO.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.vo;
2 |
3 |
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 | import lombok.Data;
6 |
7 | @Schema(description ="字典类型分页对象")
8 | @Data
9 | public class DictTypePageVO {
10 |
11 | @Schema(description="字典类型ID")
12 | private Long id;
13 |
14 | @Schema(description="类型名称")
15 | private String name;
16 |
17 | @Schema(description="类型编码")
18 | private String code;
19 |
20 | @Schema(description="状态:1:启用;0:禁用")
21 | private Integer status;
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/shrink.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/youlai-common/common-sms/src/main/java/com/youlai/common/sms/service/SmsService.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.sms.service;
2 |
3 |
4 | /**
5 | * 短信服务接口层
6 | *
7 | * @author haoxr
8 | * @since 3.0.0
9 | */
10 | public interface SmsService {
11 |
12 | /**
13 | * 发送短信验证码
14 | *
15 | * @param mobile 手机号 13388886666
16 | * @param templateCode 短信模板 SMS_194640010
17 | * @param templateParam 模板参数 "[{"code":"123456"}]"
18 | *
19 | * @return boolean 是否发送成功
20 | */
21 | boolean sendSms(String mobile, String templateCode, String templateParam);
22 |
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/mapper/SysMenuMapper.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.mapper;
2 |
3 | /**
4 | * 菜单持久接口层
5 | *
6 | * @author haoxr
7 | * @since 2022/1/24
8 | */
9 |
10 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
11 | import com.youlai.system.model.bo.RouteBO;
12 | import com.youlai.system.model.entity.SysMenu;
13 | import org.apache.ibatis.annotations.Mapper;
14 |
15 | import java.util.List;
16 | import java.util.Set;
17 |
18 | @Mapper
19 | public interface SysMenuMapper extends BaseMapper {
20 |
21 | List listRoutes();
22 | }
23 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/mapper/SysUserRoleMapper.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.youlai.system.model.entity.SysUserRole;
5 | import org.apache.ibatis.annotations.Mapper;
6 |
7 | /**
8 | * 用户角色访问层
9 | *
10 | * @author haoxr
11 | * @since 2022/1/15
12 | */
13 | @Mapper
14 | public interface SysUserRoleMapper extends BaseMapper {
15 |
16 | /**
17 | * 获取角色绑定的用户数
18 | *
19 | * @param roleId 角色ID
20 | */
21 | int countUsersForRole(Long roleId);
22 | }
23 |
--------------------------------------------------------------------------------
/vue-admin/src/types/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module "*.vue" {
4 | import { DefineComponent } from "vue";
5 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
6 | const component: DefineComponent<{}, {}, any>;
7 | export default component;
8 | }
9 |
10 | interface ImportMetaEnv {
11 | /** 应用端口 */
12 | VITE_APP_PORT: string;
13 | /** API 基础路径 */
14 | VITE_APP_BASE_API: string;
15 | VITE_APP_API_URL: string;
16 | VITE_MOCK_DEV_SERVER:boolean;
17 | }
18 |
19 | interface ImportMeta {
20 | readonly env: ImportMetaEnv;
21 | }
22 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/converter/DeptConverter.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.converter;
2 |
3 | import com.youlai.system.model.entity.SysDept;
4 | import com.youlai.system.model.form.DeptForm;
5 | import com.youlai.system.model.vo.DeptVO;
6 | import org.mapstruct.Mapper;
7 |
8 | /**
9 | * 部门对象转换器
10 | *
11 | * @author haoxr
12 | * @since 2022/7/29
13 | */
14 | @Mapper(componentModel = "spring")
15 | public interface DeptConverter {
16 |
17 | DeptForm entity2Form(SysDept entity);
18 | DeptVO entity2Vo(SysDept entity);
19 |
20 | SysDept form2Entity(DeptForm deptForm);
21 |
22 | }
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/resources/bootstrap-prod.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8800
3 |
4 | spring:
5 | main:
6 | allow-circular-references: true
7 | mvc:
8 | path-match:
9 | matching-strategy: ant_path_matcher
10 | cloud:
11 | nacos:
12 | # 注册中心
13 | discovery:
14 | server-addr: http://localhost:8848
15 | namespace: youlai-cloud
16 | # 配置中心
17 | config:
18 | server-addr: http://localhost:8848
19 | namespace: youlai-cloud
20 | file-extension: yaml
21 | shared-configs[0]:
22 | data-id: youlai-common.yaml
23 | refresh: true
--------------------------------------------------------------------------------
/youlai-common/common-core/src/main/java/com/youlai/common/enums/StatusEnum.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.enums;
2 |
3 | import com.youlai.common.base.IBaseEnum;
4 | import lombok.Getter;
5 |
6 | /**
7 | * 状态枚举
8 | *
9 | * @author haoxr
10 | * @since 2022/10/14
11 | */
12 | public enum StatusEnum implements IBaseEnum {
13 |
14 | ENABLE(1, "启用"),
15 | DISABLE (0, "禁用");
16 |
17 | @Getter
18 | private Integer value;
19 |
20 | @Getter
21 | private String label;
22 |
23 | StatusEnum(Integer value, String label) {
24 | this.value = value;
25 | this.label = label;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/converter/MenuConverter.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.converter;
2 |
3 | import com.youlai.system.model.entity.SysMenu;
4 | import com.youlai.system.model.form.MenuForm;
5 | import com.youlai.system.model.vo.MenuVO;
6 | import org.mapstruct.Mapper;
7 |
8 | /**
9 | * 菜单对象转换器
10 | *
11 | * @author haoxr
12 | * @since 2022/7/29
13 | */
14 | @Mapper(componentModel = "spring")
15 | public interface MenuConverter {
16 |
17 | MenuVO entity2Vo(SysMenu entity);
18 |
19 |
20 | MenuForm entity2Form(SysMenu entity);
21 |
22 | SysMenu form2Entity(MenuForm menuForm);
23 |
24 | }
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/resources/bootstrap-dev.yml:
--------------------------------------------------------------------------------
1 | server:
2 | port: 8800
3 |
4 | spring:
5 | main:
6 | allow-circular-references: true
7 | mvc:
8 | path-match:
9 | matching-strategy: ant_path_matcher
10 | cloud:
11 | nacos:
12 | # 注册中心
13 | discovery:
14 | server-addr: http://localhost:8848
15 | namespace: youlai-cloud
16 | # 配置中心
17 | config:
18 | server-addr: http://localhost:8848
19 | namespace: youlai-cloud
20 | file-extension: yaml
21 | shared-configs[0]:
22 | data-id: youlai-common.yaml
23 | refresh: true
24 |
25 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/ip.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/vue-admin/.env.development:
--------------------------------------------------------------------------------
1 | ## 开发环境
2 | NODE_ENV='development'
3 |
4 | # 应用端口
5 | VITE_APP_PORT = 9527
6 |
7 | # 代理前缀
8 | VITE_APP_BASE_API = '/dev-api'
9 |
10 |
11 | # 开发接口地址
12 | VITE_APP_API_URL = http://localhost:9999
13 |
14 | # 线上接口地址(暂不可用)
15 | # VITE_APP_API_URL = https://api.youlai.tech
16 |
17 | # 是否启用 Mock 服务
18 | VITE_MOCK_DEV_SERVER = false
19 |
20 | # OAuth2 客户端ID
21 | VITE_OAUTH_CLIENT_ID = messaging-client
22 |
23 | # OAuth2 客户端密钥
24 | VITE_OAUTH_CLIENT_SECRET = 123456
25 |
26 | # OAuth2 重定向地址
27 | VITE_OAUTH_REDIRECT_URI = http://127.0.0.1:9527/OAuth2Redirect
28 |
29 | # OAuth2 认证服务器地址
30 | VITE_OAUTH_ISSUER=http://127.0.0.1:9000
31 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/close_left.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vue-admin/src/styles/index.scss:
--------------------------------------------------------------------------------
1 | @use "./reset";
2 |
3 | .app-container {
4 | padding: 10px;
5 | }
6 |
7 | .search-container {
8 | padding: 18px 0 0 10px;
9 | margin-bottom: 10px;
10 | background-color: var(--el-bg-color-overlay);
11 | border: 1px solid var(--el-border-color-light);
12 | border-radius: 4px;
13 | box-shadow: var(--el-box-shadow-light);
14 | }
15 |
16 | .table-container > .el-card__header {
17 | padding: calc(var(--el-card-padding) - 8px) var(--el-card-padding);
18 | }
19 |
20 | .link-type,
21 | .link-type:focus {
22 | color: #337ab7;
23 | cursor: pointer;
24 |
25 | &:hover {
26 | color: rgb(32 160 255);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/youlai-common/common-core/src/main/java/com/youlai/common/constant/JwtClaimConstants.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.constant;
2 |
3 | /**
4 | * JWT常量
5 | */
6 | public interface JwtClaimConstants {
7 |
8 | /**
9 | * 用户ID
10 | */
11 | String USER_ID = "userId";
12 |
13 | /**
14 | * 用户名
15 | */
16 | String USERNAME = "username";
17 |
18 | /**
19 | * 部门ID
20 | */
21 | String DEPT_ID = "deptId";
22 |
23 | /**
24 | * 数据权限
25 | */
26 | String DATA_SCOPE = "dataScope";
27 |
28 | /**
29 | * JWT claim中存储授权信息(角色)的字段名称
30 | */
31 | String AUTHORITIES = "authorities";
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/entity/SysRoleMenu.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.TableField;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 |
9 | /**
10 | * 角色和菜单关联表
11 | */
12 | @Data
13 | @AllArgsConstructor
14 | @NoArgsConstructor
15 | public class SysRoleMenu {
16 | /**
17 | * 角色ID
18 | */
19 | private Long roleId;
20 |
21 | /**
22 | * 菜单ID
23 | */
24 | private Long menuId;
25 |
26 | @TableField(exist = false)
27 | private static final long serialVersionUID = 1L;
28 | }
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/query/UserPageQuery.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.query;
2 |
3 | import com.youlai.common.base.BasePageQuery;
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 | import lombok.Data;
6 |
7 | /**
8 | * 用户分页查询对象
9 | *
10 | * @author haoxr
11 | * @since 2022/1/14
12 | */
13 | @Schema
14 | @Data
15 | public class UserPageQuery extends BasePageQuery {
16 |
17 | @Schema(description="关键字(用户名/昵称/手机号)")
18 | private String keywords;
19 |
20 | @Schema(description="用户状态")
21 | private Integer status;
22 |
23 | @Schema(description="部门ID")
24 | private Long deptId;
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/form/DictTypeForm.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.form;
2 |
3 |
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 | import lombok.Data;
6 |
7 | @Schema(description = "字典类型")
8 | @Data
9 | public class DictTypeForm {
10 |
11 | @Schema(description="字典类型ID")
12 | private Long id;
13 |
14 | @Schema(description="类型名称")
15 | private String name;
16 |
17 | @Schema(description="类型编码")
18 | private String code;
19 |
20 | @Schema(description="类型状态(1:启用;0:禁用)")
21 | private Integer status;
22 |
23 | @Schema(description = "备注")
24 | private String remark;
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/Dockerfile:
--------------------------------------------------------------------------------
1 | # 基础镜像
2 | FROM openjdk:8-jre
3 |
4 | # 维护者信息
5 | MAINTAINER youlai
6 |
7 | # 设置容器时区为当前时区
8 | RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \&& echo 'Asia/Shanghai' >/etc/timezone
9 |
10 | # /tmp 目录作为容器数据卷目录,SpringBoot内嵌Tomcat容器默认使用/tmp作为工作目录,任何向 /tmp 中写入的信息不会记录进容器存储层
11 | # 在宿主机的/var/lib/docker目录下创建一个临时文件并把它链接到容器中的/tmp目录
12 | VOLUME /tmp
13 |
14 | # 复制主机文件至镜像内,复制的目录需放置在 Dockerfile 文件同级目录下
15 | ADD target/system-boot.jar app.jar
16 |
17 | # 容器启动执行命令
18 | ENTRYPOINT ["java", "-Xmx128m", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"]
19 |
20 | # 声明容器提供服务端口
21 | EXPOSE 8800
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/service/OssService.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.service;
2 |
3 | import com.youlai.system.model.vo.FileInfoVO;
4 | import org.springframework.web.multipart.MultipartFile;
5 |
6 | /**
7 | * 对象存储服务接口层
8 | *
9 | * @author haoxr
10 | * @since 3.0.0
11 | */
12 | public interface OssService {
13 |
14 | /**
15 | * 上传文件
16 | * @param file 表单文件对象
17 | * @return 文件信息
18 | */
19 | FileInfoVO uploadFile(MultipartFile file);
20 |
21 | /**
22 | * 删除文件
23 | *
24 | * @param filePath 文件完整URL
25 | * @return 删除结果
26 | */
27 | boolean deleteFile(String filePath);
28 |
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/config/PasswordEncoderConfig.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.config;
2 |
3 | import org.springframework.context.annotation.Bean;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
6 | import org.springframework.security.crypto.password.PasswordEncoder;
7 |
8 | /**
9 | * 密码编码器(修改、重置密码使用)
10 | *
11 | * @author haoxr
12 | * @since 0.0.1
13 | */
14 | @Configuration
15 | public class PasswordEncoderConfig {
16 |
17 | @Bean
18 | public PasswordEncoder passwordEncoder() {
19 | return new BCryptPasswordEncoder();
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/theme.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/close_right.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/youlai-auth/src/main/java/com/youlai/auth/AuthApplication.java:
--------------------------------------------------------------------------------
1 | package com.youlai.auth;
2 |
3 | import com.youlai.system.api.UserFeignClient;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
7 | import org.springframework.cloud.openfeign.EnableFeignClients;
8 |
9 | @EnableFeignClients(basePackageClasses = {UserFeignClient.class})
10 | @SpringBootApplication
11 | @EnableDiscoveryClient
12 | public class AuthApplication {
13 |
14 | public static void main(String[] args) {
15 | SpringApplication.run(AuthApplication.class, args);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/youlai-system/system-api/src/main/java/com/youlai/system/api/fallback/UserFeignFallbackClient.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.api.fallback;
2 |
3 | import com.youlai.system.api.UserFeignClient;
4 | import com.youlai.system.dto.UserAuthInfo;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.stereotype.Component;
7 |
8 | /**
9 | * 系统用户服务远程调用异常后的降级处理类
10 | *
11 | * @author haoxr
12 | * @since 2021/4/24
13 | */
14 | @Component
15 | @Slf4j
16 | public class UserFeignFallbackClient implements UserFeignClient {
17 |
18 | @Override
19 | public UserAuthInfo getUserAuthInfo(String username) {
20 | log.error("feign远程调用系统用户服务异常后的降级方法");
21 | return new UserAuthInfo();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/entity/SysUserRole.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.TableField;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 |
9 | /**
10 | * 用户和角色关联表
11 | *
12 | * @author haoxr
13 | * @since 2022/12/17
14 | */
15 | @Data
16 | @AllArgsConstructor
17 | @NoArgsConstructor
18 | public class SysUserRole {
19 | /**
20 | * 用户ID
21 | */
22 | private Long userId;
23 |
24 | /**
25 | * 角色ID
26 | */
27 | private Long roleId;
28 |
29 | @TableField(exist = false)
30 | private static final long serialVersionUID = 1L;
31 | }
--------------------------------------------------------------------------------
/youlai-common/common-core/src/main/java/com/youlai/common/base/BaseEntity.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.base;
2 | import com.baomidou.mybatisplus.annotation.FieldFill;
3 | import com.baomidou.mybatisplus.annotation.TableField;
4 | import lombok.Data;
5 |
6 | import java.io.Serial;
7 | import java.io.Serializable;
8 | import java.time.LocalDateTime;
9 |
10 | /**
11 | * 基础实体类
12 | */
13 | @Data
14 | public class BaseEntity implements Serializable {
15 |
16 | @Serial
17 | private static final long serialVersionUID = 1L;
18 |
19 | @TableField(fill = FieldFill.INSERT)
20 | private LocalDateTime createTime;
21 |
22 | @TableField(fill = FieldFill.INSERT_UPDATE)
23 | private LocalDateTime updateTime;
24 | }
25 |
--------------------------------------------------------------------------------
/youlai-system/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | youlai-cloud
7 | com.youlai
8 | 0.0.1
9 |
10 | 4.0.0
11 |
12 | youlai-system
13 | pom
14 |
15 |
16 | system-api
17 | system-boot
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # youlai-cloud
2 |
3 | #### 介绍
4 | 面向 SpringBoot3,基于 Java17、Spring Cloud&Alibaba 2021、Spring Boot 2.7 、Spring Authorization Server 0.3.1 全新升级OAuth2授权+微服务+UPMS管理系统解决方案。
5 |
6 |
7 | #### Spring Authorization Server 授权码模式测试流程
8 | 1. 创建名为 oauth2 的数据库,执行docs/sql/oauth2.sql的脚本创建表
9 | 2. 启动nacos,创建 cloud-namespace-id 的namespace,导入docs/nacos/DEFAULT_GROUP.zip配置
10 | 3. 依次启动 youlai-auth、youlai-system、youlai-gateway
11 | 4. 浏览器输入网关: http://127.0.0.1:9999/youlai-system/messages
12 | 5. 因为第一次未授权会跳转到认证中心进行认证,输入用户名/密码(admin/123456),认证成功网关会路由到资源服务器获取数据。
13 |
14 | 
15 |
16 |
17 | #### 参与贡献
18 |
19 | 1. Fork 本仓库
20 | 2. 新建 Feat_xxx 分支
21 | 3. 提交代码
22 | 4. 新建 Pull Request
--------------------------------------------------------------------------------
/youlai-common/common-core/src/main/java/com/youlai/common/enums/GenderEnum.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.enums;
2 |
3 | import com.youlai.common.base.IBaseEnum;
4 | import lombok.Getter;
5 |
6 | /**
7 | * 性别枚举
8 | *
9 | * @author haoxr
10 | * @since 2022/4/10
11 | */
12 | public enum GenderEnum implements IBaseEnum {
13 |
14 | MALE(1, "男"),
15 | FEMALE(2, "女"),
16 | UNKNOWN(0, "未知");
17 |
18 | @Getter
19 | // @EnumValue // Mybatis-Plus 提供注解表示插入数据库时插入该值
20 | private Integer value;
21 |
22 | @Getter
23 | // @JsonValue // 表示对枚举序列化时返回此字段
24 | private String label;
25 |
26 | GenderEnum(Integer value, String label) {
27 | this.value = value;
28 | this.label = label;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/form/DeptForm.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.form;
2 |
3 | import io.swagger.v3.oas.annotations.media.Schema;
4 | import jakarta.validation.constraints.NotNull;
5 | import lombok.Data;
6 |
7 | @Schema(description = "部门表单对象")
8 | @Data
9 | public class DeptForm {
10 |
11 | @Schema(description="部门ID")
12 | private Long id;
13 |
14 | @Schema(description="部门名称")
15 | private String name;
16 |
17 | @Schema(description="父部门ID")
18 | @NotNull(message = "父部门ID不能为空")
19 | private Long parentId;
20 |
21 | @Schema(description="状态(1:启用;0:禁用)")
22 | private Integer status;
23 |
24 | @Schema(description="排序(数字越小排名越靠前)")
25 | private Integer sort;
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/converter/DictTypeConverter.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.converter;
2 |
3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
4 | import com.youlai.system.model.entity.SysDictType;
5 | import com.youlai.system.model.form.DictTypeForm;
6 | import com.youlai.system.model.vo.DictTypePageVO;
7 | import org.mapstruct.Mapper;
8 |
9 | /**
10 | * 字典类型对象转换器
11 | *
12 | * @author haoxr
13 | * @since 2022/6/8
14 | */
15 | @Mapper(componentModel = "spring")
16 | public interface DictTypeConverter {
17 |
18 | Page entity2Page(Page page);
19 |
20 | DictTypeForm entity2Form(SysDictType entity);
21 |
22 | SysDictType form2Entity(DictTypeForm entity);
23 | }
24 |
--------------------------------------------------------------------------------
/youlai-common/common-mybatis/src/main/java/com/youlai/common/mybatis/enums/DataScopeEnum.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.mybatis.enums;
2 |
3 | import com.youlai.common.base.IBaseEnum;
4 | import lombok.Getter;
5 |
6 | /**
7 | * 数据权限枚举
8 | *
9 | * @author haoxr
10 | * @since 2022/10/14
11 | */
12 | public enum DataScopeEnum implements IBaseEnum {
13 |
14 | /**
15 | * value 越小,数据权限范围越大
16 | */
17 | ALL(0, "所有数据"),
18 | DEPT_AND_SUB(1, "部门及子部门数据"),
19 | DEPT(2, "本部门数据"),
20 | SELF(3, "本人数据");
21 |
22 | @Getter
23 | private Integer value;
24 |
25 | @Getter
26 | private String label;
27 |
28 | DataScopeEnum(Integer value, String label) {
29 | this.value = value;
30 | this.label = label;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/vo/UserImportVO.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.vo;
2 |
3 | import com.alibaba.excel.annotation.ExcelProperty;
4 | import lombok.Data;
5 |
6 | /**
7 | * 用户导入对象
8 | *
9 | * @author haoxr
10 | * @since 2022/4/10
11 | */
12 | @Data
13 | public class UserImportVO {
14 |
15 | @ExcelProperty(value = "用户名")
16 | private String username;
17 |
18 | @ExcelProperty(value = "昵称")
19 | private String nickname;
20 |
21 | @ExcelProperty(value = "性别")
22 | private String gender;
23 |
24 | @ExcelProperty(value = "手机号码")
25 | private String mobile;
26 |
27 | @ExcelProperty(value = "邮箱")
28 | private String email;
29 |
30 | @ExcelProperty("角色")
31 | private String roleCodes;
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/vue-admin/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from "vue";
2 | import App from "./App.vue";
3 | import router from "@/router";
4 | import { setupStore } from "@/store";
5 | import { setupDirective } from "@/directive";
6 | import { setupElIcons, setupI18n, setupPermission } from "@/plugins";
7 |
8 | // 本地SVG图标
9 | import "virtual:svg-icons-register";
10 |
11 | // 样式
12 | import "element-plus/theme-chalk/dark/css-vars.css";
13 | import "@/styles/index.scss";
14 | import "uno.css";
15 | import "animate.css";
16 |
17 | const app = createApp(App);
18 | // 全局注册 自定义指令(directive)
19 | setupDirective(app);
20 | // 全局注册 状态管理(store)
21 | setupStore(app);
22 | // 全局注册Element-plus图标
23 | setupElIcons(app);
24 | // 国际化
25 | setupI18n(app);
26 | // 注册动态路由
27 | setupPermission();
28 | app.use(router).mount("#app");
29 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/mapper/SysDeptMapper.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.conditions.Wrapper;
4 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
5 | import com.baomidou.mybatisplus.core.toolkit.Constants;
6 | import com.youlai.common.mybatis.annotation.DataPermission;
7 | import com.youlai.system.model.entity.SysDept;
8 | import org.apache.ibatis.annotations.Mapper;
9 | import org.apache.ibatis.annotations.Param;
10 |
11 | import java.util.List;
12 |
13 |
14 | @Mapper
15 | public interface SysDeptMapper extends BaseMapper {
16 |
17 | @DataPermission(deptIdColumnName = "id")
18 | @Override
19 | List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper);
20 | }
21 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/vo/UserInfoVO.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.vo;
2 |
3 | import io.swagger.v3.oas.annotations.media.Schema;
4 | import lombok.Data;
5 |
6 | import java.util.Set;
7 |
8 | /**
9 | * 用户登录视图对象
10 | *
11 | * @author haoxr
12 | * @since 2022/1/14
13 | */
14 | @Schema(description ="当前登录用户视图对象")
15 | @Data
16 | public class UserInfoVO {
17 |
18 | @Schema(description="用户ID")
19 | private Long userId;
20 |
21 | @Schema(description="用户昵称")
22 | private String nickname;
23 |
24 | @Schema(description="头像地址")
25 | private String avatar;
26 |
27 | @Schema(description="用户角色编码集合")
28 | private Set roles;
29 |
30 | @Schema(description="用户权限标识集合")
31 | private Set perms;
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/youlai-common/common-mybatis/src/main/java/com/youlai/common/mybatis/handler/StringArrayJsonTypeHandler.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.mybatis.handler;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.apache.ibatis.type.JdbcType;
5 | import org.apache.ibatis.type.MappedJdbcTypes;
6 | import org.apache.ibatis.type.MappedTypes;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * String 数组类型转换 json
11 | *
12 | * @author Gadfly
13 | * @since 1.0.0
14 | */
15 | @Slf4j
16 | @Component
17 | @MappedTypes(value = {String[].class})
18 | @MappedJdbcTypes(value = {JdbcType.OTHER}, includeNullJdbcType = true)
19 | public class StringArrayJsonTypeHandler extends ArrayObjectJsonTypeHandler {
20 | public StringArrayJsonTypeHandler() {
21 | super(String[].class);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/form/DictForm.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.form;
2 |
3 |
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 | import lombok.Data;
6 |
7 | @Schema(description = "字典表单对象")
8 | @Data
9 | public class DictForm {
10 |
11 | @Schema(description="字典ID")
12 | private Long id;
13 |
14 | @Schema(description="类型编码")
15 | private String typeCode;
16 |
17 | @Schema(description="字典名称")
18 | private String name;
19 |
20 | @Schema(description="字典值")
21 | private String value;
22 |
23 | @Schema(description="状态(1:启用;0:禁用)")
24 | private Integer status;
25 |
26 | @Schema(description="排序")
27 | private Integer sort;
28 |
29 | @Schema(description = "字典备注")
30 | private String remark;
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/youlai-system/system-api/src/main/java/com/youlai/system/api/UserFeignClient.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.api;
2 |
3 | import com.youlai.common.web.config.FeignDecoderConfig;
4 | import com.youlai.system.api.fallback.UserFeignFallbackClient;
5 | import com.youlai.system.dto.UserAuthInfo;
6 | import com.youlai.common.result.Result;
7 | import org.springframework.cloud.openfeign.FeignClient;
8 | import org.springframework.web.bind.annotation.GetMapping;
9 | import org.springframework.web.bind.annotation.PathVariable;
10 |
11 | @FeignClient(value = "youlai-system", fallback = UserFeignFallbackClient.class, configuration = {FeignDecoderConfig.class})
12 | public interface UserFeignClient {
13 |
14 | @GetMapping("/api/v1/users/{username}/authInfo")
15 | UserAuthInfo getUserAuthInfo(@PathVariable String username);
16 | }
17 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/nested.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/converter/DictConverter.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.converter;
2 |
3 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
4 | import com.youlai.system.model.entity.SysDict;
5 | import com.youlai.system.model.form.DictForm;
6 | import com.youlai.system.model.vo.DictPageVO;
7 | import org.mapstruct.InheritInverseConfiguration;
8 | import org.mapstruct.Mapper;
9 |
10 | /**
11 | * 字典数据项对象转换器
12 | *
13 | * @author haoxr
14 | * @since 2022/6/8
15 | */
16 | @Mapper(componentModel = "spring")
17 | public interface DictConverter {
18 |
19 | Page entity2Page(Page page);
20 |
21 | DictForm entity2Form(SysDict entity);
22 |
23 | @InheritInverseConfiguration(name="entity2Form")
24 | SysDict form2Entity(DictForm entity);
25 | }
26 |
--------------------------------------------------------------------------------
/youlai-common/common-web/src/main/resources/ValidationMessages.properties:
--------------------------------------------------------------------------------
1 | # \u901A\u7528\u5F02\u5E38\u4FE1\u606F
2 | id.positive=id\u5FC5\u987B\u4E3A\u6B63\u6574\u6570
3 | page.count.min=\u5206\u9875\u6570\u91CF\u5FC5\u987B\u4E3A\u6B63\u6574\u6570
4 | page.count.max=\u5206\u9875\u6570\u91CF\u5FC5\u987B\u5C0F\u4E8E{value}
5 | page.number.min=\u5206\u9875\u9875\u7801\u5FC5\u987B\u4E3A\u6B63\u6574\u6570
6 | date.past=\u65E5\u671F\u5FC5\u987B\u662F\u8FC7\u53BB\u7684\u65F6\u95F4
7 | date.interval=\u7ED3\u675F\u65E5\u671F\u5FC5\u987B\u65E9\u4E8E\u5F00\u59CB\u65E5\u671F
8 | text.length.min=\u6700\u5C0F\u957F\u5EA6\u5FC5\u987B\u5927\u4E8E{min}
9 | text.length.max=\u6700\u5927\u957F\u5EA6\u5FC5\u987B\u5C0F\u4E8E{max}
10 | phone.valid=\u5FC5\u987B\u662F\u5927\u964611\u4F4D\u624B\u673A\u53F7
11 | zipcode.valid=\u90AE\u7F16\u5FC5\u987B\u4E3A6\u4F4D\u6570\u5B57
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/mapper/SysRoleMenuMapper.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.mapper;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.youlai.system.model.bo.RolePermsBO;
5 | import com.youlai.system.model.entity.SysRoleMenu;
6 | import org.apache.ibatis.annotations.Mapper;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * 角色菜单持久层
12 | *
13 | * @author haoxr
14 | * @since 2022/6/4
15 | */
16 | @Mapper
17 | public interface SysRoleMenuMapper extends BaseMapper {
18 |
19 | /**
20 | * 获取角色拥有的菜单ID集合
21 | *
22 | * @param roleId
23 | * @return
24 | */
25 | List listMenuIdsByRoleId(Long roleId);
26 |
27 | /**
28 | * 获取权限和拥有权限的角色列表
29 | */
30 | List getRolePermsList(String roleCode);
31 | }
32 |
--------------------------------------------------------------------------------
/youlai-common/common-core/src/main/java/com/youlai/common/constant/RedisConstants.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.constant;
2 |
3 | public interface RedisConstants {
4 |
5 | /**
6 | * 黑名单TOKEN Key前缀
7 | */
8 | String TOKEN_BLACKLIST_PREFIX = "token:blacklist:";
9 |
10 | /**
11 | * 图形验证码key前缀
12 | */
13 | String CAPTCHA_CODE_PREFIX = "captcha_code:";
14 |
15 | /**
16 | * 登录短信验证码key前缀
17 | */
18 | String LOGIN_SMS_CODE_PREFIX = "sms_code:login";
19 |
20 | /**
21 | * 注册短信验证码key前缀
22 | */
23 | String REGISTER_SMS_CODE_PREFIX = "sms_code:register";
24 |
25 |
26 | /**
27 | * 角色和权限缓存前缀
28 | */
29 | String ROLE_PERMS_PREFIX = "role_perms:";
30 |
31 |
32 | /**
33 | * JWT 密钥对(包含公钥和私钥)
34 | */
35 | String JWK_SET_KEY = "jwk_set";
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/vue-admin/src/api/file/index.ts:
--------------------------------------------------------------------------------
1 | import request from "@/utils/request";
2 | import { AxiosPromise } from "axios";
3 | import { FileInfo } from "./types";
4 |
5 | /**
6 | * 上传文件
7 | *
8 | * @param file
9 | */
10 | export function uploadFileApi(file: File): AxiosPromise {
11 | const formData = new FormData();
12 | formData.append("file", file);
13 | return request({
14 | url: "/youlai-system/api/v1/files",
15 | method: "post",
16 | data: formData,
17 | headers: {
18 | "Content-Type": "multipart/form-data",
19 | },
20 | });
21 | }
22 |
23 | /**
24 | * 删除文件
25 | *
26 | * @param filePath 文件完整路径
27 | */
28 | export function deleteFileApi(filePath?: string) {
29 | return request({
30 | url: "/youlai-system/api/v1/files",
31 | method: "delete",
32 | params: { filePath: filePath },
33 | });
34 | }
35 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/form/RoleForm.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.form;
2 |
3 | import io.swagger.v3.oas.annotations.media.Schema;
4 | import jakarta.validation.constraints.NotBlank;
5 | import lombok.Data;
6 |
7 | @Schema(description = "角色表单对象")
8 | @Data
9 | public class RoleForm {
10 |
11 | @Schema(description="角色ID")
12 | private Long id;
13 |
14 | @Schema(description="角色名称")
15 | @NotBlank(message = "角色名称不能为空")
16 | private String name;
17 |
18 | @Schema(description="角色编码")
19 | @NotBlank(message = "角色编码不能为空")
20 | private String code;
21 |
22 | @Schema(description="排序")
23 | private Integer sort;
24 |
25 | @Schema(description="角色状态(1-正常;0-停用)")
26 | private Integer status;
27 |
28 | @Schema(description="数据权限")
29 | private Integer dataScope;
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/service/SysUserRoleService.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.service;
2 |
3 |
4 | import com.baomidou.mybatisplus.extension.service.IService;
5 | import com.youlai.system.model.entity.SysUserRole;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * 用户角色关联业务接口
11 | *
12 | * @author haoxr
13 | * @since 0.0.1
14 | */
15 | public interface SysUserRoleService extends IService {
16 |
17 | /**
18 | * 保存用户角色
19 | *
20 | * @param userId 用户ID
21 | * @param roleIds 角色ID集合
22 | * @return boolean 是否保存成功
23 | */
24 | boolean saveUserRoles(Long userId, List roleIds);
25 |
26 |
27 | /**
28 | * 判断角色是否存在绑定的用户
29 | *
30 | * @param roleId 角色ID
31 | * @return true:已分配 false:未分配
32 | */
33 | boolean hasAssignedUsers(Long roleId);
34 | }
35 |
--------------------------------------------------------------------------------
/youlai-common/common-web/src/main/java/com/youlai/common/web/exception/BizException.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.web.exception;
2 |
3 | import com.youlai.common.result.IResultCode;
4 | import lombok.Getter;
5 |
6 | /**
7 | * 自定义业务异常
8 | *
9 | * @author haoxr
10 | * @since 2022/7/31
11 | */
12 | @Getter
13 | public class BizException extends RuntimeException {
14 |
15 | public IResultCode resultCode;
16 |
17 | public BizException(IResultCode errorCode) {
18 | super(errorCode.getMsg());
19 | this.resultCode = errorCode;
20 | }
21 |
22 | public BizException(String message){
23 | super(message);
24 | }
25 |
26 | public BizException(String message, Throwable cause){
27 | super(message, cause);
28 | }
29 |
30 | public BizException(Throwable cause){
31 | super(cause);
32 | }
33 |
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/vue-admin/src/components/Hamburger/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
11 |
12 |
13 |
28 |
29 |
40 |
--------------------------------------------------------------------------------
/youlai-common/common-mybatis/src/main/java/com/youlai/common/mybatis/annotation/DataPermission.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.mybatis.annotation;
2 |
3 | import java.lang.annotation.*;
4 |
5 | /**
6 | * MP数据权限注解
7 | *
8 | * https://gitee.com/baomidou/mybatis-plus/issues/I37I90
9 | *
10 | * @author zc
11 | * @since 2021-12-10 15:48
12 | */
13 | @Documented
14 | @Retention(RetentionPolicy.RUNTIME)
15 | @Target({ElementType.TYPE, ElementType.METHOD})
16 | public @interface DataPermission {
17 |
18 | /**
19 | * 数据权限 {@link com.baomidou.mybatisplus.extension.plugins.inner.DataPermissionInterceptor}
20 | */
21 | String deptAlias() default "";
22 |
23 | String deptIdColumnName() default "dept_id";
24 | String userAlias() default "";
25 |
26 | String userIdColumnName() default "create_by";
27 |
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/entity/SysDictType.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.youlai.common.base.BaseEntity;
6 | import lombok.Data;
7 |
8 | /**
9 | * 字典类型实体
10 | *
11 | * @author haoxr
12 | * @since 2022/12/17
13 | */
14 | @Data
15 | public class SysDictType extends BaseEntity {
16 | /**
17 | * 主键
18 | */
19 | @TableId(type = IdType.AUTO)
20 | private Long id;
21 |
22 | /**
23 | * 类型名称
24 | */
25 | private String name;
26 |
27 | /**
28 | * 类型编码
29 | */
30 | private String code;
31 |
32 | /**
33 | * 状态(0:正常;1:禁用)
34 | */
35 | private Integer status;
36 |
37 | /**
38 | * 备注
39 | */
40 | private String remark;
41 | }
--------------------------------------------------------------------------------
/vue-admin/src/components/AppLink/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
41 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/enums/MenuTypeEnum.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.enums;
2 |
3 | import com.baomidou.mybatisplus.annotation.EnumValue;
4 | import com.youlai.common.base.IBaseEnum;
5 | import lombok.Getter;
6 |
7 | /**
8 | * 菜单类型枚举
9 | *
10 | * @author haoxr
11 | * @since 2022/4/23
12 | */
13 |
14 | public enum MenuTypeEnum implements IBaseEnum {
15 |
16 | NULL(0, null),
17 | MENU(1, "菜单"),
18 | CATALOG(2, "目录"),
19 | EXTLINK(3, "外链"),
20 |
21 | BUTTON(4, "按钮");
22 |
23 | @Getter
24 | @EnumValue // Mybatis-Plus 提供注解表示插入数据库时插入该值
25 | private Integer value;
26 |
27 | @Getter
28 | // @JsonValue // 表示对枚举序列化时返回此字段
29 | private String label;
30 |
31 | MenuTypeEnum(Integer value, String label) {
32 | this.value = value;
33 | this.label = label;
34 | }
35 |
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/monitor.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/youlai-common/common-mybatis/src/main/java/com/youlai/common/mybatis/handler/LongArrayJsonTypeHandler.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.mybatis.handler;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.apache.ibatis.type.JdbcType;
5 | import org.apache.ibatis.type.MappedJdbcTypes;
6 | import org.apache.ibatis.type.MappedTypes;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * Long 数组类型转换 json
11 | * https://www.jianshu.com/p/ab832f3fe81c
12 | *
13 | * @author Gadfly
14 | * @since 2021-06-30 15:26
15 | */
16 | @Slf4j
17 | @Component
18 | @MappedTypes(value = {Long[].class})
19 | @MappedJdbcTypes(value = {JdbcType.OTHER}, includeNullJdbcType = true)
20 | public class LongArrayJsonTypeHandler extends ArrayObjectJsonTypeHandler {
21 | public LongArrayJsonTypeHandler() {
22 | super(Long[].class);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/document.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/youlai-common/common-mybatis/src/main/java/com/youlai/common/mybatis/handler/IntegerArrayJsonTypeHandler.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.mybatis.handler;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.apache.ibatis.type.JdbcType;
5 | import org.apache.ibatis.type.MappedJdbcTypes;
6 | import org.apache.ibatis.type.MappedTypes;
7 | import org.springframework.stereotype.Component;
8 |
9 | /**
10 | * Integer 数组类型转换 json
11 | * https://www.jianshu.com/p/ab832f3fe81c
12 | *
13 | * @author Gadfly
14 | * @since 2021-06-30 15:19
15 | */
16 | @Slf4j
17 | @Component
18 | @MappedTypes(value = {Integer[].class})
19 | @MappedJdbcTypes(value = {JdbcType.VARCHAR}, includeNullJdbcType = true)
20 | public class IntegerArrayJsonTypeHandler extends ArrayObjectJsonTypeHandler {
21 | public IntegerArrayJsonTypeHandler() {
22 | super(Integer[].class);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/vo/RolePageVO.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.vo;
2 |
3 | import com.fasterxml.jackson.annotation.JsonFormat;
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 | import lombok.Data;
6 |
7 | import java.time.LocalDateTime;
8 |
9 | @Schema(description ="角色分页对象")
10 | @Data
11 | public class RolePageVO {
12 |
13 | @Schema(description="角色ID")
14 | private Long id;
15 |
16 | @Schema(description="角色名称")
17 | private String name;
18 |
19 | @Schema(description="角色编码")
20 | private String code;
21 |
22 | @Schema(description="角色状态")
23 | private Integer status;
24 |
25 | @Schema(description="排序")
26 | private Integer sort;
27 |
28 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
29 | private LocalDateTime createTime;
30 |
31 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
32 | private LocalDateTime updateTime;
33 | }
34 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/eye.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vue-admin/src/layout/components/Settings/components/ThemeColorPicker.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
36 |
37 |
42 |
--------------------------------------------------------------------------------
/youlai-common/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | youlai-cloud
9 | com.youlai
10 | 0.0.1
11 |
12 |
13 | youlai-common
14 | pom
15 |
16 |
17 | common-apidoc
18 | common-core
19 | common-redis
20 | common-web
21 | common-mybatis
22 | common-security
23 | common-sms
24 |
25 |
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Example SysUserDetails template template
3 | ### Example SysUserDetails template
4 |
5 | # IntelliJ project files
6 | .idea
7 | *.iml
8 | out
9 | gen
10 | target
11 | *.log
12 |
13 | # Nacos
14 | !**/nacos/target
15 | **/nacos/bin/work
16 | **/nacos/data
17 | logs
18 | **/nacos/LICENSE
19 | **/nacos/NOTICE
20 |
21 | # Canal
22 | h2.mv.db
23 | **/meta.dat
24 |
25 | # https://raw.githubusercontent.com/redhat-developer/vscode-java/master/.gitignore
26 | # vscode
27 | server
28 | node_modules
29 | *.vsix
30 | .DS_Store
31 | .vscode-test
32 | undefined
33 | dist
34 | jre
35 | .settings
36 | .classpath
37 | .project
38 | test/resources/projects/**/.vscode
39 | test/resources/projects/maven/salut/testGradle
40 |
41 |
42 |
43 | *.local
44 | .history
45 |
46 | # Editor directories and files
47 | *.suo
48 | *.ntvs*
49 | *.njsproj
50 | *.sln
51 |
52 | package-lock.json
53 | pnpm-lock.yaml
54 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/handler/UserBlockHandler.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.handler;
2 |
3 | import com.alibaba.csp.sentinel.slots.block.BlockException;
4 | import com.youlai.common.result.Result;
5 | import com.youlai.system.model.vo.UserInfoVO;
6 | import lombok.extern.slf4j.Slf4j;
7 |
8 | /**
9 | * 用户接口降级逻辑
10 | * @author haoxr
11 | * @createTime 2021/4/23 23:30
12 | */
13 | @Slf4j
14 | public class UserBlockHandler {
15 |
16 | /**
17 | * 获取当前登录用户信息的熔断降级处理
18 | * @param blockException
19 | * @return
20 | */
21 | public static Result handleGetCurrentUserBlock(BlockException blockException) {
22 | return Result.success(new UserInfoVO());
23 | }
24 |
25 |
26 | public static Result handleGetUserByUsernameBlock(String username,BlockException blockException){
27 | log.info("降级了:{}",username);
28 | return Result.failed("降级了");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/user.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/youlai-common/common-web/src/main/java/com/youlai/common/web/config/FeignDecoderConfig.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.web.config;
2 |
3 | import com.youlai.common.web.decoder.FeignDecoder;
4 | import feign.codec.Decoder;
5 | import feign.optionals.OptionalDecoder;
6 | import org.springframework.beans.factory.ObjectProvider;
7 | import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
8 | import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
9 | import org.springframework.cloud.openfeign.support.SpringDecoder;
10 | import org.springframework.context.annotation.Bean;
11 |
12 | /**
13 | *
14 | * @author haoxr
15 | * @since 2023/8/24
16 | */
17 | public class FeignDecoderConfig {
18 |
19 | @Bean
20 | public Decoder feignDecoder(ObjectProvider messageConverters) {
21 | return new OptionalDecoder((new ResponseEntityDecoder(new FeignDecoder(new SpringDecoder(messageConverters)))));
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/vue-admin/src/api/auth/types.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 登录请求参数
3 | */
4 | export interface LoginData {
5 | /**
6 | * 用户名
7 | */
8 | username: string;
9 | /**
10 | * 密码
11 | */
12 | password: string;
13 | /**
14 | * 授权类型
15 | */
16 | grant_type?: string;
17 | /**
18 | * 验证码Code
19 | */
20 | captchaCode?: string;
21 | /**
22 | * 验证码唯一标识(UUID)
23 | */
24 | captchaId?: string;
25 | }
26 |
27 | /**
28 | * 登录响应
29 | */
30 | export interface LoginResult {
31 | /**
32 | * 访问token
33 | */
34 | access_token?: string;
35 | /**
36 | * 过期时间(单位:毫秒)
37 | */
38 | expires?: number;
39 | /**
40 | * 刷新token
41 | */
42 | refresh_token?: string;
43 | /**
44 | * token 类型
45 | */
46 | token_type?: string;
47 | }
48 |
49 | /**
50 | * 验证码响应
51 | */
52 | export interface CaptchaResult {
53 | /**
54 | * 验证码缓存key
55 | */
56 | captchaId: string;
57 | /**
58 | * 验证码图片Base64字符串
59 | */
60 | captchaBase64: string;
61 | }
62 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/uv.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/dict_item.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/link.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/youlai-auth/src/main/java/com/youlai/auth/oauth2/jackson/SysUserMixin.java:
--------------------------------------------------------------------------------
1 | package com.youlai.auth.oauth2.jackson;
2 |
3 | import com.fasterxml.jackson.annotation.JsonAutoDetect;
4 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
5 | import com.fasterxml.jackson.annotation.JsonTypeInfo;
6 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
7 |
8 | /**
9 | * SysUserDetails 反序列化注册
10 | *
11 | * 刷新模式根据 refresh_token 从 oauth2_authorization 表中获取字段 attributes 内容反序列化成
12 | *
13 | * @author haoxr
14 | * @see org.springframework.security.jackson2.UserMixin
15 | * @since 2023/7/4
16 | */
17 | @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY)
18 | @JsonDeserialize(using = SysUserDeserializer.class)
19 | @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE)
20 | @JsonIgnoreProperties(ignoreUnknown = true)
21 | public class SysUserMixin {
22 | }
23 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/advert.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/youlai-common/common-web/src/main/java/com/youlai/common/web/constraint/CheckCityValid.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.web.constraint;
2 |
3 | import jakarta.validation.Constraint;
4 | import jakarta.validation.Payload;
5 | import java.lang.annotation.Documented;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.Target;
8 |
9 | import static java.lang.annotation.ElementType.*;
10 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
11 |
12 | /**
13 | * 校验城市地名等是否合法,不接受null
14 | *
15 | * @author Gadfly
16 | * @since 2021-08-06 16:02
17 | */
18 | @Documented
19 | @Constraint(validatedBy = CityValidator.class)
20 | @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
21 | @Retention(RUNTIME)
22 | public @interface CheckCityValid {
23 | /* 校验字段类型 */
24 | CityType value() default CityType.CITY;
25 |
26 | String message() default "{city.valid}";
27 |
28 | Class>[] groups() default {};
29 |
30 | Class extends Payload>[] payload() default {};
31 | }
32 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/resources/mapper/SysRoleMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
27 |
28 |
--------------------------------------------------------------------------------
/vue-admin/src/components/SizeSelect/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
14 | {{ item.label }}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
36 |
--------------------------------------------------------------------------------
/vue-admin/src/assets/icons/download.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/youlai-common/common-core/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | youlai-common
7 | com.youlai
8 | 0.0.1
9 |
10 | 4.0.0
11 |
12 | common-core
13 |
14 |
15 |
16 |
17 | io.swagger.core.v3
18 | swagger-annotations
19 |
20 |
21 |
22 |
23 | com.baomidou
24 | mybatis-plus-spring-boot3-starter
25 | true
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/resources/mapper/SysUserRoleMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
16 |
17 |
18 |
19 |
30 |
31 |
--------------------------------------------------------------------------------
/vue-admin/src/layout/components/Sidebar/components/SidebarMenuItemTitle.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{ translateRouteTitle(title) }}
8 |
9 |
10 |
24 |
25 |
43 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/entity/SysDept.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.youlai.common.base.BaseEntity;
6 | import lombok.Data;
7 |
8 | /**
9 | * 部门表
10 | */
11 | @Data
12 | public class SysDept extends BaseEntity {
13 | /**
14 | * 主键
15 | */
16 | @TableId(type = IdType.AUTO)
17 | private Long id;
18 |
19 | /**
20 | * 部门名称
21 | */
22 | private String name;
23 |
24 | /**
25 | * 父节点id
26 | */
27 | private Long parentId;
28 |
29 | /**
30 | * 父节点id路径
31 | */
32 | private String treePath;
33 |
34 | /**
35 | * 显示顺序
36 | */
37 | private Integer sort;
38 |
39 | /**
40 | * 状态(1:正常;0:禁用)
41 | */
42 | private Integer status;
43 |
44 | /**
45 | * 逻辑删除标识(1:已删除;0:未删除)
46 | */
47 | private Integer deleted;
48 |
49 | /* private Long createBy;
50 |
51 | private Long updateBy;*/
52 |
53 | }
--------------------------------------------------------------------------------
/vue-admin/src/api/system/dept/types.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * 部门查询参数
3 | */
4 | export interface DeptQuery {
5 | keywords?: string;
6 | status?: number;
7 | }
8 |
9 | /**
10 | * 部门类型
11 | */
12 | export interface DeptVO {
13 | /**
14 | * 子部门
15 | */
16 | children?: DeptVO[];
17 | /**
18 | * 创建时间
19 | */
20 | createTime?: Date;
21 | /**
22 | * 部门ID
23 | */
24 | id?: number;
25 | /**
26 | * 部门名称
27 | */
28 | name?: string;
29 | /**
30 | * 父部门ID
31 | */
32 | parentId?: number;
33 | /**
34 | * 排序
35 | */
36 | sort?: number;
37 | /**
38 | * 状态(1:启用;0:禁用)
39 | */
40 | status?: number;
41 | /**
42 | * 修改时间
43 | */
44 | updateTime?: Date;
45 | }
46 |
47 | /**
48 | * 部门表单类型
49 | */
50 | export interface DeptForm {
51 | /**
52 | * 部门ID(新增不填)
53 | */
54 | id?: number;
55 | /**
56 | * 部门名称
57 | */
58 | name?: string;
59 | /**
60 | * 父部门ID
61 | */
62 | parentId: number;
63 | /**
64 | * 排序
65 | */
66 | sort?: number;
67 | /**
68 | * 状态(1:启用;0:禁用)
69 | */
70 | status?: number;
71 | }
72 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/entity/SysRole.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.entity;
2 |
3 | import com.baomidou.mybatisplus.annotation.IdType;
4 | import com.baomidou.mybatisplus.annotation.TableId;
5 | import com.baomidou.mybatisplus.annotation.TableName;
6 | import com.youlai.common.base.BaseEntity;
7 | import lombok.Data;
8 |
9 | /**
10 | * 角色表
11 | */
12 | @TableName(value ="sys_role")
13 | @Data
14 | public class SysRole extends BaseEntity {
15 | /**
16 | *
17 | */
18 | @TableId(type = IdType.AUTO)
19 | private Long id;
20 |
21 | /**
22 | * 角色名称
23 | */
24 | private String name;
25 |
26 | /**
27 | * 角色编码
28 | */
29 | private String code;
30 |
31 | /**
32 | * 显示顺序
33 | */
34 | private Integer sort;
35 |
36 | /**
37 | * 角色状态(1-正常;0-停用)
38 | */
39 | private Integer status;
40 |
41 | /**
42 | * 逻辑删除标识(0-未删除;1-已删除)
43 | */
44 | private Integer deleted;
45 |
46 | /**
47 | * 数据权限
48 | */
49 | private Integer dataScope;
50 | }
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/service/SysRoleMenuService.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.service;
2 |
3 |
4 | import com.baomidou.mybatisplus.extension.service.IService;
5 | import com.youlai.system.model.entity.SysRoleMenu;
6 |
7 | import java.util.List;
8 |
9 | /**
10 | * 角色菜单业务接口
11 | *
12 | * @author haoxr
13 | * @since 0.0.1
14 | */
15 | public interface SysRoleMenuService extends IService {
16 |
17 | /**
18 | * 获取角色拥有的菜单ID集合
19 | *
20 | * @param roleId
21 | * @return
22 | */
23 | List listMenuIdsByRoleId(Long roleId);
24 |
25 |
26 | /**
27 | * 刷新权限缓存(所有角色)
28 | */
29 | void refreshRolePermsCache();
30 |
31 | /**
32 | * 刷新权限缓存(指定角色)
33 | *
34 | * @param roleCode 角色编码
35 | */
36 | void refreshRolePermsCache(String roleCode);
37 |
38 | /**
39 | * 刷新权限缓存(修改角色编码时调用)
40 | *
41 | * @param oldRoleCode 旧角色编码
42 | * @param newRoleCode 新角色编码
43 | */
44 | void refreshRolePermsCache(String oldRoleCode, String newRoleCode);
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/vo/UserProfileVO.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.vo;
2 |
3 | import io.swagger.v3.oas.annotations.media.Schema;
4 | import lombok.Data;
5 |
6 | import java.util.Set;
7 |
8 | /**
9 | * 个人中心用户视图对象
10 | *
11 | * @author haoxr
12 | * @since 2022/1/14
13 | */
14 | @Schema(description ="个人中心用户视图对象")
15 | @Data
16 | public class UserProfileVO {
17 |
18 | @Schema(description="用户ID")
19 | private Long id;
20 |
21 | @Schema(description="登录账号")
22 | private String username;
23 |
24 | @Schema(description="用户昵称")
25 | private String nickname;
26 |
27 | @Schema(description="手机号码")
28 | private String mobile;
29 |
30 | @Schema(description="头像地址")
31 | private String avatar;
32 |
33 | @Schema(description="用户角色名称集合")
34 | private Set roleNames;
35 |
36 | @Schema(description="部门名称")
37 | private String deptName;
38 |
39 | @Schema(description="邮箱")
40 | private String email;
41 |
42 | @Schema(description="性别")
43 | private String genderLabel;
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/youlai-system/system-boot/src/main/java/com/youlai/system/model/form/UserRegisterForm.java:
--------------------------------------------------------------------------------
1 | package com.youlai.system.model.form;
2 |
3 | import io.swagger.v3.oas.annotations.media.Schema;
4 | import jakarta.validation.constraints.NotBlank;
5 | import jakarta.validation.constraints.NotEmpty;
6 | import jakarta.validation.constraints.Pattern;
7 | import lombok.Data;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * 用户注册表单
13 | *
14 | * @author haoxr
15 | * @since 3.1.0
16 | */
17 | @Schema(description = "用户注册表单")
18 | @Data
19 | public class UserRegisterForm {
20 |
21 | @Schema(description="登录账号")
22 | @NotBlank(message = "登录账号不能为空")
23 | private String username;
24 |
25 | @Schema(description="手机号码")
26 | @Pattern(regexp = "^$|^1(3\\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\\d|9[0-35-9])\\d{8}$", message = "手机号码格式不正确")
27 | private String mobile;
28 |
29 | @Schema(description="密码")
30 | @NotBlank(message = "密码不能为空")
31 | private String password;
32 |
33 | @Schema(description="验证码")
34 | @NotBlank(message = "验证码不能为空")
35 | private String code;
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/vue-admin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "esnext",
4 | "useDefineForClassFields": true,
5 | "module": "esnext",
6 | "moduleResolution": "node",
7 | "strict": true,
8 | "noLib": false,
9 | "sourceMap": true,
10 | "resolveJsonModule": true,
11 | "esModuleInterop": true,
12 | "lib": ["esnext", "dom"],
13 | "baseUrl": ".",
14 | "allowJs": true,
15 | "paths": {
16 | "@/*": ["src/*"]
17 | },
18 | "types": ["vite/client", "unplugin-icons/types/vue", "element-plus/global"],
19 | "skipLibCheck": true /* Skip type checking all .d.ts files. */,
20 | "allowSyntheticDefaultImports": true /* 允许默认导入 */,
21 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
22 |
23 | "jsx": "preserve",
24 | "jsxFactory": "h",
25 | "jsxFragmentFactory": "Fragment"
26 | },
27 | "include": [
28 | "src/**/*.ts",
29 | "src/**/*.vue",
30 | "src/types/**/*.d.ts",
31 | "mock/**/*.ts",
32 | "vite.config.ts"
33 | ],
34 | "exclude": ["node_modules", "dist", "**/*.js"]
35 | }
36 |
--------------------------------------------------------------------------------
/youlai-common/common-web/src/main/java/com/youlai/common/web/model/Option.java:
--------------------------------------------------------------------------------
1 | package com.youlai.common.web.model;
2 |
3 | import com.fasterxml.jackson.annotation.JsonInclude;
4 | import io.swagger.v3.oas.annotations.media.Schema;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * 下拉选项对象
12 | *
13 | * @author haoxr
14 | * @since 2022/1/22
15 | */
16 | @Schema(description ="下拉选项对象")
17 | @Data
18 | @NoArgsConstructor
19 | public class Option {
20 |
21 | public Option(T value, String label) {
22 | this.value = value;
23 | this.label = label;
24 | }
25 |
26 | public Option(T value, String label, List