<|start_filename|>yudao-admin-ui/src/api/infra/apiAccessLog.js<|end_filename|>
import request from '@/utils/request'

// 获得API 访问日志分页
export function getApiAccessLogPage(query) {
  return request({
    url: '/infra/api-access-log/page',
    method: 'get',
    params: query
  })
}

// 导出API 访问日志 Excel
export function exportApiAccessLogExcel(query) {
  return request({
    url: '/infra/api-access-log/export-excel',
    method: 'get',
    params: query,
    responseType: 'blob'
  })
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/databind/LocalDateTimeDeserializer.java<|end_filename|>
package cn.iocoder.yudao.framework.jackson.core.databind;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;

import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;

/**
 * LocalDateTime反序列化规则
 * <p>
 * 会将毫秒级时间戳反序列化为LocalDateTime
 */
public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    public static final LocalDateTimeDeserializer INSTANCE = new LocalDateTimeDeserializer();

    @Override
    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(p.getValueAsLong()), ZoneId.systemDefault());
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysUserSessionServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.auth.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.auth.SysUserSessionMapper;
import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginLogTypeEnum;
import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginResultEnum;
import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysUserSessionService;
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.redis.auth.SysLoginUserCoreRedisDAO;
import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService;
import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;

/**
 * 在线用户 Session Service 实现类
 *
 * @author 芋道源码
 */
@Slf4j
@Service
public class SysUserSessionServiceImpl implements SysUserSessionService {

    @Resource
    private SysUserSessionMapper userSessionMapper;
    @Resource
    private SysUserService userService;
    @Resource
    private SysLoginLogCoreService loginLogCoreService;

    @Resource
    private SysLoginUserCoreRedisDAO loginUserCoreRedisDAO;

    @Override
    public PageResult<SysUserSessionDO> getUserSessionPage(SysUserSessionPageReqVO reqVO) {
        // 处理基于用户昵称的查询
        Collection<Long> userIds = null;
        if (StrUtil.isNotEmpty(reqVO.getUsername())) {
            userIds = convertSet(userService.getUsersByUsername(reqVO.getUsername()), SysUserDO::getId);
            if (CollUtil.isEmpty(userIds)) {
                return PageResult.empty();
            }
        }
        return userSessionMapper.selectPage(reqVO, userIds);
    }

    // TODO @芋艿：优化下该方法
    @Override
    public long clearSessionTimeout() {
        // 获取db里已经超时的用户列表
        List<SysUserSessionDO> sessionTimeoutDOS = userSessionMapper.selectListBySessionTimoutLt();
        Map<String, SysUserSessionDO> timeoutSessionDOMap = sessionTimeoutDOS
                .stream()
                .filter(sessionDO -> loginUserCoreRedisDAO.get(sessionDO.getId()) == null)
                .collect(Collectors.toMap(SysUserSessionDO::getId, o -> o));
        // 确认已经超时,按批次移出在线用户列表
        if (CollUtil.isNotEmpty(timeoutSessionDOMap)) {
            Lists.partition(new ArrayList<>(timeoutSessionDOMap.keySet()), 100)
                    .forEach(userSessionMapper::deleteBatchIds);
            // 记录用户超时退出日志
            createTimeoutLogoutLog(timeoutSessionDOMap.values());
        }
        return timeoutSessionDOMap.size();
    }

    private void createTimeoutLogoutLog(Collection<SysUserSessionDO> timeoutSessionDOS) {
        for (SysUserSessionDO timeoutSessionDO : timeoutSessionDOS) {
            SysLoginLogCreateReqDTO reqDTO = new SysLoginLogCreateReqDTO();
            reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_TIMEOUT.getType());
            reqDTO.setTraceId(TracerUtils.getTraceId());
            reqDTO.setUserId(timeoutSessionDO.getUserId());
            reqDTO.setUserType(timeoutSessionDO.getUserType());
            reqDTO.setUsername(timeoutSessionDO.getUsername());
            reqDTO.setUserAgent(timeoutSessionDO.getUserAgent());
            reqDTO.setUserIp(timeoutSessionDO.getUserIp());
            reqDTO.setResult(SysLoginResultEnum.SUCCESS.getResult());
            loginLogCoreService.createLoginLog(reqDTO);
        }
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-swipe-action-item/nvue - backup.js<|end_filename|>
// nvue操作dom的库，用于获取dom的尺寸信息
const dom = uni.requireNativePlugin('dom')
// nvue中用于操作元素动画的库，类似于uni.animation，只不过uni.animation不能用于nvue
const animation = uni.requireNativePlugin('animation')

export default {
    data() {
        return {
            // 是否滑动中
            moving: false,
            // 状态，open-打开状态，close-关闭状态
            status: 'close',
            // 开始触摸点的X和Y轴坐标
            startX: 0,
            startY: 0,
            // 所有隐藏按钮的尺寸信息数组
            buttons: [],
            // 所有按钮的总宽度
            buttonsWidth: 0,
            // 记录上一次移动的位置值
            moveX: 0,
            // 记录上一次滑动的位置，用于前后两次做对比，如果移动的距离小于某一阈值，则认为前后之间没有移动，为了解决可能存在的通信阻塞问题
            lastX: 0
        }
    },
    computed: {
        // 获取过渡时间
        getDuratin() {
            let duration = String(this.duration)
            // 如果ms为单位，返回ms的数值部分
            if (duration.indexOf('ms') >= 0) return parseInt(duration)
            // 如果s为单位，为了得到ms的数值，需要乘以1000
            if (duration.indexOf('s') >= 0) return parseInt(duration) * 1000
            // 如果值传了数值，且小于30，认为是s单位
            duration = Number(duration)
            return duration < 30 ? duration * 1000 : duration
        }
    },
    watch: {
        show: {
            immediate: true,
            handler(n) {
                // if(n === true) {
                // 	uni.$u.sleep(50).then(() => {
                // 		this.openSwipeAction()
                // 	})
                // } else {
                // 	this.closeSwipeAction()
                // }
            }
        }
    },
    mounted() {
        uni.$u.sleep(20).then(() => {
            this.queryRect()
        })
    },
    methods: {
        close() {
            this.closeSwipeAction()
        },
        // 触摸单元格
        touchstart(event) {
            if (this.disabled) return
            this.closeOther()
            const { touches } = event
            // 记录触摸开始点的坐标值
            this.startX = touches[0].pageX
            this.startY = touches[0].pageY
        },
        // // 触摸滑动
        touchmove(event) {
            if (this.disabled) return
            const { touches } = event
            const { pageX } = touches[0]
            const { pageY } = touches[0]
            let moveX = pageX - this.startX
            const moveY = pageY - this.startY
            const { buttonsWidth } = this
            const len = this.buttons.length

            // 判断前后两次的移动距离，如果小于一定值，则不进行移动处理
            if (Math.abs(pageX - this.lastX) < 0.3) return
            this.lastX = pageX

            // 移动的X轴距离大于Y轴距离，也即终点与起点位置连线，与X轴夹角小于45度时，禁止页面滚动
            if (Math.abs(moveX) > Math.abs(moveY) || Math.abs(moveX) > this.threshold) {
                event.stopPropagation()
            }
            // 如果移动的X轴距离小于Y轴距离，也即终点位置与起点位置连线，与Y轴夹角小于45度时，认为是页面上下滑动，而不是左右滑动单元格
            if (Math.abs(moveX) < Math.abs(moveY)) return

            // 限制右滑的距离，不允许内容部分往右偏移，右滑会导致X轴偏移值大于0，以此做判断
            // 此处不能直接return，因为滑动过程中会缺失某些关键点坐标，会导致错乱，最好的办法就是
            // 在超出后，设置为0
            if (this.status === 'open') {
                // 在开启状态下，向左滑动，需忽略
                if (moveX < 0) moveX = 0
                // 想要收起菜单，最大能移动的距离为按钮的总宽度
                if (moveX > buttonsWidth) moveX = buttonsWidth
                // 如果是已经打开了的状态，向左滑动时，移动收起菜单
                this.moveSwipeAction(-buttonsWidth + moveX)
            } else {
                // 关闭状态下，右滑动需忽略
                if (moveX > 0) moveX = 0
                // 滑动的距离不允许超过所有按钮的总宽度，此时只能是左滑，最终设置按钮的总宽度，同时为负数
                if (Math.abs(moveX) > buttonsWidth) moveX = -buttonsWidth
                // 只要是在滑过程中，就不断移动菜单的内容部分，从而使隐藏的菜单显示出来
                this.moveSwipeAction(moveX)
            }
        },
        // 单元格结束触摸
        touchend(event) {
            if (this.disabled) return
            const touches = event.changedTouches ? event.changedTouches[0] : {}
            const { pageX } = touches
            const { pageY } = touches
            const { buttonsWidth } = this
            this.moveX = pageX - this.startX
            if (this.status === 'open') {
                // 在展开的状态下，继续左滑，无需操作
                if (this.moveX < 0) this.moveX = 0
                if (this.moveX > buttonsWidth) this.moveX = buttonsWidth
                // 在开启状态下，点击一下内容区域，moveX为0，也即没有进行移动，这时执行收起菜单逻辑
                if (this.moveX === 0) {
                    return this.closeSwipeAction()
                }
                // 在开启状态下，滑动距离小于阈值，则默认为不关闭，同时恢复原来的打开状态
                if (Math.abs(this.moveX) < this.threshold) {
                    this.openSwipeAction()
                } else {
                    // 如果滑动距离大于阈值，则执行收起逻辑
                    this.closeSwipeAction()
                }
            } else {
                // 在关闭的状态下，右滑，无需操作
                if (this.moveX >= 0) this.moveX = 0
                if (this.moveX <= -buttonsWidth) this.moveX = -buttonsWidth
                // 理由同上
                if (Math.abs(this.moveX) < this.threshold) {
                    this.closeSwipeAction()
                } else {
                    this.openSwipeAction()
                }
            }
        },
        // 移动滑动选择器内容区域，同时显示出其隐藏的菜单
        moveSwipeAction(moveX) {
            if (this.moving) return
            this.moving = true

            let previewButtonsMoveX = 0
            const len = this.buttons.length
            animation.transition(this.$refs['u-swipe-action-item__content'].ref, {
                styles: {
                    transform: `translateX(${moveX}px)`
                },
                timingFunction: 'linear'
            }, () => {
                this.moving = false
            })
            // 按钮的组的长度
            for (let i = len - 1; i >= 0; i--) {
                const buttonRef = this.$refs[`u-swipe-action-item__right__button-${i}`][0].ref
                // 通过比例，得出元素自身该移动的距离
                const translateX = this.buttons[i].width / this.buttonsWidth * moveX
                // 最终移动的距离，是通过自身比例算出的距离，再加上在它之前所有按钮移动的距离之和
                const realTranslateX = translateX + previewButtonsMoveX
                animation.transition(buttonRef, {
                    styles: {
                        transform: `translateX(${realTranslateX}px)`
                    },
                    duration: 0,
                    delay: 0,
                    timingFunction: 'linear'
                }, () => {})
                // 记录本按钮之前的所有按钮的移动距离之和
                previewButtonsMoveX += translateX
            }
        },
        // 关闭菜单
        closeSwipeAction() {
            if (this.status === 'close') return
            this.moving = true
            const { buttonsWidth } = this
            animation.transition(this.$refs['u-swipe-action-item__content'].ref, {
                styles: {
                    transform: 'translateX(0px)'
                },
                duration: this.getDuratin,
                timingFunction: 'ease-in-out'
            }, () => {
                this.status = 'close'
                this.moving = false
                this.closeHandler()
            })
            // 按钮的组的长度
            const len = this.buttons.length
            for (let i = len - 1; i >= 0; i--) {
                const buttonRef = this.$refs[`u-swipe-action-item__right__button-${i}`][0].ref
                // 如果不满足边界条件，返回
                if (this.buttons.length === 0 || !this.buttons[i] || !this.buttons[i].width) return

                animation.transition(buttonRef, {
                    styles: {
                        transform: 'translateX(0px)'
                    },
                    duration: this.getDuratin,
                    timingFunction: 'ease-in-out'
                }, () => {})
            }
        },
        // 打开菜单
        openSwipeAction() {
            if (this.status === 'open') return
            this.moving = true
            const buttonsWidth = -this.buttonsWidth
            let previewButtonsMoveX = 0
            animation.transition(this.$refs['u-swipe-action-item__content'].ref, {
                styles: {
                    transform: `translateX(${buttonsWidth}px)`
                },
                duration: this.getDuratin,
                timingFunction: 'ease-in-out'
            }, () => {
                this.status = 'open'
                this.moving = false
                this.openHandler()
            })
            // 按钮的组的长度
            const len = this.buttons.length
            for (let i = len - 1; i >= 0; i--) {
                const buttonRef = this.$refs[`u-swipe-action-item__right__button-${i}`][0].ref
                // 如果不满足边界条件，返回
                if (this.buttons.length === 0 || !this.buttons[i] || !this.buttons[i].width) return
                // 通过比例，得出元素自身该移动的距离
                const translateX = this.buttons[i].width / this.buttonsWidth * buttonsWidth
                // 最终移动的距离，是通过自身比例算出的距离，再加上在它之前所有按钮移动的距离之和
                const realTranslateX = translateX + previewButtonsMoveX
                animation.transition(buttonRef, {
                    styles: {
                        transform: `translateX(${realTranslateX}px)`
                    },
                    duration: this.getDuratin,
                    timingFunction: 'ease-in-out'
                }, () => {})
                previewButtonsMoveX += translateX
            }
        },
        // 查询按钮节点信息
        queryRect() {
            // 历遍所有按钮数组，通过getRectByDom返回一个promise
            const promiseAll = this.rightOptions.map((item, index) => this.getRectByDom(this.$refs[`u-swipe-action-item__right__button-${index}`][0]))
            // 通过promise.all方法，让所有按钮的查询结果返回一个数组的形式
            Promise.all(promiseAll).then((sizes) => {
                this.buttons = sizes
                // 计算所有按钮总宽度
                this.buttonsWidth = sizes.reduce((sum, cur) => sum + cur.width, 0)
            })
        },
        // 通过nvue的dom模块，查询节点信息
        getRectByDom(ref) {
            return new Promise((resolve) => {
                dom.getComponentRect(ref, (res) => {
                    resolve(res.size)
                })
            })
        }
    }
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/SmsClientFactoryImpl.java<|end_filename|>
package cn.iocoder.yudao.framework.sms.core.client.impl;

import cn.iocoder.yudao.framework.sms.core.client.SmsClient;
import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.yudao.framework.sms.core.client.impl.aliyun.AliyunSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.debug.DebugDingTalkSmsClient;
import cn.iocoder.yudao.framework.sms.core.client.impl.yunpian.YunpianSmsClient;
import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;

import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 短信客户端工厂接口
 *
 * @author zzf
 */
@Validated
@Slf4j
public class SmsClientFactoryImpl implements SmsClientFactory {

    /**
     * 短信客户端 Map
     * key：渠道编号，使用 {@link SmsChannelProperties#getId()}
     */
    private final ConcurrentMap<Long, AbstractSmsClient> channelIdClients = new ConcurrentHashMap<>();

    /**
     * 短信客户端 Map
     * key：渠道编码，使用 {@link SmsChannelProperties#getCode()} ()}
     *
     * 注意，一些场景下，需要获得某个渠道类型的客户端，所以需要使用它。
     * 例如说，解析短信接收结果，是相对通用的，不需要使用某个渠道编号的 {@link #channelIdClients}
     */
    private final ConcurrentMap<String, AbstractSmsClient> channelCodeClients = new ConcurrentHashMap<>();

    public SmsClientFactoryImpl() {
        // 初始化 channelCodeClients 集合
        Arrays.stream(SmsChannelEnum.values()).forEach(channel -> {
            // 创建一个空的 SmsChannelProperties 对象
            SmsChannelProperties properties = new SmsChannelProperties().setCode(channel.getCode())
                    .setApiKey("default").setApiSecret("default");
            // 创建 Sms 客户端
            AbstractSmsClient smsClient = createSmsClient(properties);
            channelCodeClients.put(channel.getCode(), smsClient);
        });
    }

    @Override
    public SmsClient getSmsClient(Long channelId) {
        return channelIdClients.get(channelId);
    }

    @Override
    public SmsClient getSmsClient(String channelCode) {
        return channelCodeClients.get(channelCode);
    }

    @Override
    public void createOrUpdateSmsClient(SmsChannelProperties properties) {
        AbstractSmsClient client = channelIdClients.get(properties.getId());
        if (client == null) {
            client = this.createSmsClient(properties);
            client.init();
            channelIdClients.put(client.getId(), client);
        } else {
            client.refresh(properties);
        }
    }

    private AbstractSmsClient createSmsClient(SmsChannelProperties properties) {
        SmsChannelEnum channelEnum = SmsChannelEnum.getByCode(properties.getCode());
        Assert.notNull(channelEnum, String.format("渠道类型(%s) 为空", channelEnum));
        // 创建客户端
        switch (channelEnum) {
            case ALIYUN: return new AliyunSmsClient(properties);
            case YUN_PIAN: return new YunpianSmsClient(properties);
            case DEBUG_DING_TALK: return new DebugDingTalkSmsClient(properties);
        }
        // 创建失败，错误日志 + 抛出异常
        log.error("[createSmsClient][配置({}) 找不到合适的客户端实现]", properties);
        throw new IllegalArgumentException(String.format("配置(%s) 找不到合适的客户端实现", properties));
    }

}


<|start_filename|>yudao-admin-ui/src/utils/constants.js<|end_filename|>
/**
 * Created by 芋道源码
 *
 * 枚举类
 */

/**
 * 全局通用状态枚举
 */
export const SysCommonStatusEnum = {
  ENABLE: 0, // 开启
  DISABLE: 1 // 禁用
}

/**
 * 菜单的类型枚举
 */
export const SysMenuTypeEnum = {
  DIR : 1, // 目录
  MENU: 2, // 菜单
  BUTTON: 3 // 按钮
}

/**
 * 角色的类型枚举
 */
export const SysRoleTypeEnum = {
  SYSTEM: 1, // 内置角色
  CUSTOM: 2 // 自定义角色
}

/**
 * 数据权限的范围枚举
 */
export const SysDataScopeEnum = {
  ALL: 1, // 全部数据权限
  DEPT_CUSTOM: 2, // 指定部门数据权限
  DEPT_ONLY: 3, // 部门数据权限
  DEPT_AND_CHILD: 4, // 部门及以下数据权限
  DEPT_SELF: 5 // 仅本人数据权限
}

/**
 * 代码生成模板类型
 */
export const ToolCodegenTemplateTypeEnum = {
  CRUD: 1, // 基础 CRUD
  TREE: 2, // 树形 CRUD
  SUB: 3, // 主子表 CRUD
}

/**
 * 任务状态的枚举
 */
export const InfJobStatusEnum = {
  INIT: 0, // 初始化中
  NORMAL: 1, // 运行中
  STOP: 2, // 暂停运行
}

/**
 * API 异常数据的处理状态
 */
export const InfApiErrorLogProcessStatusEnum = {
  INIT: 0, // 未处理
  DONE: 1, // 已处理
  IGNORE: 2, // 已忽略
}

/**
 * 用户的社交平台的类型枚举
 */
export const SysUserSocialTypeEnum = {
  // GITEE: {
  //   title: "码云",
  //   type: 10,
  //   source: "gitee",
  //   img: "https://cdn.jsdelivr.net/gh/justauth/justauth-oauth-logo@1.11/gitee.png",
  // },
  DINGTALK: {
    title: "钉钉",
    type: 20,
    source: "dingtalk",
    img: "https://cdn.jsdelivr.net/gh/justauth/justauth-oauth-logo@1.11/dingtalk.png",
  },
  WECHAT_ENTERPRISE: {
    title: "企业微信",
    type: 30,
    source: "wechat_enterprise",
    img: "https://cdn.jsdelivr.net/gh/justauth/justauth-oauth-logo@1.11/wechat_enterprise.png",
  }
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/rate.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:05:09
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/rate.js
 */
export default {
    // rate组件
    rate: {
        value: 1,
        count: 5,
        disabled: false,
        size: 18,
        inactiveColor: '#b2b2b2',
        activeColor: '#FA3534',
        gutter: 4,
        minCount: 1,
        allowHalf: false,
        activeIcon: 'star-fill',
        inactiveIcon: 'star',
        touchable: true
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/notice/SysNoticeTypeEnum.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.enums.notice;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 通知类型
 *
 * @author 芋道源码
 */
@Getter
@AllArgsConstructor
public enum SysNoticeTypeEnum {

    NOTICE(1),
    ANNOUNCEMENT(2);

    /**
     * 类型
     */
    private final Integer type;

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsCodeMapping.java<|end_filename|>
package cn.iocoder.yudao.framework.sms.core.client.impl.yunpian;

import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;

import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.SUCCESS;
import static com.yunpian.sdk.constant.Code.*;

/**
 * 云片的 SmsCodeMapping 实现类
 * <p>
 * 参见 https://www.yunpian.com/official/document/sms/zh_CN/returnvalue_common 文档
 *
 * @author 芋道源码
 */
public class YunpianSmsCodeMapping implements SmsCodeMapping {

    @Override
    public ErrorCode apply(String apiCode) {
        int code = Integer.parseInt(apiCode);
        switch (code) {
            case OK:
                return SUCCESS;
            case ARGUMENT_MISSING:
                return SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR;
            case BAD_ARGUMENT_FORMAT:
                return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_PARAM_ERROR;
            case TPL_NOT_FOUND:
            case TPL_NOT_VALID:
                return SmsFrameworkErrorCodeConstants.SMS_TEMPLATE_INVALID;
            case MONEY_NOT_ENOUGH:
                return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_MONEY_NOT_ENOUGH;
            case BLACK_WORD:
                return SmsFrameworkErrorCodeConstants.SMS_SEND_CONTENT_INVALID;
            case DUP_IN_SHORT_TIME:
            case TOO_MANY_TIME_IN_5:
            case DAY_LIMIT_PER_MOBILE:
            case HOUR_LIMIT_PER_MOBILE:
                return SmsFrameworkErrorCodeConstants.SMS_SEND_BUSINESS_LIMIT_CONTROL;
            case BLACK_PHONE_FILTER:
                return SmsFrameworkErrorCodeConstants.SMS_MOBILE_BLACK;
            case SIGN_NOT_MATCH:
            case BAD_SIGN_FORMAT:
            case SIGN_NOT_VALID:
                return SmsFrameworkErrorCodeConstants.SMS_SIGN_INVALID;
            case BAD_API_KEY:
                return SmsFrameworkErrorCodeConstants.SMS_ACCOUNT_INVALID;
            case API_NOT_ALLOWED:
                return SmsFrameworkErrorCodeConstants.SMS_PERMISSION_DENY;
            case IP_NOT_ALLOWED:
                return SmsFrameworkErrorCodeConstants.SMS_IP_DENY;
            default:
                break;
        }
        return SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/collapse.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 16:56:30
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/collapse.js
 */
export default {
    // collapse 组件
    collapse: {
        value: null,
        accordion: false,
        border: true
    }
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/toolbar.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:24:55
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/toolbar.js
 */
export default {
    // toolbar 组件
    toolbar: {
        show: true,
        cancelText: '取消',
        confirmText: '确认',
        cancelColor: '#909193',
        confirmColor: '#3c9cff',
        title: ''
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/datetimePicker.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 16:57:48
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/datetimePicker.js
 */
export default {
    // datetimePicker 组件
    datetimePicker: {
        show: false,
        showToolbar: true,
        value: '',
        title: '',
        mode: 'datetime',
        maxDate: new Date(new Date().getFullYear() + 10, 0, 1).getTime(),
        minDate: new Date(new Date().getFullYear() - 10, 0, 1).getTime(),
        minHour: 0,
        maxHour: 23,
        minMinute: 0,
        maxMinute: 59,
        filter: null,
        formatter: null,
        loading: false,
        itemHeight: 44,
        cancelText: '取消',
        confirmText: '确认',
        cancelColor: '#909193',
        confirmColor: '#3c9cff',
        visibleItemCount: 5,
        closeOnClickOverlay: false,
        defaultIndex: () => []
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/sms/SysSmsTemplateService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.sms;

import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.template.SysSmsTemplateExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.template.SysSmsTemplatePageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import javax.validation.Valid;
import java.util.Collection;
import java.util.List;

/**
 * 短信模板 Service 接口
 *
 * @author zzf
 * @date 2021/1/25 9:24
 */
public interface SysSmsTemplateService {

    /**
     * 获得短信模板
     *
     * @param code 模板编码
     * @return 短信模板
     */
    SysSmsTemplateDO getSmsTemplateByCode(String code);

    /**
     * 创建短信模板
     *
     * @param createReqVO 创建信息
     * @return 编号
     */
    Long createSmsTemplate(@Valid SysSmsTemplateCreateReqVO createReqVO);

    /**
     * 更新短信模板
     *
     * @param updateReqVO 更新信息
     */
    void updateSmsTemplate(@Valid SysSmsTemplateUpdateReqVO updateReqVO);

    /**
     * 删除短信模板
     *
     * @param id 编号
     */
    void deleteSmsTemplate(Long id);

    /**
     * 获得短信模板
     *
     * @param id 编号
     * @return 短信模板
     */
    SysSmsTemplateDO getSmsTemplate(Long id);

    /**
     * 获得短信模板列表
     *
     * @param ids 编号
     * @return 短信模板列表
     */
    List<SysSmsTemplateDO> getSmsTemplateList(Collection<Long> ids);

    /**
     * 获得短信模板分页
     *
     * @param pageReqVO 分页查询
     * @return 短信模板分页
     */
    PageResult<SysSmsTemplateDO> getSmsTemplatePage(SysSmsTemplatePageReqVO pageReqVO);

    /**
     * 获得短信模板列表, 用于 Excel 导出
     *
     * @param exportReqVO 查询条件
     * @return 短信模板分页
     */
    List<SysSmsTemplateDO> getSmsTemplateList(SysSmsTemplateExportReqVO exportReqVO);

    /**
     * 获得指定短信渠道下的短信模板数量
     *
     * @param channelId 短信渠道编号
     * @return 数量
     */
    Integer countByChannelId(Long channelId);

}


<|start_filename|>yudao-admin-ui/src/components/bpmnProcessDesigner/src/highlight/index.js<|end_filename|>
const hljs = require("highlight.js/lib/core");
hljs.registerLanguage("xml", require("highlight.js/lib/languages/xml"));
hljs.registerLanguage("json", require("highlight.js/lib/languages/json"));

module.exports = hljs;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/convert/job/InfJobLogConvert.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.convert.job;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.infra.controller.job.vo.log.InfJobLogExcelVO;
import cn.iocoder.yudao.adminserver.modules.infra.controller.job.vo.log.InfJobLogRespVO;
import cn.iocoder.yudao.adminserver.modules.infra.dal.dataobject.job.InfJobLogDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import java.util.List;

/**
 * 定时任务日志 Convert
 *
 * @author 芋艿
 */
@Mapper
public interface InfJobLogConvert {

    InfJobLogConvert INSTANCE = Mappers.getMapper(InfJobLogConvert.class);

    InfJobLogRespVO convert(InfJobLogDO bean);

    List<InfJobLogRespVO> convertList(List<InfJobLogDO> list);

    PageResult<InfJobLogRespVO> convertPage(PageResult<InfJobLogDO> page);

    List<InfJobLogExcelVO> convertList02(List<InfJobLogDO> list);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/mq/consumer/config/InfConfigRefreshConsumer.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.mq.consumer.config;

import cn.iocoder.yudao.framework.apollo.internals.DBConfigRepository;
import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
import cn.iocoder.yudao.adminserver.modules.infra.mq.message.config.InfConfigRefreshMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 针对 {@link InfConfigRefreshMessage} 的消费者
 *
 * @author 芋道源码
 */
@Component
@Slf4j
public class InfConfigRefreshConsumer extends AbstractChannelMessageListener<InfConfigRefreshMessage> {

    @Override
    public void onMessage(InfConfigRefreshMessage message) {
        log.info("[onMessage][收到 Config 刷新消息]");
        DBConfigRepository.noticeSync();
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-steps-item/props.js<|end_filename|>
export default {
    props: {
        // 标题
        title: {
            type: [String, Number],
            default: uni.$u.props.stepsItem.title
        },
        // 描述文本
        desc: {
            type: [String, Number],
            default: uni.$u.props.stepsItem.desc
        },
        // 图标大小
        iconSize: {
            type: [String, Number],
            default: uni.$u.props.stepsItem.iconSize
        },
        // 当前步骤是否处于失败状态
        error: {
            type: Boolean,
            default: uni.$u.props.stepsItem.error
        }
    }
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/config/YudaoJacksonAutoConfiguration.java<|end_filename|>
package cn.iocoder.yudao.framework.jackson.config;

import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeDeserializer;
import cn.iocoder.yudao.framework.jackson.core.databind.LocalDateTimeSerializer;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.LocalDateTime;

@Slf4j
@Configuration
public class YudaoJacksonAutoConfiguration {

    @Bean
    public BeanPostProcessor objectMapperBeanPostProcessor() {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if (!(bean instanceof ObjectMapper)) {
                    return bean;
                }
                ObjectMapper objectMapper = (ObjectMapper) bean;
                SimpleModule simpleModule = new SimpleModule();
                /*
                 * 1. 新增Long类型序列化规则，数值超过2^53-1，在JS会出现精度丢失问题，因此Long自动序列化为字符串类型
                 * 2. 新增LocalDateTime序列化、反序列化规则
                 */
                simpleModule
//                .addSerializer(Long.class, ToStringSerializer.instance)
//                    .addSerializer(Long.TYPE, ToStringSerializer.instance)
                        .addSerializer(LocalDateTime.class, LocalDateTimeSerializer.INSTANCE)
                        .addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);

                objectMapper.registerModules(simpleModule);

                JsonUtils.init(objectMapper);
                log.info("初始化 jackson 自动配置");
                return bean;
            }
        };
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/overlay.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:06:50
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/overlay.js
 */
export default {
    // overlay组件
    overlay: {
        show: false,
        zIndex: 10070,
        duration: 300,
        opacity: 0.5
    }
}


<|start_filename|>yudao-admin-ui/src/api/infra/file.js<|end_filename|>
import request from '@/utils/request'

// 删除文件
export function deleteFile(id) {
  return request({
    url: '/infra/file/delete?id=' + id,
    method: 'delete'
  })
}

// 获得文件分页
export function getFilePage(query) {
  return request({
    url: '/infra/file/page',
    method: 'get',
    params: query
  })
}


<|start_filename|>yudao-admin-ui/src/components/bpmnProcessDesigner/package/penal/listeners/template.js<|end_filename|>
export const template = isTaskListener => {
  return `
  <div class="panel-tab__content">
    <el-table :data="elementListenersList" size="mini" border>
      <el-table-column label="序号" width="50px" type="index" />
      <el-table-column label="事件类型" min-width="100px" prop="event" />
      <el-table-column label="监听器类型" min-width="100px" show-overflow-tooltip :formatter="row => listenerTypeObject[row.listenerType]" />
      <el-table-column label="操作" width="90px">
        <template slot-scope="{ row, $index }">
          <el-button size="mini" type="text" @click="openListenerForm(row, $index)">编辑</el-button>
          <el-divider direction="vertical" />
          <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeListener(row, $index)">移除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <div class="element-drawer__button">
      <el-button size="mini" type="primary" icon="el-icon-plus" @click="openListenerForm(null)">添加监听器</el-button>
    </div>

    <!-- 监听器 编辑/创建 部分 -->
    <el-drawer :visible.sync="listenerFormModelVisible" title="执行监听器" :size="width + 'px'" append-to-body destroy-on-close>
      <el-form size="mini" :model="listenerForm" label-width="96px" ref="listenerFormRef" @submit.native.prevent>
        <el-form-item label="事件类型" prop="event" :rules="{ required: true, trigger: ['blur', 'change'] }">
          <el-select v-model="listenerForm.event">
            <el-option label="start" value="start" />
            <el-option label="end" value="end" />
          </el-select>
        </el-form-item>
        <el-form-item label="监听器类型" prop="listenerType" :rules="{ required: true, trigger: ['blur', 'change'] }">
          <el-select v-model="listenerForm.listenerType">
            <el-option v-for="i in Object.keys(listenerTypeObject)" :key="i" :label="listenerTypeObject[i]" :value="i" />
          </el-select>
        </el-form-item>
        <el-form-item
          v-if="listenerForm.listenerType === 'classListener'"
          label="Java类"
          prop="class"
          key="listener-class"
          :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <el-input v-model="listenerForm.class" clearable />
        </el-form-item>
        <el-form-item
          v-if="listenerForm.listenerType === 'expressionListener'"
          label="表达式"
          prop="expression"
          key="listener-expression"
          :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <el-input v-model="listenerForm.expression" clearable />
        </el-form-item>
        <el-form-item
          v-if="listenerForm.listenerType === 'delegateExpressionListener'"
          label="代理表达式"
          prop="delegateExpression"
          key="listener-delegate"
          :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <el-input v-model="listenerForm.delegateExpression" clearable />
        </el-form-item>
        <template v-if="listenerForm.listenerType === 'scriptListener'">
          <el-form-item
            label="脚本格式"
            prop="scriptFormat"
            key="listener-script-format"
            :rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本格式' }"
          >
            <el-input v-model="listenerForm.scriptFormat" clearable />
          </el-form-item>
          <el-form-item
            label="脚本类型"
            prop="scriptType"
            key="listener-script-type"
            :rules="{ required: true, trigger: ['blur', 'change'], message: '请选择脚本类型' }"
          >
            <el-select v-model="listenerForm.scriptType">
              <el-option label="内联脚本" value="inlineScript" />
              <el-option label="外部脚本" value="externalScript" />
            </el-select>
          </el-form-item>
          <el-form-item
            v-if="listenerForm.scriptType === 'inlineScript'"
            label="脚本内容"
            prop="value"
            key="listener-script"
            :rules="{ required: true, trigger: ['blur', 'change'], message: '请填写脚本内容' }"
          >
            <el-input v-model="listenerForm.value" clearable />
          </el-form-item>
          <el-form-item
            v-if="listenerForm.scriptType === 'externalScript'"
            label="资源地址"
            prop="resource"
            key="listener-resource"
            :rules="{ required: true, trigger: ['blur', 'change'], message: '请填写资源地址' }"
          >
            <el-input v-model="listenerForm.resource" clearable />
          </el-form-item>
        </template>
        ${
          isTaskListener
            ? "<el-form-item label='定时器类型' prop='eventDefinitionType' key='eventDefinitionType'>" +
              "<el-select v-model='listenerForm.eventDefinitionType'>" +
              "<el-option label='日期' value='date' />" +
              "<el-option label='持续时长' value='duration' />" +
              "<el-option label='循环' value='cycle' />" +
              "<el-option label='无' value='' />" +
              "</el-select>" +
              "</el-form-item>" +
              "<el-form-item v-if='!!listenerForm.eventDefinitionType' label='定时器' prop='eventDefinitions' key='eventDefinitions'>" +
              "<el-input v-model='listenerForm.eventDefinitions' clearable />" +
              "</el-form-item>"
            : ""
        }
      </el-form>
      <el-divider />
      <p class="listener-filed__title">
        <span><i class="el-icon-menu"></i>注入字段：</span>
        <el-button size="mini" type="primary" @click="openListenerFieldForm(null)">添加字段</el-button>
      </p>
      <el-table :data="fieldsListOfListener" size="mini" max-height="240" border fit style="flex: none">
        <el-table-column label="序号" width="50px" type="index" />
        <el-table-column label="字段名称" min-width="100px" prop="name" />
        <el-table-column label="字段类型" min-width="80px" show-overflow-tooltip :formatter="row => fieldTypeObject[row.fieldType]" />
        <el-table-column label="字段值/表达式" min-width="100px" show-overflow-tooltip :formatter="row => row.string || row.expression" />
        <el-table-column label="操作" width="100px">
          <template slot-scope="{ row, $index }">
            <el-button size="mini" type="text" @click="openListenerFieldForm(row, $index)">编辑</el-button>
            <el-divider direction="vertical" />
            <el-button size="mini" type="text" style="color: #ff4d4f" @click="removeListenerField(row, $index)">移除</el-button>
          </template>
        </el-table-column>
      </el-table>

      <div class="element-drawer__button">
        <el-button size="mini" @click="listenerFormModelVisible = false">取 消</el-button>
        <el-button size="mini" type="primary" @click="saveListenerConfig">保 存</el-button>
      </div>
    </el-drawer>

    <!-- 注入西段 编辑/创建 部分 -->
    <el-dialog title="字段配置" :visible.sync="listenerFieldFormModelVisible" width="600px" append-to-body destroy-on-close>
      <el-form :model="listenerFieldForm" size="mini" label-width="96px" ref="listenerFieldFormRef" style="height: 136px" @submit.native.prevent>
        <el-form-item label="字段名称：" prop="name" :rules="{ required: true, trigger: ['blur', 'change'] }">
          <el-input v-model="listenerFieldForm.name" clearable />
        </el-form-item>
        <el-form-item label="字段类型：" prop="fieldType" :rules="{ required: true, trigger: ['blur', 'change'] }">
          <el-select v-model="listenerFieldForm.fieldType">
            <el-option v-for="i in Object.keys(fieldTypeObject)" :key="i" :label="fieldTypeObject[i]" :value="i" />
          </el-select>
        </el-form-item>
        <el-form-item
          v-if="listenerFieldForm.fieldType === 'string'"
          label="字段值："
          prop="string"
          key="field-string"
          :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <el-input v-model="listenerFieldForm.string" clearable />
        </el-form-item>
        <el-form-item
          v-if="listenerFieldForm.fieldType === 'expression'"
          label="表达式："
          prop="expression"
          key="field-expression"
          :rules="{ required: true, trigger: ['blur', 'change'] }"
        >
          <el-input v-model="listenerFieldForm.expression" clearable />
        </el-form-item>
      </el-form>
      <template slot="footer">
        <el-button size="mini" @click="listenerFieldFormModelVisible = false">取 消</el-button>
        <el-button size="mini" type="primary" @click="saveListenerFiled">确 定</el-button>
      </template>
    </el-dialog>
  </div>
  `;
};


<|start_filename|>yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/aop/PreAuthenticatedAspect.java<|end_filename|>
package cn.iocoder.yudao.framework.security.core.aop;

import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.UNAUTHORIZED;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

@Aspect
@Slf4j
public class PreAuthenticatedAspect {

    @Around("@annotation(preAuthenticated)")
    public Object around(ProceedingJoinPoint joinPoint, PreAuthenticated preAuthenticated) throws Throwable {
        if (SecurityFrameworkUtils.getLoginUser() == null) {
            throw exception(UNAUTHORIZED);
        }
        return joinPoint.proceed();
    }

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/WebProperties.java<|end_filename|>
package cn.iocoder.yudao.framework.web.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;

import javax.validation.constraints.NotNull;

@ConfigurationProperties(prefix = "yudao.web")
@Validated
@Data
public class WebProperties {

    /**
     * API 前缀，实现所有 Controller 提供的 RESTFul API 的统一前缀
     *
     *
     * 意义：通过该前缀，避免 Swagger、Actuator 意外通过 Nginx 暴露出来给外部，带来安全性问题
     *      这样，Nginx 只需要配置转发到 /api/* 的所有接口即可。
     *
     * @see YudaoWebAutoConfiguration#configurePathMatch(PathMatchConfigurer)
     */
    @NotNull(message = "API 前缀不能为空")
    private String apiPrefix;

    /**
     * Controller 所在包
     *
     * 主要目的是，给该 Controller 设置指定的 {@link #apiPrefix}
     *
     * 因为我们有多个 modules 包里会包含 Controller，所以只需要写到 cn.iocoder.yudao 这样的层级
     */
    @NotNull(message = "Controller 所在包不能为空")
    private String controllerPackage;

}


<|start_filename|>yudao-vue-ui/components/mescroll-uni/mescroll-uni.css<|end_filename|>
.mescroll-uni-warp{
	height: 100%;
}

.mescroll-uni-content{
	height: 100%;
}

.mescroll-uni {
	position: relative;
	width: 100%;
	height: 100%;
	min-height: 200rpx;
	overflow-y: auto;
	box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */
}

/* 定位的方式固定高度 */
.mescroll-uni-fixed{
	z-index: 1;
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	width: auto; /* 使right生效 */
	height: auto; /* 使bottom生效 */
}

/* 适配 iPhoneX */
@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {
	.mescroll-safearea {
		padding-bottom: constant(safe-area-inset-bottom);
		padding-bottom: env(safe-area-inset-bottom);
	}
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/mixin/mpMixin.js<|end_filename|>
export default {
    // #ifdef MP-WEIXIN
    // 将自定义节点设置成虚拟的，更加接近Vue组件的表现，能更好的使用flex属性
    options: {
        virtualHost: true
    }
    // #endif
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/captcha/config/CaptchaConfig.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.framework.captcha.config;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(CaptchaProperties.class)
public class CaptchaConfig {
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/mysql/sms/SysSmsLogCoreMapper.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsLogDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface SysSmsLogCoreMapper extends BaseMapperX<SysSmsLogDO> {
}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/framework/package-info.java<|end_filename|>
/**
 * 属于整个 yudao-user-server 的 framework 封装
 *
 * @author 芋道源码
 */
package cn.iocoder.yudao.userserver.framework;


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/mysql/sms/SysSmsCodeMapper.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.system.dal.mysql.sms;

import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms.SysSmsCodeDO;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface SysSmsCodeMapper extends BaseMapperX<SysSmsCodeDO> {

    /**
     * 获得手机号的最后一个手机验证码
     *
     * @param mobile 手机号
     * @param scene 发送场景，选填
     * @return 手机验证码
     */
    default SysSmsCodeDO selectLastByMobile(String mobile, Integer scene) {
        return selectOne(new QueryWrapperX<SysSmsCodeDO>()
                .eq("mobile", mobile)
                .eqIfPresent("scene", scene)
                .orderByDesc("id")
                .last("LIMIT 1"));
    }

}


<|start_filename|>yudao-vue-ui/components/mescroll-uni/components/mescroll-down.css<|end_filename|>
/* 下拉刷新区域 */
.mescroll-downwarp {
	position: absolute;
	top: -100%;
	left: 0;
	width: 100%;
	height: 100%;
	text-align: center;
}

/* 下拉刷新--内容区,定位于区域底部 */
.mescroll-downwarp .downwarp-content {
	position: absolute;
	left: 0;
	bottom: 0;
	width: 100%;
	min-height: 60rpx;
	padding: 20rpx 0;
	text-align: center;
}

/* 下拉刷新--提示文本 */
.mescroll-downwarp .downwarp-tip {
	display: inline-block;
	font-size: 28rpx;
	vertical-align: middle;
	margin-left: 16rpx;
	/* color: gray; 已在style设置color,此处删去*/
}

/* 下拉刷新--旋转进度条 */
.mescroll-downwarp .downwarp-progress {
	display: inline-block;
	width: 32rpx;
	height: 32rpx;
	border-radius: 50%;
	border: 2rpx solid gray;
	border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/
	vertical-align: middle;
}

/* 旋转动画 */
.mescroll-downwarp .mescroll-rotate {
	animation: mescrollDownRotate 0.6s linear infinite;
}

@keyframes mescrollDownRotate {
	0% {
		transform: rotate(0deg);
	}

	100% {
		transform: rotate(360deg);
	}
}

<|start_filename|>yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/package-info.java<|end_filename|>
/**
 * 基于 EasyExcel 实现 Excel 相关的操作
 */
package cn.iocoder.yudao.framework.excel;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/mixin/button.js<|end_filename|>
export default {
    props: {
        lang: String,
        sessionFrom: String,
        sendMessageTitle: String,
        sendMessagePath: String,
        sendMessageImg: String,
        showMessageCard: Boolean,
        appParameter: String,
        formType: String,
        openType: String
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/impl/SysLoginLogServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.logger.impl;

import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogPageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.logger.SysLoginLogMapper;
import cn.iocoder.yudao.adminserver.modules.system.service.logger.SysLoginLogService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger.SysLoginLogDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * 登录日志 Service 实现
 */
@Service
public class SysLoginLogServiceImpl implements SysLoginLogService {

    @Resource
    private SysLoginLogMapper loginLogMapper;

    @Override
    public PageResult<SysLoginLogDO> getLoginLogPage(SysLoginLogPageReqVO reqVO) {
        return loginLogMapper.selectPage(reqVO);
    }

    @Override
    public List<SysLoginLogDO> getLoginLogList(SysLoginLogExportReqVO reqVO) {
        return loginLogMapper.selectList(reqVO);
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/indexList.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:13:35
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/indexList.js
 */
export default {
    // indexList 组件
    indexList: {
        inactiveColor: '#606266',
        activeColor: '#5677fc',
        indexList: () => [],
        sticky: true,
        customNavHeight: 0
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/dal/dataobject/job/InfJobDO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.dal.dataobject.job;

import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.adminserver.modules.infra.enums.job.InfJobStatusEnum;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;

/**
 * 定时任务 DO
 *
 * @author 芋道源码
 */
@TableName("inf_job")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class InfJobDO extends BaseDO {

    /**
     * 任务编号
     */
    @TableId
    private Long id;
    /**
     * 任务名称
     */
    private String name;
    /**
     * 任务状态
     *
     * 枚举 {@link InfJobStatusEnum}
     */
    private Integer status;
    /**
     * 处理器的名字
     */
    private String handlerName;
    /**
     * 处理器的参数
     */
    private String handlerParam;
    /**
     * CRON 表达式
     */
    private String cronExpression;

    // ========== 重试相关字段 ==========
    /**
     * 重试次数
     * 如果不重试，则设置为 0
     */
    private Integer retryCount;
    /**
     * 重试间隔，单位：毫秒
     * 如果没有间隔，则设置为 0
     */
    private Integer retryInterval;

    // ========== 监控相关字段 ==========
    /**
     * 监控超时时间，单位：毫秒
     * 为空时，表示不监控
     *
     * 注意，这里的超时的目的，不是进行任务的取消，而是告警任务的执行时间过长
     */
    private Integer monitorTimeout;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/permission/SysMenuConvert.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.convert.permission;

import cn.iocoder.yudao.adminserver.modules.system.controller.permission.vo.menu.SysMenuCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.permission.vo.menu.SysMenuRespVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.permission.vo.menu.SysMenuSimpleRespVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.permission.vo.menu.SysMenuUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import java.util.List;

@Mapper
public interface SysMenuConvert {

    SysMenuConvert INSTANCE = Mappers.getMapper(SysMenuConvert.class);

    List<SysMenuRespVO> convertList(List<SysMenuDO> list);

    SysMenuDO convert(SysMenuCreateReqVO bean);

    SysMenuDO convert(SysMenuUpdateReqVO bean);

    SysMenuRespVO convert(SysMenuDO bean);

    List<SysMenuSimpleRespVO> convertList02(List<SysMenuDO> list);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/vo/user/SysUserExcelVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user;

import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.adminserver.modules.system.enums.SysDictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.util.Date;

/**
 * 用户 Excel 导出 VO
 */
@Data
public class SysUserExcelVO {

    @ExcelProperty("用户编号")
    private Long id;

    @ExcelProperty("用户名称")
    private String username;

    @ExcelProperty("用户昵称")
    private String nickname;

    @ExcelProperty("用户邮箱")
    private String email;

    @ExcelProperty("手机号码")
    private String mobile;

    @ExcelProperty(value = "用户性别", converter = DictConvert.class)
    @DictFormat(SysDictTypeConstants.USER_SEX)
    private Integer sex;

    @ExcelProperty(value = "帐号状态", converter = DictConvert.class)
    @DictFormat(SysDictTypeConstants.COMMON_STATUS)
    private Integer status;

    @ExcelProperty("最后登录IP")
    private String loginIp;

    @ExcelProperty("最后登录时间")
    private Date loginDate;

    @ExcelProperty("部门名称")
    private String deptName;

    @ExcelProperty("部门负责人")
    private String deptLeader;

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/mysql/user/SysUserCoreMapper.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.user;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface SysUserCoreMapper extends BaseMapperX<SysUserDO> {

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/dal/mysql/user/MbrUserCoreMapper.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.member.dal.mysql.user;

import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface MbrUserCoreMapper extends BaseMapperX<MbrUserDO> {

}


<|start_filename|>yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreServiceTest.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.infra.service.file;

import cn.hutool.core.io.resource.ResourceUtil;
import cn.iocoder.yudao.coreservice.BaseDbUnitTest;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO;
import cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.file.InfFileCoreMapper;
import cn.iocoder.yudao.coreservice.modules.infra.framework.file.config.FileProperties;
import cn.iocoder.yudao.coreservice.modules.infra.service.file.impl.InfFileCoreServiceImpl;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;

import javax.annotation.Resource;

import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.FILE_NOT_EXISTS;
import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.FILE_PATH_EXISTS;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
import static org.junit.jupiter.api.Assertions.*;

@Import({InfFileCoreServiceImpl.class, FileProperties.class})
public class InfFileCoreServiceTest extends BaseDbUnitTest {

    @Resource
    private InfFileCoreService fileCoreService;

    @MockBean
    private FileProperties fileProperties;

    @Resource
    private InfFileCoreMapper fileMapper;

    @Test
    public void testCreateFile_success() {
        // 准备参数
        String path = randomString();
        byte[] content = ResourceUtil.readBytes("file/erweima.jpg");

        // 调用
        String url = fileCoreService.createFile(path, content);
        // 断言
        assertEquals(fileProperties.getBasePath() + path, url);
        // 校验数据
        InfFileDO file = fileMapper.selectById(path);
        assertEquals(path, file.getId());
        assertEquals("jpg", file.getType());
        assertArrayEquals(content, file.getContent());
    }

    @Test
    public void testCreateFile_exists() {
        // mock 数据
        InfFileDO dbFile = randomPojo(InfFileDO.class);
        fileMapper.insert(dbFile);
        // 准备参数
        String path = dbFile.getId(); // 模拟已存在
        byte[] content = ResourceUtil.readBytes("file/erweima.jpg");

        // 调用，并断言异常
        assertServiceException(() -> fileCoreService.createFile(path, content), FILE_PATH_EXISTS);
    }

    @Test
    public void testDeleteFile_success() {
        // mock 数据
        InfFileDO dbFile = randomPojo(InfFileDO.class);
        fileMapper.insert(dbFile);// @Sql: 先插入出一条存在的数据
        // 准备参数
        String id = dbFile.getId();

        // 调用
        fileCoreService.deleteFile(id);
        // 校验数据不存在了
        assertNull(fileMapper.selectById(id));
    }

    @Test
    public void testDeleteFile_notExists() {
        // 准备参数
        String id = randomString();

        // 调用, 并断言异常
        assertServiceException(() -> fileCoreService.deleteFile(id), FILE_NOT_EXISTS);
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/dept/vo/post/SysPostExcelVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.post;

import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.adminserver.modules.system.enums.SysDictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

/**
 * 岗位 Excel 导出响应 VO
 */
@Data
public class SysPostExcelVO {

    @ExcelProperty("岗位序号")
    private Long id;

    @ExcelProperty("岗位编码")
    private String code;

    @ExcelProperty("岗位名称")
    private String name;

    @ExcelProperty("岗位排序")
    private Integer sort;

    @ExcelProperty(value = "状态", converter = DictConvert.class)
    @DictFormat(SysDictTypeConstants.COMMON_STATUS)
    private String status;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/package-info.java<|end_filename|>
/**
 * 属于 system 模块的 framework 封装
 *
 * @author 芋道源码
 */
package cn.iocoder.yudao.adminserver.modules.system.framework;


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/file/InfFileCoreService.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.infra.service.file;

import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO;

/**
 * core service 文件接口
 *
 * @author 宋天
 */
public interface InfFileCoreService {


    /**
     * 保存文件，并返回文件的访问路径
     *
     * @param path 文件路径
     * @param content 文件内容
     * @return 文件路径
     */
    String createFile(String path, byte[] content);

    /**
     * 删除文件
     *
     * @param id 编号
     */
    void deleteFile(String id);

    /**
     * 获得文件
     *
     * @param path 文件路径
     * @return 文件
     */
    InfFileDO getFile(String path);
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/SmsCodeMapping.java<|end_filename|>
package cn.iocoder.yudao.framework.sms.core.client;

import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;

import java.util.function.Function;

/**
 * 将 API 的错误码，转换为通用的错误码
 *
 * @see SmsCommonResult
 * @see SmsFrameworkErrorCodeConstants
 *
 * @author 芋道源码
 */
public interface SmsCodeMapping extends Function<String, ErrorCode> {
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/resilience4j/package-info.java<|end_filename|>
/**
 * 使用 Resilience4j 组件，实现服务保障，包括：
 * 1. 熔断器
 * 2. 限流器
 * 3. 舱壁隔离
 * 4. 重试
 * 5. 限时器
 */
package cn.iocoder.yudao.framework.resilience4j;


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/enums/common/SysSexEnum.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.enums.common;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 性别的枚举值
 *
 * @author 芋道源码
 */
@Getter
@AllArgsConstructor
public enum SysSexEnum {

    /** 男 */
    MALE(1),
    /** 女 */
    FEMALE(2),
    /* 未知 */
    UNKNOWN(3);

    /**
     * 性别
     */
    private final Integer sex;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/controller/codegen/vo/ToolCodegenDetailRespVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.controller.codegen.vo;

import cn.iocoder.yudao.adminserver.modules.tool.controller.codegen.vo.column.ToolCodegenColumnRespVO;
import cn.iocoder.yudao.adminserver.modules.tool.controller.codegen.vo.table.ToolCodegenTableRespVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.List;

@ApiModel("代码生成表和字段的明细 Response VO")
@Data
public class ToolCodegenDetailRespVO {

    @ApiModelProperty("表定义")
    private ToolCodegenTableRespVO table;

    @ApiModelProperty("字段定义")
    private List<ToolCodegenColumnRespVO> columns;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/job/vo/job/InfJobExportReqVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.controller.job.vo.job;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@ApiModel(value = "定时任务 Excel 导出 Request VO", description = "参数和 InfJobPageReqVO 是一致的")
@Data
public class InfJobExportReqVO {

    @ApiModelProperty(value = "任务名称", example = "测试任务", notes = "模糊匹配")
    private String name;

    @ApiModelProperty(value = "任务状态", example = "1", notes = "参见 InfJobStatusEnum 枚举")
    private Integer status;

    @ApiModelProperty(value = "处理器的名字", example = "sysUserSessionTimeoutJob", notes = "模糊匹配")
    private String handlerName;

}


<|start_filename|>yudao-admin-server/src/test-integration/java/cn/iocoder/yudao/adminserver/modules/tool/dal/mysql/codegen/ToolInformationSchemaTableMapperTest.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.dal.mysql.codegen;

import cn.iocoder.yudao.adminserver.BaseDbUnitTest;

import javax.annotation.Resource;

class ToolInformationSchemaTableMapperTest extends BaseDbUnitTest {

    @Resource
    private ToolSchemaTableMapper toolInformationSchemaTableMapper;

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-notice-bar/props.js<|end_filename|>
export default {
    props: {
        // 显示的内容，数组
        text: {
            type: [Array, String],
            default: uni.$u.props.noticeBar.text
        },
        // 通告滚动模式，row-横向滚动，column-竖向滚动
        direction: {
            type: String,
            default: uni.$u.props.noticeBar.direction
        },
        // direction = row时，是否使用步进形式滚动
        step: {
            type: Boolean,
            default: uni.$u.props.noticeBar.step
        },
        // 是否显示左侧的音量图标
        icon: {
            type: String,
            default: uni.$u.props.noticeBar.icon
        },
        // 通告模式，link-显示右箭头，closable-显示右侧关闭图标
        mode: {
            type: String,
            default: uni.$u.props.noticeBar.mode
        },
        // 文字颜色，各图标也会使用文字颜色
        color: {
            type: String,
            default: uni.$u.props.noticeBar.color
        },
        // 背景颜色
        bgColor: {
            type: String,
            default: uni.$u.props.noticeBar.bgColor
        },
        // 水平滚动时的滚动速度，即每秒滚动多少px(px)，这有利于控制文字无论多少时，都能有一个恒定的速度
        speed: {
            type: [String, Number],
            default: uni.$u.props.noticeBar.speed
        },
        // 字体大小
        fontSize: {
            type: [String, Number],
            default: uni.$u.props.noticeBar.fontSize
        },
        // 滚动一个周期的时间长，单位ms
        duration: {
            type: [String, Number],
            default: uni.$u.props.noticeBar.duration
        },
        // 是否禁止用手滑动切换
        // 目前HX2.6.11，只支持App 2.5.5+、H5 2.5.5+、支付宝小程序、字节跳动小程序
        disableTouch: {
            type: Boolean,
            default: uni.$u.props.noticeBar.disableTouch
        },
        // 跳转的页面路径
        url: {
            type: String,
            default: uni.$u.props.noticeBar.url
        },
        // 页面跳转的类型
        linkType: {
            type: String,
            default: uni.$u.props.noticeBar.linkType
        }
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/config/vo/InfConfigCreateReqVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.controller.config.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

@ApiModel("参数配置创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class InfConfigCreateReqVO extends InfConfigBaseVO {

    @ApiModelProperty(value = "参数键名", required = true, example = "yunai.db.username")
    @NotBlank(message = "参数键名长度不能为空")
    @Size(max = 100, message = "参数键名长度不能超过100个字符")
    private String key;

}


<|start_filename|>yudao-admin-ui/src/api/system/role.js<|end_filename|>
import request from '@/utils/request'

// 查询角色列表
export function listRole(query) {
  return request({
    url: '/system/role/page',
    method: 'get',
    params: query
  })
}

// 查询角色（精简)列表
export function listSimpleRoles() {
  return request({
    url: '/system/role/list-all-simple',
    method: 'get'
  })
}

// 查询角色详细
export function getRole(roleId) {
  return request({
    url: '/system/role/get?id=' + roleId,
    method: 'get'
  })
}

// 新增角色
export function addRole(data) {
  return request({
    url: '/system/role/create',
    method: 'post',
    data: data
  })
}

// 修改角色
export function updateRole(data) {
  return request({
    url: '/system/role/update',
    method: 'put',
    data: data
  })
}

// 角色状态修改
export function changeRoleStatus(id, status) {
  const data = {
    id,
    status
  }
  return request({
    url: '/system/role/update-status',
    method: 'put',
    data: data
  })
}

// 删除角色
export function delRole(roleId) {
  return request({
    url: '/system/role/delete?id=' + roleId,
    method: 'delete'
  })
}

// 导出角色
export function exportRole(query) {
  return request({
    url: '/system/role/export',
    method: 'get',
    params: query,
    responseType: 'blob'
  })
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/codegen/config/CodegenProperties.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.framework.codegen.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Collection;

@ConfigurationProperties(prefix = "yudao.codegen")
@Validated
@Data
public class CodegenProperties {

    /**
     * 生成的 Java 代码的基础包
     */
    @NotNull(message = "Java 代码的基础包不能为空")
    private String basePackage;

    /**
     * 数据库名数组
     */
    @NotEmpty(message = "数据库不能为空")
    private Collection<String> dbSchemas;

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/property/SmsChannelProperties.java<|end_filename|>
package cn.iocoder.yudao.framework.sms.core.property;

import cn.iocoder.yudao.framework.sms.core.enums.SmsChannelEnum;
import lombok.Data;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

/**
 * 短信渠道配置类
 *
 * @author zzf
 * @date 2021/1/25 17:01
 */
@Data
@Validated
public class SmsChannelProperties {

    /**
     * 渠道编号
     */
    @NotNull(message = "短信渠道 ID 不能为空")
    private Long id;
    /**
     * 短信签名
     */
    @NotEmpty(message = "短信签名不能为空")
    private String signature;
    /**
     * 渠道编码
     *
     * 枚举 {@link SmsChannelEnum}
     */
    @NotEmpty(message = "渠道编码不能为空")
    private String code;
    /**
     * 短信 API 的账号
     */
    @NotEmpty(message = "短信 API 的账号不能为空")
    private String apiKey;
    /**
     * 短信 API 的秘钥
     */
    @NotEmpty(message = "短信 API 的秘钥不能为空")
    private String apiSecret;
    /**
     * 短信发送回调 URL
     */
    private String callbackUrl;

}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/mysql/package-info.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.system.dal.mysql;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/errorcode/SysErrorCodeService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.errorcode;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.tool.framework.errorcode.core.service.ErrorCodeFrameworkService;
import cn.iocoder.yudao.adminserver.modules.system.controller.errorcode.vo.SysErrorCodeCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.errorcode.vo.SysErrorCodeExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.errorcode.vo.SysErrorCodePageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.errorcode.vo.SysErrorCodeUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.errorcode.SysErrorCodeDO;

import javax.validation.Valid;
import java.util.List;

/**
 * 错误码 Service 接口
 *
 * @author 芋道源码
 */
public interface SysErrorCodeService extends ErrorCodeFrameworkService {

    /**
     * 创建错误码
     *
     * @param createReqVO 创建信息
     * @return 编号
     */
    Long createErrorCode(@Valid SysErrorCodeCreateReqVO createReqVO);

    /**
     * 更新错误码
     *
     * @param updateReqVO 更新信息
     */
    void updateErrorCode(@Valid SysErrorCodeUpdateReqVO updateReqVO);

    /**
     * 删除错误码
     *
     * @param id 编号
     */
    void deleteErrorCode(Long id);

    /**
     * 获得错误码
     *
     * @param id 编号
     * @return 错误码
     */
    SysErrorCodeDO getErrorCode(Long id);

    /**
     * 获得错误码分页
     *
     * @param pageReqVO 分页查询
     * @return 错误码分页
     */
    PageResult<SysErrorCodeDO> getErrorCodePage(SysErrorCodePageReqVO pageReqVO);

    /**
     * 获得错误码列表, 用于 Excel 导出
     *
     * @param exportReqVO 查询条件
     * @return 错误码列表
     */
    List<SysErrorCodeDO> getErrorCodeList(SysErrorCodeExportReqVO exportReqVO);

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsTemplateAuditStatusEnum.java<|end_filename|>
package cn.iocoder.yudao.framework.sms.core.enums;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 短信模板的审核状态枚举
 *
 * @author 芋道源码
 */
@AllArgsConstructor
@Getter
public enum SmsTemplateAuditStatusEnum {

    CHECKING(1),
    SUCCESS(2),
    FAIL(3);

    private final Integer status;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/dept/DeptIdEnum.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.enums.dept;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 部门编号枚举
 */
@Getter
@AllArgsConstructor
public enum DeptIdEnum {

    /**
     * 根节点
     */
    ROOT(0L);

    private final Long id;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/permission/RoleCodeEnum.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.enums.permission;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 角色标识枚举
 */
@Getter
@AllArgsConstructor
public enum RoleCodeEnum {

    ADMIN("admin"), // 超级管理员
    ;

    /**
     * 角色编码
     */
    private final String key;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/notice/SysNoticeService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.notice;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.system.controller.notice.vo.SysNoticeCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.notice.vo.SysNoticePageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.notice.vo.SysNoticeUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.notice.SysNoticeDO;

/**
 * 通知公告 Service 接口
 */
public interface SysNoticeService {

    /**
     * 创建岗位公告公告
     *
     * @param reqVO 岗位公告公告信息
     * @return 岗位公告公告编号
     */
    Long createNotice(SysNoticeCreateReqVO reqVO);

    /**
     * 更新岗位公告公告
     *
     * @param reqVO 岗位公告公告信息
     */
    void updateNotice(SysNoticeUpdateReqVO reqVO);

    /**
     * 删除岗位公告公告信息
     *
     * @param id 岗位公告公告编号
     */
    void deleteNotice(Long id);

    /**
     * 获得岗位公告公告分页列表
     *
     * @param reqVO 分页条件
     * @return 部门分页列表
     */
    PageResult<SysNoticeDO> pageNotices(SysNoticePageReqVO reqVO);

    /**
     * 获得岗位公告公告信息
     *
     * @param id 岗位公告公告编号
     * @return 岗位公告公告信息
     */
    SysNoticeDO getNotice(Long id);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/monitor/package-info.java<|end_filename|>
/**
 * 使用 Spring Boot Admin 实现简单的监控平台
 */
package cn.iocoder.yudao.adminserver.framework.monitor;


<|start_filename|>yudao-admin-ui/src/api/system/operatelog.js<|end_filename|>
import request from '@/utils/request'

// 查询操作日志列表
export function listOperateLog(query) {
  return request({
    url: '/system/operate-log/page',
    method: 'get',
    params: query
  })
}

// 导出操作日志
export function exportOperateLog(query) {
  return request({
    url: '/system/operate-log/export',
    method: 'get',
    params: query,
    responseType: 'blob'
  })
}


<|start_filename|>yudao-admin-ui/src/components/bpmnProcessDesigner/src/utils/xml2json.js<|end_filename|>
function xmlStr2XmlObj(xmlStr) {
  let xmlObj = {};
  if (document.all) {
    const xmlDom = new window.ActiveXObject("Microsoft.XMLDOM");
    xmlDom.loadXML(xmlStr);
    xmlObj = xmlDom;
  } else {
    xmlObj = new DOMParser().parseFromString(xmlStr, "text/xml");
  }
  return xmlObj;
}

function xml2json(xml) {
  try {
    let obj = {};
    if (xml.children.length > 0) {
      for (let i = 0; i < xml.children.length; i++) {
        const item = xml.children.item(i);
        const nodeName = item.nodeName;
        if (typeof obj[nodeName] == "undefined") {
          obj[nodeName] = xml2json(item);
        } else {
          if (typeof obj[nodeName].push == "undefined") {
            const old = obj[nodeName];
            obj[nodeName] = [];
            obj[nodeName].push(old);
          }
          obj[nodeName].push(xml2json(item));
        }
      }
    } else {
      obj = xml.textContent;
    }
    return obj;
  } catch (e) {
    console.log(e.message);
  }
}

function xmlObj2json(xml) {
  const xmlObj = xmlStr2XmlObj(xml);
  console.log(xmlObj);
  let jsonObj = {};
  if (xmlObj.childNodes.length > 0) {
    jsonObj = xml2json(xmlObj);
  }
  return jsonObj;
}

export default xmlObj2json;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/job/vo/log/InfJobLogExportReqVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.controller.job.vo.log;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;

@ApiModel(value = "定时任务 Excel 导出 Request VO", description = "参数和 InfJobLogPageReqVO 是一致的")
@Data
public class InfJobLogExportReqVO {

    @ApiModelProperty(value = "任务编号", example = "10")
    private Long jobId;

    @ApiModelProperty(value = "处理器的名字", notes = "模糊匹配")
    private String handlerName;

    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
    @ApiModelProperty(value = "开始执行时间")
    private Date beginTime;

    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
    @ApiModelProperty(value = "结束执行时间")
    private Date endTime;

    @ApiModelProperty(value = "任务状态", notes = "参见 InfJobLogStatusEnum 枚举")
    private Integer status;

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-dict/src/main/java/cn/iocoder/yudao/framework/dict/package-info.java<|end_filename|>
/**
 * 字典数据模块，提供 {@link cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils} 工具类
 *
 * 通过将字典缓存在内存中，保证性能
 */
package cn.iocoder.yudao.framework.dict;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/notice/impl/SysNoticeServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.notice.impl;

import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.system.controller.notice.vo.SysNoticeCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.notice.vo.SysNoticePageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.notice.vo.SysNoticeUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.convert.notice.SysNoticeConvert;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.notice.SysNoticeMapper;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.notice.SysNoticeDO;
import cn.iocoder.yudao.adminserver.modules.system.service.notice.SysNoticeService;
import com.google.common.annotations.VisibleForTesting;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.NOTICE_NOT_FOUND;

/**
 * 通知公告 Service 实现类
 *
 * @author 芋道源码
 */
@Service
public class SysNoticeServiceImpl implements SysNoticeService {

    @Resource
    private SysNoticeMapper noticeMapper;

    @Override
    public Long createNotice(SysNoticeCreateReqVO reqVO) {
        SysNoticeDO notice = SysNoticeConvert.INSTANCE.convert(reqVO);
        noticeMapper.insert(notice);
        return notice.getId();
    }

    @Override
    public void updateNotice(SysNoticeUpdateReqVO reqVO) {
        // 校验是否存在
        this.checkNoticeExists(reqVO.getId());
        // 更新通知公告
        SysNoticeDO updateObj = SysNoticeConvert.INSTANCE.convert(reqVO);
        noticeMapper.updateById(updateObj);
    }

    @Override
    public void deleteNotice(Long id) {
        // 校验是否存在
        this.checkNoticeExists(id);
        // 删除通知公告
        noticeMapper.deleteById(id);
    }

    @Override
    public PageResult<SysNoticeDO> pageNotices(SysNoticePageReqVO reqVO) {
        return noticeMapper.selectPage(reqVO);
    }

    @Override
    public SysNoticeDO getNotice(Long id) {
        return noticeMapper.selectById(id);
    }

    @VisibleForTesting
    public void checkNoticeExists(Long id) {
        if (id == null) {
            return;
        }
        SysNoticeDO notice = noticeMapper.selectById(id);
        if (notice == null) {
            throw ServiceExceptionUtil.exception(NOTICE_NOT_FOUND);
        }
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-swipe-action-item/props.js<|end_filename|>
export default {
    props: {
        // 控制打开或者关闭
        show: {
            type: Boolean,
            default: uni.$u.props.swipeActionItem.show
        },
        // 标识符，如果是v-for，可用index索引值
        name: {
            type: [String, Number],
            default: uni.$u.props.swipeActionItem.name
        },
        // 是否禁用
        disabled: {
            type: Boolean,
            default: uni.$u.props.swipeActionItem.disabled
        },
        // 是否自动关闭其他swipe按钮组
        autoClose: {
            type: Boolean,
            default: uni.$u.props.swipeActionItem.autoClose
        },
        // 滑动距离阈值，只有大于此值，才被认为是要打开菜单
        threshold: {
            type: Number,
            default: uni.$u.props.swipeActionItem.threshold
        },
        // 右侧按钮内容
        options: {
            type: Array,
            default() {
                return uni.$u.props.swipeActionItem.rightOptions
            }
        },
        // 动画过渡时间，单位ms
        duration: {
            type: [String, Number],
            default: uni.$u.props.swipeActionItem.duration
        }
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/mq/consumer/permission/SysRoleMenuRefreshConsumer.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.mq.consumer.permission;

import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.permission.SysRoleMenuRefreshMessage;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 针对 {@link SysRoleMenuRefreshMessage} 的消费者
 *
 * @author 芋道源码
 */
@Component
@Slf4j
public class SysRoleMenuRefreshConsumer extends AbstractChannelMessageListener<SysRoleMenuRefreshMessage> {

    @Resource
    private SysPermissionService permissionService;

    @Override
    public void onMessage(SysRoleMenuRefreshMessage message) {
        log.info("[onMessage][收到 Role 与 Menu 的关联刷新消息]");
        permissionService.initLocalCache();
    }

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/package-info.java<|end_filename|>
/**
 * infra 包下，我们放基础设施的运维与管理，支撑上层的通用与核心业务。
 * 例如说：定时任务的管理、服务器的信息等等
 *
 * 缩写：inf
 */
package cn.iocoder.yudao.coreservice.modules.infra;


<|start_filename|>yudao-admin-ui/src/api/system/sms/smsTemplate.js<|end_filename|>
import request from '@/utils/request'

// 创建短信模板
export function createSmsTemplate(data) {
  return request({
    url: '/system/sms-template/create',
    method: 'post',
    data: data
  })
}

// 更新短信模板
export function updateSmsTemplate(data) {
  return request({
    url: '/system/sms-template/update',
    method: 'put',
    data: data
  })
}

// 删除短信模板
export function deleteSmsTemplate(id) {
  return request({
    url: '/system/sms-template/delete?id=' + id,
    method: 'delete'
  })
}

// 获得短信模板
export function getSmsTemplate(id) {
  return request({
    url: '/system/sms-template/get?id=' + id,
    method: 'get'
  })
}

// 获得短信模板分页
export function getSmsTemplatePage(query) {
  return request({
    url: '/system/sms-template/page',
    method: 'get',
    params: query
  })
}

// 创建短信模板
export function sendSms(data) {
  return request({
    url: '/system/sms-template/send-sms',
    method: 'post',
    data: data
  })
}

// 导出短信模板 Excel
export function exportSmsTemplateExcel(query) {
  return request({
    url: '/system/sms-template/export-excel',
    method: 'get',
    params: query,
    responseType: 'blob'
  })
}



<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/swiper.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:21:38
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/swiper.js
 */
export default {
    // swiper 组件
    swiper: {
        list: () => [],
        indicator: false,
        indicatorActiveColor: '#FFFFFF',
        indicatorInactiveColor: 'rgba(255, 255, 255, 0.35)',
        indicatorStyle: '',
        indicatorMode: 'line',
        autoplay: true,
        current: 0,
        currentItemId: '',
        interval: 3000,
        duration: 300,
        circular: false,
        previousMargin: 0,
        nextMargin: 0,
        acceleration: false,
        displayMultipleItems: 1,
        easingFunction: 'default',
        keyName: 'url',
        imgMode: 'aspectFill',
        height: 130,
        bgColor: '#f3f4f6',
        radius: 4,
        loading: false,
        showTitle: false
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/notice/SysNoticeConvert.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.convert.notice;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.system.controller.notice.vo.SysNoticeCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.notice.vo.SysNoticeRespVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.notice.vo.SysNoticeUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.notice.SysNoticeDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface SysNoticeConvert {

    SysNoticeConvert INSTANCE = Mappers.getMapper(SysNoticeConvert.class);

    PageResult<SysNoticeRespVO> convertPage(PageResult<SysNoticeDO> page);

    SysNoticeRespVO convert(SysNoticeDO bean);

    SysNoticeDO convert(SysNoticeUpdateReqVO bean);

    SysNoticeDO convert(SysNoticeCreateReqVO bean);

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/enums/JobDataKeyEnum.java<|end_filename|>
package cn.iocoder.yudao.framework.quartz.core.enums;

/**
 * Quartz Job Data 的 key 枚举
 */
public enum JobDataKeyEnum {

    JOB_ID,
    JOB_HANDLER_NAME,
    JOB_HANDLER_PARAM,
    JOB_RETRY_COUNT, // 最大重试次数
    JOB_RETRY_INTERVAL, // 每次重试间隔

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/lineProgress.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:14:11
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/lineProgress.js
 */
export default {
    // lineProgress 组件
    lineProgress: {
        activeColor: '#19be6b',
        inactiveColor: '#ececec',
        percentage: 0,
        showText: true,
        height: 12
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/mq/consumer/permission/SysMenuRefreshConsumer.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.mq.consumer.permission;

import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.permission.SysMenuRefreshMessage;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysMenuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 针对 {@link SysMenuRefreshMessage} 的消费者
 *
 * @author 芋道源码
 */
@Component
@Slf4j
public class SysMenuRefreshConsumer extends AbstractChannelMessageListener<SysMenuRefreshMessage> {

    @Resource
    private SysMenuService menuService;

    @Override
    public void onMessage(SysMenuRefreshMessage message) {
        log.info("[onMessage][收到 Menu 刷新消息]");
        menuService.initLocalCache();
    }

}


<|start_filename|>yudao-admin-ui/src/components/bpmnProcessDesigner/src/modules/custom-renderer/index.js<|end_filename|>
import CustomRenderer from "./CustomRenderer";

export default {
  __init__: ["customRenderer"],
  customRenderer: ["type", CustomRenderer]
};


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/enums/MbrErrorCodeConstants.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.member.enums;

import cn.iocoder.yudao.framework.common.exception.ErrorCode;

/**
 * Member 错误码枚举类
 *
 * member 系统，使用 1-004-000-000 段
 */
public interface MbrErrorCodeConstants {

    // ==========用户相关  1004001000============
    ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在");

    // ==========文件相关 1004002000 ===========
    ErrorCode FILE_IS_EMPTY = new ErrorCode(1004002000, "文件为空");
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/permission/SysMenuController.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.permission;

import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.adminserver.modules.system.controller.permission.vo.menu.*;
import cn.iocoder.yudao.adminserver.modules.system.convert.permission.SysMenuConvert;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysMenuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
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.Comparator;
import java.util.List;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

@Api(tags = "菜单")
@RestController
@RequestMapping("/system/menu")
@Validated
public class SysMenuController {

    @Resource
    private SysMenuService menuService;

    @PostMapping("/create")
    @ApiOperation("创建菜单")
    @PreAuthorize("@ss.hasPermission('system:menu:create')")
    public CommonResult<Long> createMenu(@Valid @RequestBody SysMenuCreateReqVO reqVO) {
        Long menuId = menuService.createMenu(reqVO);
        return success(menuId);
    }

    @PutMapping("/update")
    @ApiOperation("修改菜单")
    @PreAuthorize("@ss.hasPermission('system:menu:update')")
    public CommonResult<Boolean> updateMenu(@Valid @RequestBody SysMenuUpdateReqVO reqVO) {
        menuService.updateMenu(reqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @ApiOperation("删除菜单")
    @ApiImplicitParam(name = "id", value = "角色编号", required= true, example = "1024", dataTypeClass = Long.class)
    @PreAuthorize("@ss.hasPermission('system:menu:delete')")
    public CommonResult<Boolean> deleteMenu(@RequestParam("id") Long id) {
        menuService.deleteMenu(id);
        return success(true);
    }

    @GetMapping("/list")
    @ApiOperation("获取菜单列表")
    @PreAuthorize("@ss.hasPermission('system:menu:query')")
    public CommonResult<List<SysMenuRespVO>> getMenus(SysMenuListReqVO reqVO) {
        List<SysMenuDO> list = menuService.getMenus(reqVO);
        list.sort(Comparator.comparing(SysMenuDO::getSort));
        return success(SysMenuConvert.INSTANCE.convertList(list));
    }

    @GetMapping("/list-all-simple")
    @ApiOperation(value = "获取菜单精简信息列表", notes = "只包含被开启的菜单，主要用于前端的下拉选项")
    public CommonResult<List<SysMenuSimpleRespVO>> getSimpleMenus() {
        // 获得菜单列表，只要开启状态的
        SysMenuListReqVO reqVO = new SysMenuListReqVO();
        reqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
        List<SysMenuDO> list = menuService.getMenus(reqVO);
        // 排序后，返回个诶前端
        list.sort(Comparator.comparing(SysMenuDO::getSort));
        return success(SysMenuConvert.INSTANCE.convertList02(list));
    }

    @GetMapping("/get")
    @ApiOperation("获取菜单信息")
    @PreAuthorize("@ss.hasPermission('system:menu:query')")
    public CommonResult<SysMenuRespVO> getMenu(Long id) {
        SysMenuDO menu = menuService.getMenu(id);
        return success(SysMenuConvert.INSTANCE.convert(menu));
    }

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/package-info.java<|end_filename|>
/**
 * 针对 SpringMVC 的基础封装
 */
package cn.iocoder.yudao.framework.web;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/luch-request/core/dispatchRequest.js<|end_filename|>
import adapter from '../adapters/index'

export default (config) => adapter(config)


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/logger/vo/loginlog/SysLoginLogBaseVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

/**
 * 登录日志 Base VO，提供给添加、修改、详细的子 VO 使用
 * 如果子 VO 存在差异的字段，请不要添加到这里，影响 Swagger 文档生成
 */
@Data
public class SysLoginLogBaseVO {

    @ApiModelProperty(value = "日志类型", required = true, example = "1", notes = "参见 SysLoginLogTypeEnum 枚举类")
    @NotNull(message = "日志类型不能为空")
    private Integer logType;

    @ApiModelProperty(value = "链路追踪编号", required = true, example = "89aca178-a370-411c-ae02-3f0d672be4ab")
    @NotEmpty(message = "链路追踪编号不能为空")
    private String traceId;

    @ApiModelProperty(value = "用户账号", required = true, example = "yudao")
    @NotBlank(message = "用户账号不能为空")
    @Size(max = 30, message = "用户账号长度不能超过30个字符")
    private String username;

    @ApiModelProperty(value = "登录结果", required = true, example = "1", notes = "参见 SysLoginResultEnum 枚举类")
    @NotNull(message = "登录结果不能为空")
    private Integer result;

    @ApiModelProperty(value = "用户 IP", required = true, example = "127.0.0.1")
    @NotEmpty(message = "用户 IP 不能为空")
    private String userIp;

    @ApiModelProperty(value = "浏览器 UserAgent", required = true, example = "Mozilla/5.0")
    @NotEmpty(message = "浏览器 UserAgent 不能为空")
    private String userAgent;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/dict/SysDictTypeService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.dict;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.type.SysDictTypeCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.type.SysDictTypeExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.type.SysDictTypePageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.type.SysDictTypeUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dict.SysDictTypeDO;

import java.util.List;

/**
 * 字典类型 Service 接口
 *
 * @author 芋道源码
 */
public interface SysDictTypeService {

    /**
     * 创建字典类型
     *
     * @param reqVO 字典类型信息
     * @return 字典类型编号
     */
    Long createDictType(SysDictTypeCreateReqVO reqVO);

    /**
     * 更新字典类型
     *
     * @param reqVO 字典类型信息
     */
    void updateDictType(SysDictTypeUpdateReqVO reqVO);

    /**
     * 删除字典类型
     *
     * @param id 字典类型编号
     */
    void deleteDictType(Long id);

    /**
     * 获得字典类型分页列表
     *
     * @param reqVO 分页请求
     * @return 字典类型分页列表
     */
    PageResult<SysDictTypeDO> getDictTypePage(SysDictTypePageReqVO reqVO);

    /**
     * 获得字典类型列表
     *
     * @param reqVO 列表请求
     * @return 字典类型列表
     */
    List<SysDictTypeDO> getDictTypeList(SysDictTypeExportReqVO reqVO);

    /**
     * 获得字典类型详情
     *
     * @param id 字典类型编号
     * @return 字典类型
     */
    SysDictTypeDO getDictType(Long id);

    /**
     * 获得字典类型详情
     *
     * @param type 字典类型
     * @return 字典类型详情
     */
    SysDictTypeDO getDictType(String type);

    /**
     * 获得全部字典类型列表
     *
     * @return 字典类型列表
     */
    List<SysDictTypeDO> getDictTypeList();

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/logger/SysLoginLogCoreService.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.logger;

import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;

/**
 * 登录日志 Core Service 接口
 */
public interface SysLoginLogCoreService {

    /**
     * 创建登录日志
     *
     * @param reqDTO 日志信息
     */
    void createLoginLog(SysLoginLogCreateReqDTO reqDTO);

}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/sms/SysSmsTemplateCodeConstants.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.system.enums.sms;

/**
 * yudao-user-server 使用到的短信模板的 Code 编码的枚举
 *
 * @author 芋道源码
 */
public interface SysSmsTemplateCodeConstants {

    /**
     * 前台用户短信登录
     */
    String USER_SMS_LOGIN = "user-sms-login";

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/sms/impl/SysSmsChannelServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.sms.impl;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.channel.SysSmsChannelCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.channel.SysSmsChannelUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.convert.sms.SysSmsChannelConvert;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.sms.SysSmsChannelMapper;
import cn.iocoder.yudao.adminserver.modules.system.mq.producer.sms.SysSmsProducer;
import cn.iocoder.yudao.adminserver.modules.system.service.sms.SysSmsChannelService;
import cn.iocoder.yudao.adminserver.modules.system.service.sms.SysSmsTemplateService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.SMS_CHANNEL_HAS_CHILDREN;
import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.SMS_CHANNEL_NOT_EXISTS;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 短信渠道Service实现类
 *
 * @author zzf
 * @date 2021/1/25 9:25
 */
@Service
@Slf4j
public class SysSmsChannelServiceImpl implements SysSmsChannelService {

    /**
     * 定时执行 {@link #schedulePeriodicRefresh()} 的周期
     * 因为已经通过 Redis Pub/Sub 机制，所以频率不需要高
     */
    private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;

    /**
     * 缓存菜单的最大更新时间，用于后续的增量轮询，判断是否有更新
     */
    private volatile Date maxUpdateTime;

    @Resource
    private SmsClientFactory smsClientFactory;

    @Resource
    private SysSmsChannelMapper smsChannelMapper;

    @Resource
    private SysSmsTemplateService smsTemplateService;

    @Resource
    private SysSmsProducer smsProducer;

    @Override
    @PostConstruct
    public void initSmsClients() {
        // 获取短信渠道，如果有更新
        List<SysSmsChannelDO> smsChannels = this.loadSmsChannelIfUpdate(maxUpdateTime);
        if (CollUtil.isEmpty(smsChannels)) {
            return;
        }

        // 创建或更新短信 Client
        List<SmsChannelProperties> propertiesList = SysSmsChannelConvert.INSTANCE.convertList02(smsChannels);
        propertiesList.forEach(properties -> smsClientFactory.createOrUpdateSmsClient(properties));

        // 写入缓存
        assert smsChannels.size() > 0; // 断言，避免告警
        maxUpdateTime = smsChannels.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime();
        log.info("[initSmsClients][初始化 SmsChannel 数量为 {}]", smsChannels.size());
    }

    @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
    public void schedulePeriodicRefresh() {
        initSmsClients();
    }

    /**
     * 如果短信渠道发生变化，从数据库中获取最新的全量短信渠道。
     * 如果未发生变化，则返回空
     *
     * @param maxUpdateTime 当前短信渠道的最大更新时间
     * @return 短信渠道列表
     */
    private List<SysSmsChannelDO> loadSmsChannelIfUpdate(Date maxUpdateTime) {
        // 第一步，判断是否要更新。
        if (maxUpdateTime == null) { // 如果更新时间为空，说明 DB 一定有新数据
            log.info("[loadSmsChannelIfUpdate][首次加载全量短信渠道]");
        } else { // 判断数据库中是否有更新的短信渠道
            if (smsChannelMapper.selectExistsByUpdateTimeAfter(maxUpdateTime) == null) {
                return null;
            }
            log.info("[loadSmsChannelIfUpdate][增量加载全量短信渠道]");
        }
        // 第二步，如果有更新，则从数据库加载所有短信渠道
        return smsChannelMapper.selectList();
    }

    @Override
    public Long createSmsChannel(SysSmsChannelCreateReqVO createReqVO) {
        // 插入
        SysSmsChannelDO smsChannel = SysSmsChannelConvert.INSTANCE.convert(createReqVO);
        smsChannelMapper.insert(smsChannel);
        // 发送刷新消息
        smsProducer.sendSmsChannelRefreshMessage();
        // 返回
        return smsChannel.getId();
    }

    @Override
    public void updateSmsChannel(SysSmsChannelUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateSmsChannelExists(updateReqVO.getId());
        // 更新
        SysSmsChannelDO updateObj = SysSmsChannelConvert.INSTANCE.convert(updateReqVO);
        smsChannelMapper.updateById(updateObj);
        // 发送刷新消息
        smsProducer.sendSmsChannelRefreshMessage();
    }

    @Override
    public void deleteSmsChannel(Long id) {
        // 校验存在
        this.validateSmsChannelExists(id);
        // 校验是否有字典数据
        if (smsTemplateService.countByChannelId(id) > 0) {
            throw exception(SMS_CHANNEL_HAS_CHILDREN);
        }
        // 删除
        smsChannelMapper.deleteById(id);
        // 发送刷新消息
        smsProducer.sendSmsChannelRefreshMessage();
    }

    private void validateSmsChannelExists(Long id) {
        if (smsChannelMapper.selectById(id) == null) {
            throw exception(SMS_CHANNEL_NOT_EXISTS);
        }
    }

    @Override
    public SysSmsChannelDO getSmsChannel(Long id) {
        return smsChannelMapper.selectById(id);
    }

    @Override
    public List<SysSmsChannelDO> getSmsChannelList(Collection<Long> ids) {
        return smsChannelMapper.selectBatchIds(ids);
    }

    @Override
    public List<SysSmsChannelDO> getSmsChannelList() {
        return smsChannelMapper.selectList();
    }

    @Override
    public PageResult<SysSmsChannelDO> getSmsChannelPage(SysSmsChannelPageReqVO pageReqVO) {
        return smsChannelMapper.selectPage(pageReqVO);
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/package-info.java<|end_filename|>
/**
 * 属于整个 yudao-admin-server 的 framework 封装
 *
 * @author 芋道源码
 */
package cn.iocoder.yudao.adminserver.framework;


<|start_filename|>yudao-admin-server/src/test-integration/java/cn/iocoder/yudao/adminserver/modules/system/service/package-info.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-toolbar/props.js<|end_filename|>
export default {
    props: {
        // 是否展示工具条
        show: {
            type: Boolean,
            default: uni.$u.props.toolbar.show
        },
        // 取消按钮的文字
        cancelText: {
            type: String,
            default: uni.$u.props.toolbar.cancelText
        },
        // 确认按钮的文字
        confirmText: {
            type: String,
            default: uni.$u.props.toolbar.confirmText
        },
        // 取消按钮的颜色
        cancelColor: {
            type: String,
            default: uni.$u.props.toolbar.cancelColor
        },
        // 确认按钮的颜色
        confirmColor: {
            type: String,
            default: uni.$u.props.toolbar.confirmColor
        },
        // 标题文字
        title: {
            type: String,
            default: uni.$u.props.toolbar.title
        }
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/sms/vo/log/SysSmsLogRespVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.log;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.Date;
import java.util.Map;

@ApiModel("短信日志 Response VO")
@Data
public class SysSmsLogRespVO {

    @ApiModelProperty(value = "编号", required = true, example = "1024")
    private Long id;

    @ApiModelProperty(value = "短信渠道编号", required = true, example = "10")
    private Long channelId;

    @ApiModelProperty(value = "短信渠道编码", required = true, example = "ALIYUN")
    private String channelCode;

    @ApiModelProperty(value = "模板编号", required = true, example = "20")
    private Long templateId;

    @ApiModelProperty(value = "模板编码", required = true, example = "test-01")
    private String templateCode;

    @ApiModelProperty(value = "短信类型", required = true, example = "1")
    private Integer templateType;

    @ApiModelProperty(value = "短信内容", required = true, example = "你好，你的验证码是 1024")
    private String templateContent;

    @ApiModelProperty(value = "短信参数", required = true, example = "name,code")
    private Map<String, Object> templateParams;

    @ApiModelProperty(value = "短信 API 的模板编号", required = true, example = "SMS_207945135")
    private String apiTemplateId;

    @ApiModelProperty(value = "手机号", required = true, example = "15601691300")
    private String mobile;

    @ApiModelProperty(value = "用户编号", example = "10")
    private Long userId;

    @ApiModelProperty(value = "用户类型", example = "1")
    private Integer userType;

    @ApiModelProperty(value = "发送状态", required = true, example = "1")
    private Integer sendStatus;

    @ApiModelProperty(value = "发送时间")
    private Date sendTime;

    @ApiModelProperty(value = "发送结果的编码", example = "0")
    private Integer sendCode;

    @ApiModelProperty(value = "发送结果的提示", example = "成功")
    private String sendMsg;

    @ApiModelProperty(value = "短信 API 发送结果的编码", example = "SUCCESS")
    private String apiSendCode;

    @ApiModelProperty(value = "短信 API 发送失败的提示", example = "成功")
    private String apiSendMsg;

    @ApiModelProperty(value = "短信 API 发送返回的唯一请求 ID", example = "3837C6D3-B96F-428C-BBB2-86135D4B5B99")
    private String apiRequestId;

    @ApiModelProperty(value = "短信 API 发送返回的序号", example = "62923244790")
    private String apiSerialNo;

    @ApiModelProperty(value = "接收状态", required = true, example = "0")
    private Integer receiveStatus;

    @ApiModelProperty(value = "接收时间")
    private Date receiveTime;

    @ApiModelProperty(value = "API 接收结果的编码", example = "DELIVRD")
    private String apiReceiveCode;

    @ApiModelProperty(value = "API 接收结果的说明", example = "用户接收成功")
    private String apiReceiveMsg;

    @ApiModelProperty(value = "创建时间", required = true)
    private Date createTime;

}


<|start_filename|>yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/InEnum.java<|end_filename|>
package cn.iocoder.yudao.framework.common.validation;

import cn.iocoder.yudao.framework.common.core.IntArrayValuable;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Target({
        ElementType.METHOD,
        ElementType.FIELD,
        ElementType.ANNOTATION_TYPE,
        ElementType.CONSTRUCTOR,
        ElementType.PARAMETER,
        ElementType.TYPE_USE
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
        validatedBy = InEnumValidator.class
)
public @interface InEnum {

    /**
     * @return 实现 EnumValuable 接口的
     */
    Class<? extends IntArrayValuable> value();

    String message() default "必须在指定范围 {value}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysUserSessionService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.auth;

import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.session.SysUserSessionPageReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

/**
 * 在线用户 Session Service 接口
 *
 * @author 芋道源码
 */
public interface SysUserSessionService {

    /**
     * 获得在线用户分页列表
     *
     * @param reqVO 分页条件
     * @return 份额与列表
     */
    PageResult<SysUserSessionDO> getUserSessionPage(SysUserSessionPageReqVO reqVO);

    /**
     * 移除超时的在线用户
     *
     * @return {@link Long } 移出的超时用户数量
     **/
    long clearSessionTimeout();

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/redis/vo/InfRedisKeyRespVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.controller.redis.vo;

import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

import java.time.Duration;

@ApiModel("Redis Key 信息 Response VO")
@Data
@Builder
@AllArgsConstructor
public class InfRedisKeyRespVO {

    @ApiModelProperty(value = "login_user:%s", required = true, example = "String")
    private String keyTemplate;

    @ApiModelProperty(value = "Key 类型的枚举", required = true, example = "String")
    private RedisKeyDefine.KeyTypeEnum keyType;

    @ApiModelProperty(value = "Value 类型", required = true, example = "java.lang.String")
    private Class valueType;

    @ApiModelProperty(value = "超时类型", required = true, example = "1")
    private RedisKeyDefine.TimeoutTypeEnum timeoutType;

    @ApiModelProperty(value = "过期时间，单位：毫秒", required = true, example = "1024")
    private Duration timeout;

    @ApiModelProperty(value = "备注", required = true, example = "啦啦啦啦~")
    private String memo;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/package-info.java<|end_filename|>
/**
 * 提供 POJO 类的实体转换
 *
 * 目前使用 MapStruct 框架
 */
package cn.iocoder.yudao.adminserver.modules.system.convert;


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/service/package-info.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.member.service;


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/service/logger/InfApiErrorLogCoreService.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.infra.service.logger;

import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;

/**
 * API 错误日志 Service 接口
 *
 * @author 芋道源码
 */
public interface InfApiErrorLogCoreService extends ApiErrorLogFrameworkService {

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props.js<|end_filename|>
/**
 * 此文件的作用为统一配置所有组件的props参数
 * 借此用户可以全局覆盖组件的props默认值
 * 无需在每个引入组件的页面中都配置一次
 */
import config from './config'

import actionSheet from './props/actionSheet.js'
import album from './props/album.js'
import alert from './props/alert.js'
import avatar from './props/avatar'
import avatarGroup from './props/avatarGroup'
import backtop from './props/backtop'
import badge from './props/badge'
import button from './props/button'
import calendar from './props/calendar'
import carKeyboard from './props/carKeyboard'
import cell from './props/cell'
import cellGroup from './props/cellGroup'
import checkbox from './props/checkbox'
import checkboxGroup from './props/checkboxGroup'
import circleProgress from './props/circleProgress'
import code from './props/code'
import codeInput from './props/codeInput'
import col from './props/col'
import collapse from './props/collapse'
import collapseItem from './props/collapseItem'
import columnNotice from './props/columnNotice'
import countDown from './props/countDown'
import countTo from './props/countTo'
import datetimePicker from './props/datetimePicker'
import divider from './props/divider'
import empty from './props/empty'
import form from './props/form'
import formItem from './props/formItem'
import gap from './props/gap'
import grid from './props/grid'
import gridItem from './props/gridItem'
import icon from './props/icon'
import image from './props/image'
import indexAnchor from './props/indexAnchor'
import indexList from './props/indexList'
import input from './props/input'
import keyboard from './props/keyboard'
import line from './props/line'
import lineProgress from './props/lineProgress'
import link from './props/link'
import list from './props/list'
import listItem from './props/listItem'
import loadingIcon from './props/loadingIcon'
import loadingPage from './props/loadingPage'
import loadmore from './props/loadmore'
import modal from './props/modal'
import navbar from './props/navbar'
import noNetwork from './props/noNetwork'
import noticeBar from './props/noticeBar'
import notify from './props/notify'
import numberBox from './props/numberBox'
import numberKeyboard from './props/numberKeyboard'
import overlay from './props/overlay'
import parse from './props/parse'
import picker from './props/picker'
import popup from './props/popup'
import radio from './props/radio'
import radioGroup from './props/radioGroup'
import rate from './props/rate'
import readMore from './props/readMore'
import row from './props/row'
import rowNotice from './props/rowNotice'
import scrollList from './props/scrollList'
import search from './props/search'
import section from './props/section'
import skeleton from './props/skeleton'
import slider from './props/slider'
import statusBar from './props/statusBar'
import steps from './props/steps'
import stepsItem from './props/stepsItem'
import sticky from './props/sticky'
import subsection from './props/subsection'
import swipeAction from './props/swipeAction'
import swipeActionItem from './props/swipeActionItem'
import swiper from './props/swiper'
import swipterIndicator from './props/swipterIndicator'
import _switch from './props/switch'
import tabbar from './props/tabbar'
import tabbarItem from './props/tabbarItem'
import tabs from './props/tabs'
import tag from './props/tag'
import text from './props/text'
import textarea from './props/textarea'
import toast from './props/toast'
import toolbar from './props/toolbar'
import tooltip from './props/tooltip'
import transition from './props/transition'
import upload from './props/upload'

const {
    color
} = config

export default {
    ...actionSheet,
    ...album,
    ...alert,
    ...avatar,
    ...avatarGroup,
    ...backtop,
    ...badge,
    ...button,
    ...calendar,
    ...carKeyboard,
    ...cell,
    ...cellGroup,
    ...checkbox,
    ...checkboxGroup,
    ...circleProgress,
    ...code,
    ...codeInput,
    ...col,
    ...collapse,
    ...collapseItem,
    ...columnNotice,
    ...countDown,
    ...countTo,
    ...datetimePicker,
    ...divider,
    ...empty,
    ...form,
    ...formItem,
    ...gap,
    ...grid,
    ...gridItem,
    ...icon,
    ...image,
    ...indexAnchor,
    ...indexList,
    ...input,
    ...keyboard,
    ...line,
    ...lineProgress,
    ...link,
    ...list,
    ...listItem,
    ...loadingIcon,
    ...loadingPage,
    ...loadmore,
    ...modal,
    ...navbar,
    ...noNetwork,
    ...noticeBar,
    ...notify,
    ...numberBox,
    ...numberKeyboard,
    ...overlay,
    ...parse,
    ...picker,
    ...popup,
    ...radio,
    ...radioGroup,
    ...rate,
    ...readMore,
    ...row,
    ...rowNotice,
    ...scrollList,
    ...search,
    ...section,
    ...skeleton,
    ...slider,
    ...statusBar,
    ...steps,
    ...stepsItem,
    ...sticky,
    ...subsection,
    ...swipeAction,
    ...swipeActionItem,
    ...swiper,
    ...swipterIndicator,
    ..._switch,
    ...tabbar,
    ...tabbarItem,
    ...tabs,
    ...tag,
    ...text,
    ...textarea,
    ...toast,
    ...toolbar,
    ...tooltip,
    ...transition,
    ...upload
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/auth/SysUserSessionCoreService.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.auth;

import cn.iocoder.yudao.framework.security.core.LoginUser;

/**
 * 在线用户 Session Core Service 接口
 *
 * @author 芋道源码
 */
public interface SysUserSessionCoreService {

    /**
     * 创建在线用户 Session
     *
     * @param loginUser 登录用户
     * @param userIp 用户 IP
     * @param userAgent 用户 UA
     * @return Session 编号
     */
    String createUserSession(LoginUser loginUser, String userIp, String userAgent);

    /**
     * 刷新在线用户 Session 的更新时间
     *
     * @param sessionId Session 编号
     * @param loginUser 登录用户
     */
    void refreshUserSession(String sessionId, LoginUser loginUser);

    /**
     * 删除在线用户 Session
     *
     * @param sessionId Session 编号
     */
    void deleteUserSession(String sessionId);

    /**
     * 获得 Session 编号对应的在线用户
     *
     * @param sessionId Session 编号
     * @return 在线用户
     */
    LoginUser getLoginUser(String sessionId);

    /**
     * 获得 Session 超时时间，单位：毫秒
     *
     * @return 超时时间
     */
    Long getSessionTimeoutMillis();

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/SysOperateLogService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.logger;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService;
import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.operatelog.SysOperateLogExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.operatelog.SysOperateLogPageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.logger.SysOperateLogDO;

import java.util.List;

/**
 * 操作日志 Service 接口
 */
public interface SysOperateLogService extends OperateLogFrameworkService {

    /**
     * 获得操作日志分页列表
     *
     * @param reqVO 分页条件
     * @return 操作日志分页列表
     */
    PageResult<SysOperateLogDO> getOperateLogPage(SysOperateLogPageReqVO reqVO);

    /**
     * 获得操作日志列表
     *
     * @param reqVO 列表条件
     * @return 日志列表
     */
    List<SysOperateLogDO> getOperateLogs(SysOperateLogExportReqVO reqVO);

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/luch-request/index.js<|end_filename|>
import Request from './core/Request'

export default Request


<|start_filename|>yudao-admin-ui/src/components/bpmnProcessDesigner/src/utils/log.js<|end_filename|>
class Log {
  static type = ["primary", "success", "warn", "error", "info"];

  static typeColor(type = "default") {
    let color = "";
    switch (type) {
      case "primary":
        color = "#2d8cf0";
        break;
      case "success":
        color = "#19be6b";
        break;
      case "info":
        color = "#909399";
        break;
      case "warn":
        color = "#ff9900";
        break;
      case "error":
        color = "#f03f14";
        break;
      case "default":
        color = "#35495E";
        break;
      default:
        color = type;
        break;
    }
    return color;
  }

  static print(text, type = "default", back = false) {
    if (typeof text === "object") {
      // 如果是對象則調用打印對象方式
      console.dir(text);
      return;
    }
    if (back) {
      // 如果是打印帶背景圖的
      console.log(`%c ${text} `, `background:${this.typeColor(type)}; padding: 2px; border-radius: 4px;color: #fff;`);
    } else {
      console.log(`%c ${text} `, `color: ${this.typeColor(type)};`);
    }
  }

  static pretty(title, text, type = "primary") {
    if (typeof text === "object") {
      console.log(
        `%c ${title} %c`,
        `background:${this.typeColor(type)};border:1px solid ${this.typeColor(type)}; padding: 1px; border-radius: 4px 0 0 4px; color: #fff;`
      );
      console.dir(text);
      return;
    }
    console.log(
      `%c ${title} %c ${text} %c`,
      `background:${this.typeColor(type)};border:1px solid ${this.typeColor(type)}; padding: 1px; border-radius: 4px 0 0 4px; color: #fff;`,
      `border:1px solid ${this.typeColor(type)}; padding: 1px; border-radius: 0 4px 4px 0; color: ${this.typeColor(type)};`,
      "background:transparent"
    );
  }
}
export default Log;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/tooltip.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:25:14
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/tooltip.js
 */
export default {
    // tooltip 组件
    tooltip: {
        text: '',
        copyText: '',
        size: 14,
        color: '#606266',
        bgColor: 'transparent',
        direction: 'top',
        zIndex: 10071,
        showCopy: true,
        buttons: () => [],
        overlay: true,
        showToast: true
    }
}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/SysAuthSendSmsReqVO.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;

import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.common.validation.Mobile;
import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;

import javax.validation.constraints.NotNull;

@ApiModel("发送手机验证码 Response VO")
@Data
@Accessors(chain = true)
public class SysAuthSendSmsReqVO {

    @ApiModelProperty(value = "手机号", example = "15601691234")
    @Mobile
    private String mobile;

    @ApiModelProperty(value = "发送场景", example = "1", notes = "对应 MbrSmsSceneEnum 枚举")
    @NotNull(message = "发送场景不能为空")
    @InEnum(SysSmsSceneEnum.class)
    private Integer scene;

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/statusBar.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:20:39
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/statusBar.js
 */
export default {
    // statusBar
    statusBar: {
        bgColor: 'transparent'
    }
}


<|start_filename|>yudao-admin-ui/src/api/infra/config.js<|end_filename|>
import request from '@/utils/request'

// 查询参数列表
export function listConfig(query) {
  return request({
    url: '/infra/config/page',
    method: 'get',
    params: query
  })
}

// 查询参数详细
export function getConfig(configId) {
  return request({
    url: '/infra/config/get?id=' + configId,
    method: 'get'
  })
}

// 根据参数键名查询参数值
export function getConfigKey(configKey) {
  return request({
    url: '/infra/config/get-value-by-key?key=' + configKey,
    method: 'get'
  })
}

// 新增参数配置
export function addConfig(data) {
  return request({
    url: '/infra/config/create',
    method: 'post',
    data: data
  })
}

// 修改参数配置
export function updateConfig(data) {
  return request({
    url: '/infra/config/update',
    method: 'put',
    data: data
  })
}

// 删除参数配置
export function delConfig(configId) {
  return request({
    url: '/infra/config/delete?id=' + configId,
    method: 'delete'
  })
}

// 导出参数
export function exportConfig(query) {
  return request({
    url: '/infra/config/export',
    method: 'get',
    params: query,
    responseType: 'blob'
  })
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/collapseItem.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 16:56:42
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/collapseItem.js
 */
export default {
    // collapseItem 组件
    collapseItem: {
        title: '',
        value: '',
        label: '',
        disabled: false,
        isLink: true,
        clickable: true,
        border: true,
        align: 'left',
        name: '',
        icon: '',
        duration: 300
    }
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-mq/src/main/java/cn/iocoder/yudao/framework/mq/package-info.java<|end_filename|>
/**
 * 消息队列，基于 Redis 提供：
 * 1. 基于 Pub/Sub 实现广播消费
 * 2. 基于 Stream 实现集群消费
 */
package cn.iocoder.yudao.framework.mq;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/cellGroup.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 16:54:16
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/cellGroup.js
 */
export default {
    // cell-group组件的props
    cellGroup: {
        title: '',
        border: true,
        customStyle: {}
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/enums/InfDictTypeConstants.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.enums;

/**
 * Infra 字典类型的枚举类
 *
 * @author 芋道源码
 */
public interface InfDictTypeConstants {

    String REDIS_TIMEOUT_TYPE = "inf_redis_timeout_type"; // Redis 超时类型

    String JOB_STATUS = "inf_job_status"; // 定时任务状态的枚举
    String JOB_LOG_STATUS = "inf_job_log_status"; // 定时任务日志状态的枚举

    String API_ERROR_LOG_PROCESS_STATUS = "inf_api_error_log_process_status"; // API 错误日志的处理状态的枚举

    String ERROR_CODE_TYPE = "inf_error_code_type"; // 错误码的类型枚举

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/mysql/logger/SysLoginLogCoreMapper.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.logger;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger.SysLoginLogDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface SysLoginLogCoreMapper extends BaseMapperX<SysLoginLogDO> {

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/sms/impl/SysSmsTemplateCoreServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.sms.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms.SysSmsTemplateCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsTemplateCoreService;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 短信模板 Core Service 接口
 *
 * @author 芋道源码
 */
@Service
@Slf4j
public class SysSmsTemplateCoreServiceImpl implements SysSmsTemplateCoreService {

    /**
     * 定时执行 {@link #schedulePeriodicRefresh()} 的周期
     * 因为已经通过 Redis Pub/Sub 机制，所以频率不需要高
     */
    private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L;

    /**
     * 短信模板缓存
     * key：短信模板编码 {@link SysSmsTemplateDO#getCode()}
     *
     * 这里声明 volatile 修饰的原因是，每次刷新时，直接修改指向
     */
    private volatile Map<String, SysSmsTemplateDO> smsTemplateCache;
    /**
     * 缓存短信模板的最大更新时间，用于后续的增量轮询，判断是否有更新
     */
    private volatile Date maxUpdateTime;

    @Resource
    private SysSmsTemplateCoreMapper smsTemplateCoreMapper;

    @Override
    @PostConstruct
    public void initLocalCache() {
        // 获取短信模板列表，如果有更新
        List<SysSmsTemplateDO> smsTemplateList = this.loadSmsTemplateIfUpdate(maxUpdateTime);
        if (CollUtil.isEmpty(smsTemplateList)) {
            return;
        }

        // 写入缓存
        ImmutableMap.Builder<String, SysSmsTemplateDO> builder = ImmutableMap.builder();
        smsTemplateList.forEach(sysSmsTemplateDO -> builder.put(sysSmsTemplateDO.getCode(), sysSmsTemplateDO));
        smsTemplateCache = builder.build();
        assert smsTemplateList.size() > 0; // 断言，避免告警
        maxUpdateTime = smsTemplateList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime();
        log.info("[initLocalCache][初始化 SmsTemplate 数量为 {}]", smsTemplateList.size());
    }

    /**
     * 如果短信模板发生变化，从数据库中获取最新的全量短信模板。
     * 如果未发生变化，则返回空
     *
     * @param maxUpdateTime 当前短信模板的最大更新时间
     * @return 短信模板列表
     */
    private List<SysSmsTemplateDO> loadSmsTemplateIfUpdate(Date maxUpdateTime) {
        // 第一步，判断是否要更新。
        if (maxUpdateTime == null) { // 如果更新时间为空，说明 DB 一定有新数据
            log.info("[loadSmsTemplateIfUpdate][首次加载全量短信模板]");
        } else { // 判断数据库中是否有更新的短信模板
            if (smsTemplateCoreMapper.selectExistsByUpdateTimeAfter(maxUpdateTime) == null) {
                return null;
            }
            log.info("[loadSmsTemplateIfUpdate][增量加载全量短信模板]");
        }
        // 第二步，如果有更新，则从数据库加载所有短信模板
        return smsTemplateCoreMapper.selectList();
    }

    @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD)
    public void schedulePeriodicRefresh() {
        initLocalCache();
    }

    @Override
    public SysSmsTemplateDO getSmsTemplateByCodeFromCache(String code) {
        return smsTemplateCache.get(code);
    }

    @Override
    public String formatSmsTemplateContent(String content, Map<String, Object> params) {
        return StrUtil.format(content, params);
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/dept/impl/SysPostServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.dept.impl;

import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.post.SysPostCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.post.SysPostExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.post.SysPostPageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.post.SysPostUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.convert.dept.SysPostConvert;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.dept.SysPostMapper;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysPostDO;
import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.List;

import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.*;

/**
 * 岗位 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class SysPostServiceImpl implements SysPostService {

    @Resource
    private SysPostMapper postMapper;

    @Override
    public Long createPost(SysPostCreateReqVO reqVO) {
        // 校验正确性
        this.checkCreateOrUpdate(null, reqVO.getName(), reqVO.getCode());
        // 插入岗位
        SysPostDO post = SysPostConvert.INSTANCE.convert(reqVO);
        postMapper.insert(post);
        return post.getId();
    }

    @Override
    public void updatePost(SysPostUpdateReqVO reqVO) {
        // 校验正确性
        this.checkCreateOrUpdate(reqVO.getId(), reqVO.getName(), reqVO.getCode());
        // 更新岗位
        SysPostDO updateObj = SysPostConvert.INSTANCE.convert(reqVO);
        postMapper.updateById(updateObj);
    }

    @Override
    public void deletePost(Long id) {
        // 校验是否存在
        this.checkPostExists(id);
        // 删除部门
        postMapper.deleteById(id);
    }

    @Override
    public List<SysPostDO> getPosts(Collection<Long> ids, Collection<Integer> statuses) {
        return postMapper.selectList(ids, statuses);
    }

    @Override
    public PageResult<SysPostDO> getPostPage(SysPostPageReqVO reqVO) {
        return postMapper.selectPage(reqVO);
    }

    @Override
    public List<SysPostDO> getPosts(SysPostExportReqVO reqVO) {
        return postMapper.selectList(reqVO);
    }

    @Override
    public SysPostDO getPost(Long id) {
        return postMapper.selectById(id);
    }

    private void checkCreateOrUpdate(Long id, String name, String code) {
        // 校验自己存在
        checkPostExists(id);
        // 校验岗位名的唯一性
        checkPostNameUnique(id, name);
        // 校验岗位编码的唯一性
        checkPostCodeUnique(id, code);
    }

    private void checkPostNameUnique(Long id, String name) {
        SysPostDO post = postMapper.selectByName(name);
        if (post == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的岗位
        if (id == null) {
            throw ServiceExceptionUtil.exception(POST_NAME_DUPLICATE);
        }
        if (!post.getId().equals(id)) {
            throw ServiceExceptionUtil.exception(POST_NAME_DUPLICATE);
        }
    }

    private void checkPostCodeUnique(Long id, String code) {
        SysPostDO post = postMapper.selectByCode(code);
        if (post == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的岗位
        if (id == null) {
            throw ServiceExceptionUtil.exception(POST_CODE_DUPLICATE);
        }
        if (!post.getId().equals(id)) {
            throw ServiceExceptionUtil.exception(POST_CODE_DUPLICATE);
        }
    }

    private void checkPostExists(Long id) {
        if (id == null) {
            return;
        }
        SysPostDO post = postMapper.selectById(id);
        if (post == null) {
            throw ServiceExceptionUtil.exception(POST_NOT_FOUND);
        }
    }

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/filter/DruidAdRemoveFilter.java<|end_filename|>
package cn.iocoder.yudao.framework.datasource.core.filter;

import com.alibaba.druid.util.Utils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Druid 底部广告过滤器
 *
 * @author 芋道源码
 */
public class DruidAdRemoveFilter extends OncePerRequestFilter {

    /**
     * common.js 的路径
     */
    private static final String COMMON_JS_ILE_PATH = "support/http/resources/js/common.js";

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        chain.doFilter(request, response);
        // 重置缓冲区，响应头不会被重置
        response.resetBuffer();
        // 获取 common.js
        String text = Utils.readFromResource(COMMON_JS_ILE_PATH);
        // 正则替换 banner, 除去底部的广告信息
        text = text.replaceAll("<a.*?banner\"></a><br/>", "");
        text = text.replaceAll("powered.*?shrek.wang</a>", "");
        response.getWriter().write(text);
    }

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/sms/SysSmsCoreService.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.sms;

import cn.iocoder.yudao.coreservice.modules.system.mq.message.sms.SysSmsSendMessage;

import java.util.List;
import java.util.Map;

/**
 * 短信 Service Core 接口
 *
 * 接入方，通过调用 send 开头的方法，创建发送短信的任务到 MQ 中
 * 后续，yudao-admin-server 监听 MQ，执行真正的短信发送逻辑
 *
 * @author 芋道源码
 */
public interface SysSmsCoreService {

    /**
     * 发送单条短信给后台用户
     *
     * 在 mobile 为空时，使用 userId 加载对应管理员的手机号
     *
     * @param mobile 手机号
     * @param userId 用户编号
     * @param templateCode 短信模板编号
     * @param templateParams 短信模板参数
     * @return 发送日志编号
     */
    Long sendSingleSmsToAdmin(String mobile, Long userId,
                              String templateCode, Map<String, Object> templateParams);

    /**
     * 发送单条短信给前台用户
     *
     * 在 mobile 为空时，使用 userId 加载对应会员的手机号
     *
     * @param mobile 手机号
     * @param userId 用户编号
     * @param templateCode 短信模板编号
     * @param templateParams 短信模板参数
     * @return 发送日志编号
     */
    Long sendSingleSmsToMember(String mobile, Long userId,
                               String templateCode, Map<String, Object> templateParams);

    Long sendSingleSms(String mobile, Long userId, Integer userType,
                       String templateCode, Map<String, Object> templateParams);

    void sendBatchSms(List<String> mobiles, List<Long> userIds, Integer userType,
                      String templateCode, Map<String, Object> templateParams);

    void doSendSms(SysSmsSendMessage message);

    /**
     * 接收短信的接收结果
     *
     * @param channelCode 渠道编码
     * @param text 结果内容
     * @throws Throwable 处理失败时，抛出异常
     */
    void receiveSmsStatus(String channelCode, String text) throws Throwable;

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-number-keyboard/props.js<|end_filename|>
export default {
    props: {
        // 键盘的类型，number-数字键盘，card-身份证键盘
        mode: {
            type: String,
            default: uni.$u.props.numberKeyboard.value
        },
        // 是否显示键盘的"."符号
        dotDisabled: {
            type: Boolean,
            default: uni.$u.props.numberKeyboard.dotDisabled
        },
        // 是否打乱键盘按键的顺序
        random: {
            type: Boolean,
            default: uni.$u.props.numberKeyboard.random
        }
    }
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/switch.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:22:24
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/switch.js
 */
export default {
    // switch
    switch: {
        loading: false,
        disabled: false,
        size: 25,
        activeColor: '#2979ff',
        inactiveColor: '#ffffff',
        value: false,
        activeValue: true,
        inactiveValue: false,
        asyncChange: false,
        space: 0
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/enums/ToolDictTypeConstants.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.enums;

/**
 * Tool 字典类型的枚举类
 *
 * @author 芋道源码
 */
public interface ToolDictTypeConstants {

    String TEST_DEMO_TYPE = "tool_test_demo_type";

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/dict/SysDictTypeConvert.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.convert.dict;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.type.*;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dict.SysDictTypeDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import java.util.List;

@Mapper
public interface SysDictTypeConvert {

    SysDictTypeConvert INSTANCE = Mappers.getMapper(SysDictTypeConvert.class);

    PageResult<SysDictTypeRespVO> convertPage(PageResult<SysDictTypeDO> bean);

    SysDictTypeRespVO convert(SysDictTypeDO bean);

    SysDictTypeDO convert(SysDictTypeCreateReqVO bean);

    SysDictTypeDO convert(SysDictTypeUpdateReqVO bean);

    List<SysDictTypeSimpleRespVO> convertList(List<SysDictTypeDO> list);

    List<SysDictTypeExcelVO> convertList02(List<SysDictTypeDO> list);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/codegen/config/CodegenConfiguration.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.framework.codegen.config;

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(CodegenProperties.class)
public class CodegenConfiguration {
}


<|start_filename|>yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/infra/service/package-info.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.infra.service;


<|start_filename|>yudao-admin-ui/src/components/bpmnProcessDesigner/package/penal/listeners/utilSelf.js<|end_filename|>
// 初始化表单数据
export function initListenerForm(listener) {
  let self = {
    ...listener
  };
  if (listener.script) {
    self = {
      ...listener,
      ...listener.script,
      scriptType: listener.script.resource ? "externalScript" : "inlineScript"
    };
  }
  if (listener.event === "timeout" && listener.eventDefinitions) {
    if (listener.eventDefinitions.length) {
      let k = "";
      for (let key in listener.eventDefinitions[0]) {
        console.log(listener.eventDefinitions, key);
        if (key.indexOf("time") !== -1) {
          k = key;
          self.eventDefinitionType = key.replace("time", "").toLowerCase();
        }
      }
      console.log(k);
      self.eventTimeDefinitions = listener.eventDefinitions[0][k].body;
    }
  }
  return self;
}

export function initListenerType(listener) {
  let listenerType;
  if (listener.class) listenerType = "classListener";
  if (listener.expression) listenerType = "expressionListener";
  if (listener.delegateExpression) listenerType = "delegateExpressionListener";
  if (listener.script) listenerType = "scriptListener";
  return {
    ...JSON.parse(JSON.stringify(listener)),
    ...(listener.script ?? {}),
    listenerType: listenerType
  };
}

export const listenerType = {
  classListener: "Java 类",
  expressionListener: "表达式",
  delegateExpressionListener: "代理表达式",
  scriptListener: "脚本"
};

export const eventType = {
  create: "创建",
  assignment: "指派",
  complete: "完成",
  delete: "删除",
  update: "更新",
  timeout: "超时"
};

export const fieldType = {
  string: "字符串",
  expression: "表达式"
};


<|start_filename|>yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/SysMenuServiceTest.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.permission;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.adminserver.modules.system.controller.permission.vo.menu.SysMenuCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.permission.vo.menu.SysMenuListReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.permission.vo.menu.SysMenuUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysMenuDO;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.permission.SysMenuMapper;
import cn.iocoder.yudao.adminserver.modules.system.enums.permission.MenuTypeEnum;
import cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission.SysMenuProducer;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.impl.SysMenuServiceImpl;
import cn.iocoder.yudao.framework.common.util.spring.SpringAopUtils;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import com.google.common.collect.Multimap;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;

import javax.annotation.Resource;
import java.util.*;

import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;

@Import(SysMenuServiceImpl.class)
public class SysMenuServiceTest extends BaseDbUnitTest {

    @Resource
    private SysMenuServiceImpl sysMenuService;

    @MockBean
    private SysPermissionService sysPermissionService;

    @MockBean
    private SysMenuProducer sysMenuProducer;

    @Resource
    private SysMenuMapper menuMapper;

    @Test
    public void testInitLocalCache_success() throws Exception {
        SysMenuDO menuDO1 = createMenuDO(MenuTypeEnum.MENU, "xxxx", 0L);
        menuMapper.insert(menuDO1);
        SysMenuDO menuDO2 = createMenuDO(MenuTypeEnum.MENU, "xxxx", 0L);
        menuMapper.insert(menuDO2);

        // 调用
        sysMenuService.initLocalCache();

        // 获取代理对象
        SysMenuServiceImpl target = (SysMenuServiceImpl) SpringAopUtils.getTarget(sysMenuService);

        Map<Long, SysMenuDO> menuCache =
                (Map<Long, SysMenuDO>) BeanUtil.getFieldValue(target, "menuCache");
        Assert.isTrue(menuCache.size() == 2);
        assertPojoEquals(menuDO1, menuCache.get(menuDO1.getId()));
        assertPojoEquals(menuDO2, menuCache.get(menuDO2.getId()));

        Multimap<String, SysMenuDO> permissionMenuCache =
                (Multimap<String, SysMenuDO>) BeanUtil.getFieldValue(target, "permissionMenuCache");
        Assert.isTrue(permissionMenuCache.size() == 2);
        assertPojoEquals(menuDO1, permissionMenuCache.get(menuDO1.getPermission()));
        assertPojoEquals(menuDO2, permissionMenuCache.get(menuDO2.getPermission()));

        Date maxUpdateTime = (Date) BeanUtil.getFieldValue(target, "maxUpdateTime");
        assertEquals(ObjectUtils.max(menuDO1.getUpdateTime(), menuDO2.getUpdateTime()), maxUpdateTime);
    }

    @Test
    public void testCreateMenu_success() {
        //构造父目录
        SysMenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, "parent", 0L);
        menuMapper.insert(menuDO);
        Long parentId = menuDO.getId();

        //调用
        SysMenuCreateReqVO vo = randomPojo(SysMenuCreateReqVO.class, o -> {
            o.setParentId(parentId);
            o.setName("testSonName");
            o.setType(MenuTypeEnum.MENU.getType());
            o.setStatus(RandomUtils.randomCommonStatus());
        });
        Long menuId = sysMenuService.createMenu(vo);

        //断言
        Assertions.assertNotNull(menuId);
        // 校验记录的属性是否正确
        SysMenuDO ret = menuMapper.selectById(menuId);
        assertPojoEquals(vo, ret);
        // 校验调用
        verify(sysMenuProducer).sendMenuRefreshMessage();
    }

    @Test
    public void testUpdateMenu_success() {
        //构造父子目录
        SysMenuDO sonMenuDO = initParentAndSonMenuDO();
        Long sonId = sonMenuDO.getId();
        Long parentId = sonMenuDO.getParentId();

        //调用
        SysMenuUpdateReqVO vo = randomPojo(SysMenuUpdateReqVO.class, o -> {
            o.setId(sonId);
            o.setParentId(parentId);
            o.setType(MenuTypeEnum.MENU.getType());
            o.setStatus(RandomUtils.randomCommonStatus());
            o.setName("pppppp"); //修改名字
        });
        sysMenuService.updateMenu(vo);

        //断言
        // 校验记录的属性是否正确
        SysMenuDO ret = menuMapper.selectById(sonId);
        assertPojoEquals(vo, ret);
        // 校验调用
        verify(sysMenuProducer).sendMenuRefreshMessage();
    }

    @Test
    public void testUpdateMenu_sonIdNotExist() {
        Long sonId = 99999L;
        Long parentId = 10000L;

        //调用
        SysMenuUpdateReqVO vo = randomPojo(SysMenuUpdateReqVO.class, o -> {
            o.setId(sonId);
            o.setParentId(parentId);
            o.setType(MenuTypeEnum.MENU.getType());
            o.setStatus(RandomUtils.randomCommonStatus());
        });
        //断言
        assertServiceException(() -> sysMenuService.updateMenu(vo), MENU_NOT_EXISTS);
    }

    @Test
    public void testDeleteMenu_success() {
        SysMenuDO sonMenuDO = initParentAndSonMenuDO();
        Long sonId = sonMenuDO.getId();

        //调用
        sysMenuService.deleteMenu(sonId);

        //断言
        SysMenuDO menuDO = menuMapper.selectById(sonId);
        Assert.isNull(menuDO);
        verify(sysPermissionService).processMenuDeleted(sonId);
        verify(sysMenuProducer).sendMenuRefreshMessage();
    }

    @Test
    public void testDeleteMenu_menuNotExist() {
        Long sonId = 99999L;

        assertServiceException(() -> sysMenuService.deleteMenu(sonId), MENU_NOT_EXISTS);
    }

    @Test
    public void testDeleteMenu_existChildren() {
        SysMenuDO sonMenu = initParentAndSonMenuDO();
        Long parentId = sonMenu.getParentId();

        assertServiceException(() -> sysMenuService.deleteMenu(parentId), MENU_EXISTS_CHILDREN);
    }

    @Test
    public void testGetMenus_success() {
        Map<Long, SysMenuDO> idMenuMap = new HashMap<>();
        SysMenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, "parent", 0L);
        menuMapper.insert(menuDO);
        idMenuMap.put(menuDO.getId(), menuDO);

        SysMenuDO sonMenu = createMenuDO(MenuTypeEnum.MENU, "son", menuDO.getId());
        menuMapper.insert(sonMenu);
        idMenuMap.put(sonMenu.getId(), sonMenu);

        //调用
        List<SysMenuDO> menuDOS = sysMenuService.getMenus();

        //断言
        Assert.isTrue(menuDOS.size() == idMenuMap.size());
        menuDOS.forEach(m -> assertPojoEquals(idMenuMap.get(m.getId()), m));
    }

    @Test
    public void testGetMenusReqVo_success() {
        Map<Long, SysMenuDO> idMenuMap = new HashMap<>();
        //用于验证可以模糊搜索名称包含"name"，状态为1的menu
        SysMenuDO menu = createMenuDO(MenuTypeEnum.MENU, "name2", 0L, 1);
        menuMapper.insert(menu);
        idMenuMap.put(menu.getId(), menu);

        menu = createMenuDO(MenuTypeEnum.MENU, "11name111", 0L, 1);
        menuMapper.insert(menu);
        idMenuMap.put(menu.getId(), menu);

        menu = createMenuDO(MenuTypeEnum.MENU, "name", 0L, 1);
        menuMapper.insert(menu);
        idMenuMap.put(menu.getId(), menu);

        //以下是不符合搜索条件的的menu
        menu = createMenuDO(MenuTypeEnum.MENU, "xxxxxx", 0L, 1);
        menuMapper.insert(menu);
        menu = createMenuDO(MenuTypeEnum.MENU, "name", 0L, 2);
        menuMapper.insert(menu);

        //调用
        SysMenuListReqVO reqVO = new SysMenuListReqVO();
        reqVO.setStatus(1);
        reqVO.setName("name");
        List<SysMenuDO> menuDOS = sysMenuService.getMenus(reqVO);

        //断言
        Assert.isTrue(menuDOS.size() == idMenuMap.size());
        menuDOS.forEach(m -> assertPojoEquals(idMenuMap.get(m.getId()), m));
    }

    @Test
    public void testListMenusFromCache_success() throws Exception {
        Map<Long, SysMenuDO> mockCacheMap = new HashMap<>();
        //获取代理对象
        SysMenuServiceImpl target = (SysMenuServiceImpl) SpringAopUtils.getTarget(sysMenuService);
        BeanUtil.setFieldValue(target, "menuCache", mockCacheMap);

        Map<Long, SysMenuDO> idMenuMap = new HashMap<>();
        //用于验证搜索类型为MENU,状态为1的menu
        SysMenuDO menuDO = createMenuDO(1L, MenuTypeEnum.MENU, "name", 0L, 1);
        mockCacheMap.put(menuDO.getId(), menuDO);
        idMenuMap.put(menuDO.getId(), menuDO);

        menuDO = createMenuDO(2L, MenuTypeEnum.MENU, "name", 0L, 1);
        mockCacheMap.put(menuDO.getId(), menuDO);
        idMenuMap.put(menuDO.getId(), menuDO);

        //以下是不符合搜索条件的menu
        menuDO = createMenuDO(3L, MenuTypeEnum.BUTTON, "name", 0L, 1);
        mockCacheMap.put(menuDO.getId(), menuDO);
        menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2);
        mockCacheMap.put(menuDO.getId(), menuDO);

        List<SysMenuDO> menuDOS = sysMenuService.listMenusFromCache(Collections.singletonList(MenuTypeEnum.MENU.getType()),
                Collections.singletonList(CommonStatusEnum.DISABLE.getStatus()));
        Assert.isTrue(menuDOS.size() == idMenuMap.size());
        menuDOS.forEach(m -> assertPojoEquals(idMenuMap.get(m.getId()), m));
    }

    @Test
    public void testListMenusFromCache2_success() throws Exception {
        Map<Long, SysMenuDO> mockCacheMap = new HashMap<>();
        //获取代理对象
        SysMenuServiceImpl target = (SysMenuServiceImpl) SpringAopUtils.getTarget(sysMenuService);
        BeanUtil.setFieldValue(target, "menuCache", mockCacheMap);

        Map<Long, SysMenuDO> idMenuMap = new HashMap<>();
        //验证搜索id为1, 类型为MENU, 状态为1 的menu
        SysMenuDO menuDO = createMenuDO(1L, MenuTypeEnum.MENU, "name", 0L, 1);
        mockCacheMap.put(menuDO.getId(), menuDO);
        idMenuMap.put(menuDO.getId(), menuDO);

        //以下是不符合搜索条件的menu
        menuDO = createMenuDO(2L, MenuTypeEnum.MENU, "name", 0L, 1);
        mockCacheMap.put(menuDO.getId(), menuDO);
        menuDO = createMenuDO(3L, MenuTypeEnum.BUTTON, "name", 0L, 1);
        mockCacheMap.put(menuDO.getId(), menuDO);
        menuDO = createMenuDO(4L, MenuTypeEnum.MENU, "name", 0L, 2);
        mockCacheMap.put(menuDO.getId(), menuDO);

        List<SysMenuDO> menuDOS = sysMenuService.listMenusFromCache(Collections.singletonList(1L),
                Collections.singletonList(MenuTypeEnum.MENU.getType()), Collections.singletonList(1));
        Assert.isTrue(menuDOS.size() == idMenuMap.size());
        menuDOS.forEach(menu -> assertPojoEquals(idMenuMap.get(menu.getId()), menu));
    }

    @Test
    public void testCheckParentResource_success() {
        SysMenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, "parent", 0L);
        menuMapper.insert(menuDO);
        Long parentId = menuDO.getId();

        sysMenuService.checkParentResource(parentId, null);
    }

    @Test
    public void testCheckParentResource_canNotSetSelfToBeParent() {
        assertServiceException(() -> sysMenuService.checkParentResource(1L, 1L), MENU_PARENT_ERROR);
    }

    @Test
    public void testCheckParentResource_parentNotExist() {
        assertServiceException(() -> sysMenuService.checkParentResource(randomLongId(), null), MENU_PARENT_NOT_EXISTS);
    }

    @Test
    public void testCheckParentResource_parentTypeError() {
        SysMenuDO menuDO = createMenuDO(MenuTypeEnum.BUTTON, "parent", 0L);
        menuMapper.insert(menuDO);
        Long parentId = menuDO.getId();

        assertServiceException(() -> sysMenuService.checkParentResource(parentId, null), MENU_PARENT_NOT_DIR_OR_MENU);
    }

    @Test
    public void testCheckResource_success() {
        SysMenuDO sonMenu = initParentAndSonMenuDO();
        Long parentId = sonMenu.getParentId();

        Long otherSonMenuId = randomLongId();
        String otherSonMenuName = randomString();

        sysMenuService.checkResource(parentId, otherSonMenuName, otherSonMenuId);
    }

    @Test
    public void testCheckResource_sonMenuNameDuplicate(){
        SysMenuDO sonMenu=initParentAndSonMenuDO();
        Long parentId=sonMenu.getParentId();

        Long otherSonMenuId=randomLongId();
        String otherSonMenuName=sonMenu.getName(); //相同名称

        assertServiceException(() -> sysMenuService.checkResource(parentId, otherSonMenuName, otherSonMenuId), MENU_NAME_DUPLICATE);
    }

    /**
     * 构造父子目录，返回子目录
     *
     * @return
     */
    private SysMenuDO initParentAndSonMenuDO() {
        //构造父子目录
        SysMenuDO menuDO = createMenuDO(MenuTypeEnum.MENU, "parent", 0L);
        menuMapper.insert(menuDO);
        Long parentId = menuDO.getId();

        SysMenuDO sonMenuDO = createMenuDO(MenuTypeEnum.MENU, "testSonName", parentId);
        menuMapper.insert(sonMenuDO);
        return sonMenuDO;
    }

    private SysMenuDO createMenuDO(MenuTypeEnum typeEnum, String menuName, Long parentId) {
        return createMenuDO(typeEnum, menuName, parentId, RandomUtils.randomCommonStatus());
    }

    private SysMenuDO createMenuDO(MenuTypeEnum typeEnum, String menuName, Long parentId, Integer status) {
        return createMenuDO(null, typeEnum, menuName, parentId, status);
    }

    private SysMenuDO createMenuDO(Long id, MenuTypeEnum typeEnum, String menuName, Long parentId, Integer status) {
        return randomPojo(SysMenuDO.class, o -> {
            o.setId(id);
            o.setParentId(parentId);
            o.setType(typeEnum.getType());
            o.setStatus(status);
            o.setName(menuName);
        });
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/errorcode/SysErrorCodeConvert.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.convert.errorcode;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.tool.framework.errorcode.core.dto.ErrorCodeAutoGenerateReqDTO;
import cn.iocoder.yudao.adminserver.modules.tool.framework.errorcode.core.dto.ErrorCodeRespDTO;
import cn.iocoder.yudao.adminserver.modules.system.controller.errorcode.vo.SysErrorCodeCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.errorcode.vo.SysErrorCodeExcelVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.errorcode.vo.SysErrorCodeRespVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.errorcode.vo.SysErrorCodeUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.errorcode.SysErrorCodeDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import java.util.List;

/**
 * 错误码 Convert
 *
 * @author 芋道源码
 */
@Mapper
public interface SysErrorCodeConvert {

    SysErrorCodeConvert INSTANCE = Mappers.getMapper(SysErrorCodeConvert.class);

    SysErrorCodeDO convert(SysErrorCodeCreateReqVO bean);

    SysErrorCodeDO convert(SysErrorCodeUpdateReqVO bean);

    SysErrorCodeRespVO convert(SysErrorCodeDO bean);

    List<SysErrorCodeRespVO> convertList(List<SysErrorCodeDO> list);

    PageResult<SysErrorCodeRespVO> convertPage(PageResult<SysErrorCodeDO> page);

    List<SysErrorCodeExcelVO> convertList02(List<SysErrorCodeDO> list);

    SysErrorCodeDO convert(ErrorCodeAutoGenerateReqDTO bean);

    List<ErrorCodeRespDTO> convertList03(List<SysErrorCodeDO> list);

}


<|start_filename|>yudao-admin-server/src/test-integration/java/cn/iocoder/yudao/adminserver/modules/system/service/sms/SysSmsServiceIntegrationTest.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.sms;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.iocoder.yudao.adminserver.BaseDbAndRedisIntegrationTest;
import cn.iocoder.yudao.adminserver.modules.system.mq.consumer.sms.SysSmsSendConsumer;
import cn.iocoder.yudao.adminserver.modules.system.mq.producer.sms.SysSmsProducer;
import cn.iocoder.yudao.adminserver.modules.system.service.sms.impl.SysSmsChannelServiceImpl;
import cn.iocoder.yudao.adminserver.modules.system.service.sms.impl.SysSmsLogServiceImpl;
import cn.iocoder.yudao.adminserver.modules.system.service.sms.impl.SysSmsTemplateServiceImpl;
import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
import cn.iocoder.yudao.coreservice.modules.system.service.sms.impl.SysSmsCoreServiceImpl;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.sms.config.YudaoSmsAutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;

import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.TimeUnit;

// TODO @芋艿：需要迁移
@Import({YudaoSmsAutoConfiguration.class,
        SysSmsChannelServiceImpl.class, SysSmsCoreServiceImpl.class, SysSmsTemplateServiceImpl.class, SysSmsLogServiceImpl.class,
        SysSmsProducer.class, SysSmsSendConsumer.class})
public class SysSmsServiceIntegrationTest extends BaseDbAndRedisIntegrationTest {

    @Resource
    private SysSmsCoreServiceImpl smsService;
    @Resource
    private SysSmsChannelServiceImpl smsChannelService;

    @MockBean
    private SysUserService userService;

    @Test
    public void testSendSingleSms_yunpianSuccess() {
        // 参数准备
        String mobile = "15601691399";
        Long userId = 1L;
        Integer userType = UserTypeEnum.ADMIN.getValue();
        String templateCode = "test_01";
        Map<String, Object> templateParams = MapUtil.<String, Object>builder()
                .put("operation", "登录").put("code", "1234").build();
        // 调用
        smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);

        // 等待 MQ 消费
        ThreadUtil.sleep(1, TimeUnit.HOURS);
    }

    @Test
    public void testSendSingleSms_aliyunSuccess() {
        // 参数准备
        String mobile = "15601691399";
        Long userId = 1L;
        Integer userType = UserTypeEnum.ADMIN.getValue();
        String templateCode = "test_02";
        Map<String, Object> templateParams = MapUtil.<String, Object>builder()
                .put("code", "1234").build();
        // 调用
        smsService.sendSingleSms(mobile, userId, userType, templateCode, templateParams);

        // 等待 MQ 消费
        ThreadUtil.sleep(1, TimeUnit.HOURS);
    }

//    @Test
//    public void testDoSendSms() {
//        // 等待 MQ 消费
//        ThreadUtil.sleep(1, TimeUnit.HOURS);
//    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-count-to/props.js<|end_filename|>
export default {
    props: {
        // 开始的数值，默认从0增长到某一个数
        startVal: {
            type: [String, Number],
            default: uni.$u.props.countTo.startVal
        },
        // 要滚动的目标数值，必须
        endVal: {
            type: [String, Number],
            default: uni.$u.props.countTo.endVal
        },
        // 滚动到目标数值的动画持续时间，单位为毫秒（ms）
        duration: {
            type: [String, Number],
            default: uni.$u.props.countTo.duration
        },
        // 设置数值后是否自动开始滚动
        autoplay: {
            type: Boolean,
            default: uni.$u.props.countTo.autoplay
        },
        // 要显示的小数位数
        decimals: {
            type: [String, Number],
            default: uni.$u.props.countTo.decimals
        },
        // 是否在即将到达目标数值的时候，使用缓慢滚动的效果
        useEasing: {
            type: Boolean,
            default: uni.$u.props.countTo.useEasing
        },
        // 十进制分割
        decimal: {
            type: [String, Number],
            default: uni.$u.props.countTo.decimal
        },
        // 字体颜色
        color: {
            type: String,
            default: uni.$u.props.countTo.color
        },
        // 字体大小
        fontSize: {
            type: [String, Number],
            default: uni.$u.props.countTo.fontSize
        },
        // 是否加粗字体
        bold: {
            type: Boolean,
            default: uni.$u.props.countTo.bold
        },
        // 千位分隔符，类似金额的分割(￥23,321.05中的",")
        separator: {
            type: String,
            default: uni.$u.props.countTo.separator
        }
    }
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/logger/impl/SysLoginLogCoreServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.logger.impl;

import cn.iocoder.yudao.coreservice.modules.system.convert.logger.SysLoginLogCoreConvert;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger.SysLoginLogDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.logger.SysLoginLogCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService;
import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 登录日志 Service Core 实现
 *
 * @author 芋道源码
 */
@Service
public class SysLoginLogCoreServiceImpl implements SysLoginLogCoreService {

    @Resource
    private SysLoginLogCoreMapper loginLogMapper;

    @Override
    public void createLoginLog(SysLoginLogCreateReqDTO reqDTO) {
        SysLoginLogDO loginLog = SysLoginLogCoreConvert.INSTANCE.convert(reqDTO);
        // 插入
        loginLogMapper.insert(loginLog);
    }

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/framework/file/config/FileProperties.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.infra.framework.file.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotNull;

@ConfigurationProperties(prefix = "yudao.file")
@Validated
@Data
public class FileProperties {

    /**
     * 对应 InfFileController 的 getFile 方法
     */
    @NotNull(message = "基础文件路径不能为空")
    private String basePath;

    // TODO 七牛、等等

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/service/test/ToolTestDemoService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.service.test;

import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.adminserver.modules.tool.controller.test.vo.*;
import cn.iocoder.yudao.adminserver.modules.tool.dal.dataobject.test.ToolTestDemoDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

/**
 * 字典类型 Service 接口
 *
 * @author 芋艿
 */
public interface ToolTestDemoService {

    /**
     * 创建字典类型
     *
     * @param createReqVO 创建信息
     * @return 编号
     */
    Long createTestDemo(@Valid ToolTestDemoCreateReqVO createReqVO);

    /**
     * 更新字典类型
     *
     * @param updateReqVO 更新信息
     */
    void updateTestDemo(@Valid ToolTestDemoUpdateReqVO updateReqVO);

    /**
     * 删除字典类型
     *
     * @param id 编号
     */
    void deleteTestDemo(Long id);

    /**
     * 获得字典类型
     *
     * @param id 编号
     * @return 字典类型
     */
    ToolTestDemoDO getTestDemo(Long id);

    /**
     * 获得字典类型列表
     *
     * @param ids 编号
     * @return 字典类型列表
     */
    List<ToolTestDemoDO> getTestDemoList(Collection<Long> ids);

    /**
     * 获得字典类型分页
     *
     * @param pageReqVO 分页查询
     * @return 字典类型分页
     */
    PageResult<ToolTestDemoDO> getTestDemoPage(ToolTestDemoPageReqVO pageReqVO);

    /**
     * 获得字典类型列表, 用于 Excel 导出
     *
     * @param exportReqVO 查询条件
     * @return 字典类型列表
     */
    List<ToolTestDemoDO> getTestDemoList(ToolTestDemoExportReqVO exportReqVO);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/framework/package-info.java<|end_filename|>
/**
 * 属于 infra 模块的 framework 封装
 *
 * @author 芋道源码
 */
package cn.iocoder.yudao.adminserver.modules.infra.framework;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysDictTypeConstants.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.enums;

/**
 * System 字典类型的枚举类
 *
 * @author 芋道源码
 */
public interface SysDictTypeConstants {

    String USER_TYPE = "user_type"; // 用户类型
    String COMMON_STATUS = "sys_common_status"; // 系统状态

    String USER_SEX = "sys_user_sex"; // 用户性别
    String OPERATE_TYPE = "sys_operate_type"; // 操作类型
    String LOGIN_TYPE = "sys_login_type"; // 登录日志的类型
    String LOGIN_RESULT = "sys_login_result"; // 登录结果
    String CONFIG_TYPE = "sys_config_type"; // 参数配置类型
    String BOOLEAN_STRING = "sys_boolean_string"; // Boolean 是否类型

    String SMS_CHANNEL_CODE = "sys_sms_channel_code"; // 短信渠道编码
    String SMS_TEMPLATE_TYPE = "sys_sms_template_type"; // 短信模板类型
    String SMS_SEND_STATUS = "sys_sms_send_status"; // 短信发送状态
    String SMS_RECEIVE_STATUS = "sys_sms_receive_status"; // 短信接收状态

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-parse/parser.js<|end_filename|>
'use strict'

/**
 * @fileoverview html 解析器
 */
// 配置
const config = {
    // 信任的标签（保持标签名不变）
    trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,ruby,rt,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'),
    // 块级标签（转为 div，其他的非信任标签转为 span）
    blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section'),
    // 要移除的标签
    ignoreTags: makeMap('area,base,canvas,embed,frame,head,iframe,input,link,map,meta,param,rp,script,source,style,textarea,title,track,wbr'),
    // 自闭合的标签
    voidTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
    // html 实体
    entities: {
        lt: '<',
        gt: '>',
        quot: '"',
        apos: "'",
        ensp: '\u2002',
        emsp: '\u2003',
        nbsp: '\xA0',
        semi: ';',
        ndash: '–',
        mdash: '—',
        middot: '·',
        lsquo: '‘',
        rsquo: '’',
        ldquo: '“',
        rdquo: '”',
        bull: '•',
        hellip: '…'
    },
    // 默认的标签样式
    tagStyle: {
    // #ifndef APP-PLUS-NVUE
        address: 'font-style:italic',
        big: 'display:inline;font-size:1.2em',
        caption: 'display:table-caption;text-align:center',
        center: 'text-align:center',
        cite: 'font-style:italic',
        dd: 'margin-left:40px',
        mark: 'background-color:yellow',
        pre: 'font-family:monospace;white-space:pre',
        s: 'text-decoration:line-through',
        small: 'display:inline;font-size:0.8em',
        u: 'text-decoration:underline' // #endif

    }
}
const { windowWidth } = uni.getSystemInfoSync()
const blankChar = makeMap(' ,\r,\n,\t,\f')
let idIndex = 0 // #ifdef H5 || APP-PLUS

config.ignoreTags.iframe = void 0
config.trustTags.iframe = true
config.ignoreTags.embed = void 0
config.trustTags.embed = true // #endif
// #ifdef APP-PLUS-NVUE

config.ignoreTags.source = void 0
config.ignoreTags.style = void 0 // #endif

/**
 * @description 创建 map
 * @param {String} str 逗号分隔
 */

function makeMap(str) {
    const map = Object.create(null)
    const list = str.split(',')

    for (let i = list.length; i--;) {
        map[list[i]] = true
    }

    return map
}
/**
 * @description 解码 html 实体
 * @param {String} str 要解码的字符串
 * @param {Boolean} amp 要不要解码 &amp;
 * @returns {String} 解码后的字符串
 */

function decodeEntity(str, amp) {
    let i = str.indexOf('&')

    while (i != -1) {
        const j = str.indexOf(';', i + 3)
        let code = void 0
        if (j == -1) break

        if (str[i + 1] == '#') {
            // &#123; 形式的实体
            code = parseInt((str[i + 2] == 'x' ? '0' : '') + str.substring(i + 2, j))
            if (!isNaN(code)) str = str.substr(0, i) + String.fromCharCode(code) + str.substr(j + 1)
        } else {
            // &nbsp; 形式的实体
            code = str.substring(i + 1, j)
            if (config.entities[code] || code == 'amp' && amp) str = str.substr(0, i) + (config.entities[code] || '&') + str.substr(j + 1)
        }

        i = str.indexOf('&', i + 1)
    }

    return str
}
/**
 * @description html 解析器
 * @param {Object} vm 组件实例
 */

function parser(vm) {
    this.options = vm || {}
    this.tagStyle = Object.assign(config.tagStyle, this.options.tagStyle)
    this.imgList = vm.imgList || []
    this.plugins = vm.plugins || []
    this.attrs = Object.create(null)
    this.stack = []
    this.nodes = []
}
/**
 * @description 执行解析
 * @param {String} content 要解析的文本
 */

parser.prototype.parse = function (content) {
    // 插件处理
    for (let i = this.plugins.length; i--;) {
        if (this.plugins[i].onUpdate) content = this.plugins[i].onUpdate(content, config) || content
    }

    new lexer(this).parse(content) // 出栈未闭合的标签

    while (this.stack.length) {
        this.popNode()
    }

    return this.nodes
}
/**
 * @description 将标签暴露出来（不被 rich-text 包含）
 */

parser.prototype.expose = function () {
    // #ifndef APP-PLUS-NVUE
    for (let i = this.stack.length; i--;) {
        const item = this.stack[i]
        if (item.name == 'a' || item.c) return
        item.c = 1
    } // #endif
}
/**
 * @description 处理插件
 * @param {Object} node 要处理的标签
 * @returns {Boolean} 是否要移除此标签
 */

parser.prototype.hook = function (node) {
    for (let i = this.plugins.length; i--;) {
        if (this.plugins[i].onParse && this.plugins[i].onParse(node, this) == false) return false
    }

    return true
}
/**
 * @description 将链接拼接上主域名
 * @param {String} url 需要拼接的链接
 * @returns {String} 拼接后的链接
 */

parser.prototype.getUrl = function (url) {
    const { domain } = this.options

    if (url[0] == '/') {
    // // 开头的补充协议名
        if (url[1] == '/') url = `${domain ? domain.split('://')[0] : 'http'}:${url}` // 否则补充整个域名
        else if (domain) url = domain + url
    } else if (domain && !url.includes('data:') && !url.includes('://')) url = `${domain}/${url}`

    return url
}
/**
 * @description 解析样式表
 * @param {Object} node 标签
 * @returns {Object}
 */

parser.prototype.parseStyle = function (node) {
    const { attrs } = node
    const list = (this.tagStyle[node.name] || '').split(';').concat((attrs.style || '').split(';'))
    const styleObj = {}
    let tmp = ''

    if (attrs.id) {
    // 暴露锚点
        if (this.options.useAnchor) this.expose(); else if (node.name != 'img' && node.name != 'a' && node.name != 'video' && node.name != 'audio') attrs.id = void 0
    } // 转换 width 和 height 属性

    if (attrs.width) {
        styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px')
        attrs.width = void 0
    }

    if (attrs.height) {
        styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px')
        attrs.height = void 0
    }

    for (let i = 0, len = list.length; i < len; i++) {
        const info = list[i].split(':')
        if (info.length < 2) continue
        const key = info.shift().trim().toLowerCase()
        let value = info.join(':').trim() // 兼容性的 css 不压缩

        if (value[0] == '-' && value.lastIndexOf('-') > 0 || value.includes('safe')) tmp += ';'.concat(key, ':').concat(value) // 重复的样式进行覆盖
        else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import')) {
        // 填充链接
            if (value.includes('url')) {
                let j = value.indexOf('(') + 1

                if (j) {
                    while (value[j] == '"' || value[j] == "'" || blankChar[value[j]]) {
                        j++
                    }

                    value = value.substr(0, j) + this.getUrl(value.substr(j))
                }
            } // 转换 rpx（rich-text 内部不支持 rpx）
            else if (value.includes('rpx')) {
                value = value.replace(/[0-9.]+\s*rpx/g, ($) => `${parseFloat($) * windowWidth / 750}px`)
            }

            styleObj[key] = value
        }
    }

    node.attrs.style = tmp
    return styleObj
}
/**
 * @description 解析到标签名
 * @param {String} name 标签名
 * @private
 */

parser.prototype.onTagName = function (name) {
    this.tagName = this.xml ? name : name.toLowerCase()
    if (this.tagName == 'svg') this.xml = true // svg 标签内大小写敏感
}
/**
 * @description 解析到属性名
 * @param {String} name 属性名
 * @private
 */

parser.prototype.onAttrName = function (name) {
    name = this.xml ? name : name.toLowerCase()

    if (name.substr(0, 5) == 'data-') {
    // data-src 自动转为 src
        if (name == 'data-src' && !this.attrs.src) this.attrName = 'src' // a 和 img 标签保留 data- 的属性，可以在 imgtap 和 linktap 事件中使用
        else if (this.tagName == 'img' || this.tagName == 'a') this.attrName = name // 剩余的移除以减小大小
        else this.attrName = void 0
    } else {
        this.attrName = name
        this.attrs[name] = 'T' // boolean 型属性缺省设置
    }
}
/**
 * @description 解析到属性值
 * @param {String} val 属性值
 * @private
 */

parser.prototype.onAttrVal = function (val) {
    const name = this.attrName || '' // 部分属性进行实体解码

    if (name == 'style' || name == 'href') this.attrs[name] = decodeEntity(val, true) // 拼接主域名
    else if (name.includes('src')) this.attrs[name] = this.getUrl(decodeEntity(val, true)); else if (name) this.attrs[name] = val
}
/**
 * @description 解析到标签开始
 * @param {Boolean} selfClose 是否有自闭合标识 />
 * @private
 */

parser.prototype.onOpenTag = function (selfClose) {
    // 拼装 node
    const node = Object.create(null)
    node.name = this.tagName
    node.attrs = this.attrs
    this.attrs = Object.create(null)
    const { attrs } = node
    const parent = this.stack[this.stack.length - 1]
    const siblings = parent ? parent.children : this.nodes
    const close = this.xml ? selfClose : config.voidTags[node.name] // 转换 embed 标签

    if (node.name == 'embed') {
    // #ifndef H5 || APP-PLUS
        const src = attrs.src || '' // 按照后缀名和 type 将 embed 转为 video 或 audio

        if (src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8') || (attrs.type || '').includes('video')) node.name = 'video'; else if (src.includes('.mp3') || src.includes('.wav') || src.includes('.aac') || src.includes('.m4a') || (attrs.type || '').includes('audio')) node.name = 'audio'
        if (attrs.autostart) attrs.autoplay = 'T'
        attrs.controls = 'T' // #endif
        // #ifdef H5 || APP-PLUS

        this.expose() // #endif
    } // #ifndef APP-PLUS-NVUE
    // 处理音视频

    if (node.name == 'video' || node.name == 'audio') {
    // 设置 id 以便获取 context
        if (node.name == 'video' && !attrs.id) attrs.id = `v${idIndex++}` // 没有设置 controls 也没有设置 autoplay 的自动设置 controls

        if (!attrs.controls && !attrs.autoplay) attrs.controls = 'T' // 用数组存储所有可用的 source

        node.src = []

        if (attrs.src) {
            node.src.push(attrs.src)
            attrs.src = void 0
        }

        this.expose()
    } // #endif
    // 处理自闭合标签

    if (close) {
        if (!this.hook(node) || config.ignoreTags[node.name]) {
            // 通过 base 标签设置主域名
            if (node.name == 'base' && !this.options.domain) this.options.domain = attrs.href // #ifndef APP-PLUS-NVUE
            // 设置 source 标签（仅父节点为 video 或 audio 时有效）
            else if (node.name == 'source' && parent && (parent.name == 'video' || parent.name == 'audio') && attrs.src) parent.src.push(attrs.src) // #endif

            return
        } // 解析 style

        const styleObj = this.parseStyle(node) // 处理图片

        if (node.name == 'img') {
            if (attrs.src) {
                // 标记 webp
                if (attrs.src.includes('webp')) node.webp = 'T' // data url 图片如果没有设置 original-src 默认为不可预览的小图片

                if (attrs.src.includes('data:') && !attrs['original-src']) attrs.ignore = 'T'

                if (!attrs.ignore || node.webp || attrs.src.includes('cloud://')) {
                    for (let i = this.stack.length; i--;) {
                        const item = this.stack[i]

                        if (item.name == 'a') {
                            node.a = item.attrs
                            break
                        } // #ifndef H5 || APP-PLUS

                        const style = item.attrs.style || ''

                        if (style.includes('flex:') && !style.includes('flex:0') && !style.includes('flex: 0') && (!styleObj.width || !styleObj.width.includes('%'))) {
                            styleObj.width = '100% !important'
                            styleObj.height = ''

                            for (let j = i + 1; j < this.stack.length; j++) {
                                this.stack[j].attrs.style = (this.stack[j].attrs.style || '').replace('inline-', '')
                            }
                        } else if (style.includes('flex') && styleObj.width == '100%') {
                            for (let _j = i + 1; _j < this.stack.length; _j++) {
                                const _style = this.stack[_j].attrs.style || ''

                                if (!_style.includes(';width') && !_style.includes(' width') && _style.indexOf('width') != 0) {
                                    styleObj.width = ''
                                    break
                                }
                            }
                        } else if (style.includes('inline-block')) {
                            if (styleObj.width && styleObj.width[styleObj.width.length - 1] == '%') {
                                item.attrs.style += `;max-width:${styleObj.width}`
                                styleObj.width = ''
                            } else item.attrs.style += ';max-width:100%'
                        } // #endif

                        item.c = 1
                    }

                    attrs.i = this.imgList.length.toString()

                    let _src = attrs['original-src'] || attrs.src // #ifndef H5 || MP-ALIPAY || APP-PLUS || MP-360

                    if (this.imgList.includes(_src)) {
                        // 如果有重复的链接则对域名进行随机大小写变换避免预览时错位
                        let _i = _src.indexOf('://')

                        if (_i != -1) {
                            _i += 3

                            let newSrc = _src.substr(0, _i)

                            for (; _i < _src.length; _i++) {
                                if (_src[_i] == '/') break
                                newSrc += Math.random() > 0.5 ? _src[_i].toUpperCase() : _src[_i]
                            }

                            newSrc += _src.substr(_i)
                            _src = newSrc
                        }
                    } // #endif

                    this.imgList.push(_src) // #ifdef H5 || APP-PLUS

                    if (this.options.lazyLoad) {
                        attrs['data-src'] = attrs.src
                        attrs.src = void 0
                    } // #endif
                }
            }

            if (styleObj.display == 'inline') styleObj.display = '' // #ifndef APP-PLUS-NVUE

            if (attrs.ignore) {
                styleObj['max-width'] = styleObj['max-width'] || '100%'
                attrs.style += ';-webkit-touch-callout:none'
            } // #endif
            // 设置的宽度超出屏幕，为避免变形，高度转为自动

            if (parseInt(styleObj.width) > windowWidth) styleObj.height = void 0 // 记录是否设置了宽高

            if (styleObj.width) {
                if (styleObj.width.includes('auto')) styleObj.width = ''; else {
                    node.w = 'T'
                    if (styleObj.height && !styleObj.height.includes('auto')) node.h = 'T'
                }
            }
        } else if (node.name == 'svg') {
            siblings.push(node)
            this.stack.push(node)
            this.popNode()
            return
        }

        for (const key in styleObj) {
            if (styleObj[key]) attrs.style += ';'.concat(key, ':').concat(styleObj[key].replace(' !important', ''))
        }

        attrs.style = attrs.style.substr(1) || void 0
    } else {
        if (node.name == 'pre' || (attrs.style || '').includes('white-space') && attrs.style.includes('pre')) this.pre = node.pre = true
        node.children = []
        this.stack.push(node)
    } // 加入节点树

    siblings.push(node)
}
/**
 * @description 解析到标签结束
 * @param {String} name 标签名
 * @private
 */

parser.prototype.onCloseTag = function (name) {
    // 依次出栈到匹配为止
    name = this.xml ? name : name.toLowerCase()
    let i

    for (i = this.stack.length; i--;) {
        if (this.stack[i].name == name) break
    }

    if (i != -1) {
        while (this.stack.length > i) {
            this.popNode()
        }
    } else if (name == 'p' || name == 'br') {
        const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
        siblings.push({
            name,
            attrs: {}
        })
    }
}
/**
 * @description 处理标签出栈
 * @private
 */

parser.prototype.popNode = function () {
    const node = this.stack.pop()
    let { attrs } = node
    const { children } = node
    const parent = this.stack[this.stack.length - 1]
    const siblings = parent ? parent.children : this.nodes

    if (!this.hook(node) || config.ignoreTags[node.name]) {
    // 获取标题
        if (node.name == 'title' && children.length && children[0].type == 'text' && this.options.setTitle) {
            uni.setNavigationBarTitle({
                title: children[0].text
            })
        }
        siblings.pop()
        return
    }

    if (node.pre) {
    // 是否合并空白符标识
        node.pre = this.pre = void 0

        for (let i = this.stack.length; i--;) {
            if (this.stack[i].pre) this.pre = true
        }
    }

    const styleObj = {} // 转换 svg

    if (node.name == 'svg') {
    // #ifndef APP-PLUS-NVUE
        let src = ''
        const { style } = attrs
        attrs.style = ''
        attrs.xmlns = 'http://www.w3.org/2000/svg';

        (function traversal(node) {
            src += `<${node.name}`

            for (let item in node.attrs) {
                const val = node.attrs[item]

                if (val) {
                    if (item == 'viewbox') item = 'viewBox'
                    src += ' '.concat(item, '="').concat(val, '"')
                }
            }

            if (!node.children) src += '/>'; else {
                src += '>'

                for (let _i2 = 0; _i2 < node.children.length; _i2++) {
                    traversal(node.children[_i2])
                }

                src += `</${node.name}>`
            }
        }(node))

        node.name = 'img'
        node.attrs = {
            src: `data:image/svg+xml;utf8,${src.replace(/#/g, '%23')}`,
            style,
            ignore: 'T'
        }
        node.children = void 0 // #endif

        this.xml = false
        return
    } // #ifndef APP-PLUS-NVUE
    // 转换 align 属性

    if (attrs.align) {
        if (node.name == 'table') {
            if (attrs.align == 'center') styleObj['margin-inline-start'] = styleObj['margin-inline-end'] = 'auto'; else styleObj.float = attrs.align
        } else styleObj['text-align'] = attrs.align

        attrs.align = void 0
    } // 转换 font 标签的属性

    if (node.name == 'font') {
        if (attrs.color) {
            styleObj.color = attrs.color
            attrs.color = void 0
        }

        if (attrs.face) {
            styleObj['font-family'] = attrs.face
            attrs.face = void 0
        }

        if (attrs.size) {
            let size = parseInt(attrs.size)

            if (!isNaN(size)) {
                if (size < 1) size = 1; else if (size > 7) size = 7
                styleObj['font-size'] = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'][size - 1]
            }

            attrs.size = void 0
        }
    } // #endif
    // 一些编辑器的自带 class

    if ((attrs.class || '').includes('align-center')) styleObj['text-align'] = 'center'
    Object.assign(styleObj, this.parseStyle(node))

    if (parseInt(styleObj.width) > windowWidth) {
        styleObj['max-width'] = '100%'
        styleObj['box-sizing'] = 'border-box'
    } // #ifndef APP-PLUS-NVUE

    if (config.blockTags[node.name]) node.name = 'div' // 未知标签转为 span，避免无法显示
    else if (!config.trustTags[node.name] && !this.xml) node.name = 'span'
    if (node.name == 'a' || node.name == 'ad' // #ifdef H5 || APP-PLUS
  || node.name == 'iframe' // #endif
    ) this.expose() // #ifdef APP-PLUS
    else if (node.name == 'video') {
        let str = '<video style="width:100%;height:100%"' // 空白图占位

        if (!attrs.poster && !attrs.autoplay) attrs.poster = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg'/>"

        for (const item in attrs) {
            if (attrs[item]) str += ` ${item}="${attrs[item]}"`
        }

        if (this.options.pauseVideo) str += ' onplay="for(var e=document.getElementsByTagName(\'video\'),t=0;t<e.length;t++)e[t]!=this&&e[t].pause()"'
        str += '>'

        for (let _i3 = 0; _i3 < node.src.length; _i3++) {
            str += `<source src="${node.src[_i3]}">`
        }

        str += '</video>'
        node.html = str
    } // #endif
    // 列表处理
    else if ((node.name == 'ul' || node.name == 'ol') && node.c) {
        const types = {
            a: 'lower-alpha',
            A: 'upper-alpha',
            i: 'lower-roman',
            I: 'upper-roman'
        }

        if (types[attrs.type]) {
            attrs.style += `;list-style-type:${types[attrs.type]}`
            attrs.type = void 0
        }

        for (let _i4 = children.length; _i4--;) {
            if (children[_i4].name == 'li') children[_i4].c = 1
        }
    } // 表格处理
    else if (node.name == 'table') {
        // cellpadding、cellspacing、border 这几个常用表格属性需要通过转换实现
        let padding = parseFloat(attrs.cellpadding)
        let spacing = parseFloat(attrs.cellspacing)
        const border = parseFloat(attrs.border)

        if (node.c) {
            // padding 和 spacing 默认 2
            if (isNaN(padding)) padding = 2
            if (isNaN(spacing)) spacing = 2
        }

        if (border) attrs.style += `;border:${border}px solid gray`

        if (node.flag && node.c) {
            // 有 colspan 或 rowspan 且含有链接的表格通过 grid 布局实现
            styleObj.display = 'grid'

            if (spacing) {
                styleObj['grid-gap'] = `${spacing}px`
                styleObj.padding = `${spacing}px`
            } // 无间隔的情况下避免边框重叠
            else if (border) attrs.style += ';border-left:0;border-top:0'

            const width = []
            // 表格的列宽
            const trList = []
            // tr 列表
            const cells = []
            // 保存新的单元格
            const map = {}; // 被合并单元格占用的格子

            (function traversal(nodes) {
                for (let _i5 = 0; _i5 < nodes.length; _i5++) {
                    if (nodes[_i5].name == 'tr') trList.push(nodes[_i5]); else traversal(nodes[_i5].children || [])
                }
            }(children))

            for (let row = 1; row <= trList.length; row++) {
                let col = 1

                for (let j = 0; j < trList[row - 1].children.length; j++, col++) {
                    const td = trList[row - 1].children[j]

                    if (td.name == 'td' || td.name == 'th') {
                        // 这个格子被上面的单元格占用，则列号++
                        while (map[`${row}.${col}`]) {
                            col++
                        }

                        let _style2 = td.attrs.style || ''
                        const start = _style2.indexOf('width') ? _style2.indexOf(';width') : 0 // 提取出 td 的宽度

                        if (start != -1) {
                            let end = _style2.indexOf(';', start + 6)

                            if (end == -1) end = _style2.length
                            if (!td.attrs.colspan) width[col] = _style2.substring(start ? start + 7 : 6, end)
                            _style2 = _style2.substr(0, start) + _style2.substr(end)
                        }

                        _style2 += (border ? ';border:'.concat(border, 'px solid gray') + (spacing ? '' : ';border-right:0;border-bottom:0') : '') + (padding ? ';padding:'.concat(padding, 'px') : '') // 处理列合并

                        if (td.attrs.colspan) {
                            _style2 += ';grid-column-start:'.concat(col, ';grid-column-end:').concat(col + parseInt(td.attrs.colspan))
                            if (!td.attrs.rowspan) _style2 += ';grid-row-start:'.concat(row, ';grid-row-end:').concat(row + 1)
                            col += parseInt(td.attrs.colspan) - 1
                        } // 处理行合并

                        if (td.attrs.rowspan) {
                            _style2 += ';grid-row-start:'.concat(row, ';grid-row-end:').concat(row + parseInt(td.attrs.rowspan))
                            if (!td.attrs.colspan) _style2 += ';grid-column-start:'.concat(col, ';grid-column-end:').concat(col + 1) // 记录下方单元格被占用

                            for (let k = 1; k < td.attrs.rowspan; k++) {
                                map[`${row + k}.${col}`] = 1
                            }
                        }

                        if (_style2) td.attrs.style = _style2
                        cells.push(td)
                    }
                }

                if (row == 1) {
                    let temp = ''

                    for (let _i6 = 1; _i6 < col; _i6++) {
                        temp += `${width[_i6] ? width[_i6] : 'auto'} `
                    }

                    styleObj['grid-template-columns'] = temp
                }
            }

            node.children = cells
        } else {
            // 没有使用合并单元格的表格通过 table 布局实现
            if (node.c) styleObj.display = 'table'
            if (!isNaN(spacing)) styleObj['border-spacing'] = `${spacing}px`

            if (border || padding) {
                // 遍历
                (function traversal(nodes) {
                    for (let _i7 = 0; _i7 < nodes.length; _i7++) {
                        const _td = nodes[_i7]

                        if (_td.name == 'th' || _td.name == 'td') {
                            if (border) _td.attrs.style = 'border:'.concat(border, 'px solid gray;').concat(_td.attrs.style || '')
                            if (padding) _td.attrs.style = 'padding:'.concat(padding, 'px;').concat(_td.attrs.style || '')
                        } else if (_td.children) traversal(_td.children)
                    }
                }(children))
            }
        } // 给表格添加一个单独的横向滚动层

        if (this.options.scrollTable && !(attrs.style || '').includes('inline')) {
            const table = { ...node }
            node.name = 'div'
            node.attrs = {
                style: 'overflow:auto'
            }
            node.children = [table]
            attrs = table.attrs
        }
    } else if ((node.name == 'td' || node.name == 'th') && (attrs.colspan || attrs.rowspan)) {
        for (let _i8 = this.stack.length; _i8--;) {
            if (this.stack[_i8].name == 'table') {
                this.stack[_i8].flag = 1 // 指示含有合并单元格

                break
            }
        }
    } // 转换 ruby
    else if (node.name == 'ruby') {
        node.name = 'span'

        for (let _i9 = 0; _i9 < children.length - 1; _i9++) {
            if (children[_i9].type == 'text' && children[_i9 + 1].name == 'rt') {
                children[_i9] = {
                    name: 'div',
                    attrs: {
                        style: 'display:inline-block'
                    },
                    children: [{
                        name: 'div',
                        attrs: {
                            style: 'font-size:50%;text-align:start'
                        },
                        children: children[_i9 + 1].children
                    }, children[_i9]]
                }
                children.splice(_i9 + 1, 1)
            }
        }
    } else if (node.c) {
        node.c = 2

        for (let _i10 = node.children.length; _i10--;) {
            if (!node.children[_i10].c || node.children[_i10].name == 'table') node.c = 1
        }
    }
    if ((styleObj.display || '').includes('flex') && !node.c) {
        for (let _i11 = children.length; _i11--;) {
            const _item = children[_i11]

            if (_item.f) {
                _item.attrs.style = (_item.attrs.style || '') + _item.f
                _item.f = void 0
            }
        }
    } // flex 布局时部分样式需要提取到 rich-text 外层

    const flex = parent && (parent.attrs.style || '').includes('flex') // #ifdef MP-WEIXIN
  // 检查基础库版本 virtualHost 是否可用
  && !(node.c && wx.getNFCAdapter) // #endif
  // #ifndef MP-WEIXIN || MP-QQ || MP-BAIDU || MP-TOUTIAO
  && !node.c // #endif

    if (flex) node.f = ';max-width:100%' // #endif

    for (const key in styleObj) {
        if (styleObj[key]) {
            const val = ';'.concat(key, ':').concat(styleObj[key].replace(' !important', '')) // #ifndef APP-PLUS-NVUE

            if (flex && (key.includes('flex') && key != 'flex-direction' || key == 'align-self' || styleObj[key][0] == '-' || key == 'width' && val.includes('%'))) {
                node.f += val
                if (key == 'width') attrs.style += ';width:100%'
            } else // #endif
            { attrs.style += val }
        }
    }

    attrs.style = attrs.style.substr(1) || void 0
}
/**
 * @description 解析到文本
 * @param {String} text 文本内容
 */

parser.prototype.onText = function (text) {
    if (!this.pre) {
    // 合并空白符
        let trim = ''
        let flag

        for (let i = 0, len = text.length; i < len; i++) {
            if (!blankChar[text[i]]) trim += text[i]; else {
                if (trim[trim.length - 1] != ' ') trim += ' '
                if (text[i] == '\n' && !flag) flag = true
            }
        } // 去除含有换行符的空串

        if (trim == ' ' && flag) return
        text = trim
    }

    const node = Object.create(null)
    node.type = 'text'
    node.text = decodeEntity(text)

    if (this.hook(node)) {
        const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
        siblings.push(node)
    }
}
/**
 * @description html 词法分析器
 * @param {Object} handler 高层处理器
 */

function lexer(handler) {
    this.handler = handler
}
/**
 * @description 执行解析
 * @param {String} content 要解析的文本
 */

lexer.prototype.parse = function (content) {
    this.content = content || ''
    this.i = 0 // 标记解析位置

    this.start = 0 // 标记一个单词的开始位置

    this.state = this.text // 当前状态

    for (let len = this.content.length; this.i != -1 && this.i < len;) {
        this.state()
    }
}
/**
 * @description 检查标签是否闭合
 * @param {String} method 如果闭合要进行的操作
 * @returns {Boolean} 是否闭合
 * @private
 */

lexer.prototype.checkClose = function (method) {
    const selfClose = this.content[this.i] == '/'

    if (this.content[this.i] == '>' || selfClose && this.content[this.i + 1] == '>') {
        if (method) this.handler[method](this.content.substring(this.start, this.i))
        this.i += selfClose ? 2 : 1
        this.start = this.i
        this.handler.onOpenTag(selfClose)

        if (this.handler.tagName == 'script') {
            this.i = this.content.indexOf('</', this.i)

            if (this.i != -1) {
                this.i += 2
                this.start = this.i
            }

            this.state = this.endTag
        } else this.state = this.text

        return true
    }

    return false
}
/**
 * @description 文本状态
 * @private
 */

lexer.prototype.text = function () {
    this.i = this.content.indexOf('<', this.i) // 查找最近的标签

    if (this.i == -1) {
    // 没有标签了
        if (this.start < this.content.length) this.handler.onText(this.content.substring(this.start, this.content.length))
        return
    }

    const c = this.content[this.i + 1]

    if (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z') {
    // 标签开头
        if (this.start != this.i) this.handler.onText(this.content.substring(this.start, this.i))
        this.start = ++this.i
        this.state = this.tagName
    } else if (c == '/' || c == '!' || c == '?') {
        if (this.start != this.i) this.handler.onText(this.content.substring(this.start, this.i))
        const next = this.content[this.i + 2]

        if (c == '/' && (next >= 'a' && next <= 'z' || next >= 'A' && next <= 'Z')) {
            // 标签结尾
            this.i += 2
            this.start = this.i
            return this.state = this.endTag
        } // 处理注释

        let end = '-->'
        if (c != '!' || this.content[this.i + 2] != '-' || this.content[this.i + 3] != '-') end = '>'
        this.i = this.content.indexOf(end, this.i)

        if (this.i != -1) {
            this.i += end.length
            this.start = this.i
        }
    } else this.i++
}
/**
 * @description 标签名状态
 * @private
 */

lexer.prototype.tagName = function () {
    if (blankChar[this.content[this.i]]) {
    // 解析到标签名
        this.handler.onTagName(this.content.substring(this.start, this.i))

        while (blankChar[this.content[++this.i]]) {

        }

        if (this.i < this.content.length && !this.checkClose()) {
            this.start = this.i
            this.state = this.attrName
        }
    } else if (!this.checkClose('onTagName')) this.i++
}
/**
 * @description 属性名状态
 * @private
 */

lexer.prototype.attrName = function () {
    let c = this.content[this.i]

    if (blankChar[c] || c == '=') {
    // 解析到属性名
        this.handler.onAttrName(this.content.substring(this.start, this.i))
        let needVal = c == '='
        const len = this.content.length

        while (++this.i < len) {
            c = this.content[this.i]

            if (!blankChar[c]) {
                if (this.checkClose()) return

                if (needVal) {
                    // 等号后遇到第一个非空字符
                    this.start = this.i
                    return this.state = this.attrVal
                }

                if (this.content[this.i] == '=') needVal = true; else {
                    this.start = this.i
                    return this.state = this.attrName
                }
            }
        }
    } else if (!this.checkClose('onAttrName')) this.i++
}
/**
 * @description 属性值状态
 * @private
 */

lexer.prototype.attrVal = function () {
    const c = this.content[this.i]
    const len = this.content.length // 有冒号的属性

    if (c == '"' || c == "'") {
        this.start = ++this.i
        this.i = this.content.indexOf(c, this.i)
        if (this.i == -1) return
        this.handler.onAttrVal(this.content.substring(this.start, this.i))
    } // 没有冒号的属性
    else {
        for (; this.i < len; this.i++) {
            if (blankChar[this.content[this.i]]) {
                this.handler.onAttrVal(this.content.substring(this.start, this.i))
                break
            } else if (this.checkClose('onAttrVal')) return
        }
    }

    while (blankChar[this.content[++this.i]]) {

    }

    if (this.i < len && !this.checkClose()) {
        this.start = this.i
        this.state = this.attrName
    }
}
/**
 * @description 结束标签状态
 * @returns {String} 结束的标签名
 * @private
 */

lexer.prototype.endTag = function () {
    const c = this.content[this.i]

    if (blankChar[c] || c == '>' || c == '/') {
        this.handler.onCloseTag(this.content.substring(this.start, this.i))

        if (c != '>') {
            this.i = this.content.indexOf('>', this.i)
            if (this.i == -1) return
        }

        this.start = ++this.i
        this.state = this.text
    } else this.i++
}

module.exports = parser


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/InfFileService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.service.file;

import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

/**
 * 文件 Service 接口
 *
 * @author 芋道源码
 */
public interface InfFileService {

    /**
     * 获得文件分页
     *
     * @param pageReqVO 分页查询
     * @return 文件分页
     */
    PageResult<InfFileDO> getFilePage(InfFilePageReqVO pageReqVO);

}


<|start_filename|>yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/servlet/ServletUtils.java<|end_filename|>
package cn.iocoder.yudao.framework.common.util.servlet;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;

/**
 * 客户端工具类
 *
 * @author 芋道源码
 */
public class ServletUtils {

    /**
     * 返回 JSON 字符串
     *
     * @param response 响应
     * @param object 对象，会序列化成 JSON 字符串
     */
    @SuppressWarnings("deprecation") // 必须使用 APPLICATION_JSON_UTF8_VALUE，否则会乱码
    public static void writeJSON(HttpServletResponse response, Object object) {
        String content = JsonUtils.toJsonString(object);
        ServletUtil.write(response, content, MediaType.APPLICATION_JSON_UTF8_VALUE);
    }

    /**
     * 返回附件
     *
     * @param response 响应
     * @param filename 文件名
     * @param content 附件内容
     * @throws IOException
     */
    public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
        // 设置 header 和 contentType
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        // 输出附件
        IoUtil.write(response.getOutputStream(), false, content);
    }

    /**
     * @param request 请求
     * @return ua
     */
    public static String getUserAgent(HttpServletRequest request) {
        String ua = request.getHeader("User-Agent");
        return ua != null ? ua : "";
    }

    /**
     * 获得请求
     *
     * @return HttpServletRequest
     */
    public static HttpServletRequest getRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (!(requestAttributes instanceof ServletRequestAttributes)) {
            return null;
        }
        return ((ServletRequestAttributes) requestAttributes).getRequest();
    }

    public static String getUserAgent() {
        HttpServletRequest request = getRequest();
        if (request == null) {
            return null;
        }
        return getUserAgent(request);
    }

    public static String getClientIP() {
        HttpServletRequest request = getRequest();
        if (request == null) {
            return null;
        }
        return ServletUtil.getClientIP(request);
    }

    public static boolean isJsonRequest(ServletRequest request) {
        return StrUtil.startWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE);
    }

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/logger/dto/SysLoginLogCreateReqDTO.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.logger.dto;

import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

/**
 * 登录日志创建 Request DTO
 *
 * @author 芋道源码
 */
@Data
public class SysLoginLogCreateReqDTO {

    /**
     * 日志类型
     */
    @NotNull(message = "日志类型不能为空")
    private Integer logType;
    /**
     * 链路追踪编号
     */
    @NotEmpty(message = "链路追踪编号不能为空")
    private String traceId;

    /**
     * 用户编号
     */
    private Long userId;
    /**
     * 用户类型
     */
    @NotNull(message = "用户类型不能为空")
    private Integer userType;
    /**
     * 用户账号
     */
    @NotBlank(message = "用户账号不能为空")
    @Size(max = 30, message = "用户账号长度不能超过30个字符")
    private String username;

    /**
     * 登录结果
     */
    @NotNull(message = "登录结果不能为空")
    private Integer result;

    /**
     * 用户 IP
     */
    @NotEmpty(message = "用户 IP 不能为空")
    private String userIp;
    /**
     * 浏览器 UserAgent
     */
    @NotEmpty(message = "浏览器 UserAgent 不能为空")
    private String userAgent;

}


<|start_filename|>yudao-admin-ui/src/api/infra/redis.js<|end_filename|>
import request from '@/utils/request'

// 查询缓存详细
export function getCache() {
  return request({
    url: '/infra/redis/get-monitor-info',
    method: 'get'
  })
}

// TODO
export function getKeyList() {
  return request({
    url: '/infra/redis/get-key-list',
    method: 'get'
  })
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/mysql/sms/SysSmsTemplateCoreMapper.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.Date;

@Mapper
public interface SysSmsTemplateCoreMapper extends BaseMapperX<SysSmsTemplateDO> {

    @Select("SELECT id FROM sys_sms_template WHERE update_time > #{maxUpdateTime} LIMIT 1")
    Long selectExistsByUpdateTimeAfter(Date maxUpdateTime);

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/skeleton.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:20:14
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/skeleton.js
 */
export default {
    // skeleton
    skeleton: {
        loading: true,
        animate: true,
        rows: 0,
        rowsWidth: '100%',
        rowsHeight: 18,
        title: true,
        titleWidth: '50%',
        titleHeight: 18,
        avatar: false,
        avatarSize: 32,
        avatarShape: 'circle'
    }
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-redis/src/main/java/cn/iocoder/yudao/framework/redis/core/RedisKeyRegistry.java<|end_filename|>
package cn.iocoder.yudao.framework.redis.core;

import java.util.ArrayList;
import java.util.List;

/**
 * {@link RedisKeyDefine} 注册表
 */
public class RedisKeyRegistry {

    /**
     * Redis RedisKeyDefine 数组
     */
    private static final List<RedisKeyDefine> defines = new ArrayList<>();

    public static void add(RedisKeyDefine define) {
        defines.add(define);
    }

    public static List<RedisKeyDefine> list() {
        return defines;
    }

    public static int size() {
        return defines.size();
    }

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/package-info.java<|end_filename|>
/**
 * system 包下，我们放通用业务，支撑上层的核心业务。
 * 例如说：用户、部门、权限、数据字典等等
 *
 * 缩写：sys
 */
package cn.iocoder.yudao.coreservice.modules.system;


<|start_filename|>yudao-admin-ui/src/layout/components/global.js<|end_filename|>
import Vue from 'vue'
const global = new Vue()
export default global


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/logger/SysLoginLogMapper.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.logger;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger.SysLoginLogDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogPageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginResultEnum;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface SysLoginLogMapper extends BaseMapperX<SysLoginLogDO> {

    default PageResult<SysLoginLogDO> selectPage(SysLoginLogPageReqVO reqVO) {
        QueryWrapperX<SysLoginLogDO> query = new QueryWrapperX<SysLoginLogDO>()
                .likeIfPresent("user_ip", reqVO.getUserIp())
                .likeIfPresent("username", reqVO.getUsername())
                .betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime());
        if (Boolean.TRUE.equals(reqVO.getStatus())) {
            query.eq("result", SysLoginResultEnum.SUCCESS.getResult());
        } else if (Boolean.FALSE.equals(reqVO.getStatus())) {
            query.gt("result", SysLoginResultEnum.SUCCESS.getResult());
        }
        query.orderByDesc("id"); // 降序
        return selectPage(reqVO, query);
    }

    default List<SysLoginLogDO> selectList(SysLoginLogExportReqVO reqVO) {
        QueryWrapperX<SysLoginLogDO> query = new QueryWrapperX<SysLoginLogDO>()
                .likeIfPresent("user_ip", reqVO.getUserIp())
                .likeIfPresent("username", reqVO.getUsername())
                .betweenIfPresent("create_time", reqVO.getBeginTime(), reqVO.getEndTime());
        if (Boolean.TRUE.equals(reqVO.getStatus())) {
            query.eq("result", SysLoginResultEnum.SUCCESS.getResult());
        } else if (Boolean.FALSE.equals(reqVO.getStatus())) {
            query.gt("result", SysLoginResultEnum.SUCCESS.getResult());
        }
        query.orderByDesc("id"); // 降序
        return selectList(query);
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/controller/test/ToolTestDemoController.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.controller.test;

import cn.hutool.core.thread.ThreadUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.tracer.core.annotation.BizTrace;
import cn.iocoder.yudao.adminserver.modules.tool.controller.test.vo.*;
import cn.iocoder.yudao.adminserver.modules.tool.convert.test.ToolTestDemoConvert;
import cn.iocoder.yudao.adminserver.modules.tool.dal.dataobject.test.ToolTestDemoDO;
import cn.iocoder.yudao.adminserver.modules.tool.service.test.ToolTestDemoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
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.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;

@Api(tags = "测试示例")
@RestController
@RequestMapping("/tool/test-demo")
@Validated
public class ToolTestDemoController {

    @Resource
    private ToolTestDemoService testDemoService;

    @PostMapping("/create")
    @ApiOperation("创建测试示例")
    @PreAuthorize("@ss.hasPermission('tool:test-demo:create')")
    public CommonResult<Long> createTestDemo(@Valid @RequestBody ToolTestDemoCreateReqVO createReqVO) {
        return success(testDemoService.createTestDemo(createReqVO));
    }

    @PutMapping("/update")
    @ApiOperation("更新测试示例")
    @PreAuthorize("@ss.hasPermission('tool:test-demo:update')")
    public CommonResult<Boolean> updateTestDemo(@Valid @RequestBody ToolTestDemoUpdateReqVO updateReqVO) {
        testDemoService.updateTestDemo(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @ApiOperation("删除测试示例")
    @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
    @PreAuthorize("@ss.hasPermission('tool:test-demo:delete')")
    public CommonResult<Boolean> deleteTestDemo(@RequestParam("id") Long id) {
        testDemoService.deleteTestDemo(id);
        return success(true);
    }

    @GetMapping("/get")
    @ApiOperation("获得测试示例")
    @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = Long.class)
    @PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
//    @Lock4j // 分布式锁
    public CommonResult<ToolTestDemoRespVO> getTestDemo(@RequestParam("id") Long id) {
        if (true) { // 测试分布式锁
            ThreadUtil.sleep(5, TimeUnit.SECONDS);
        }
        ToolTestDemoDO testDemo = testDemoService.getTestDemo(id);
        return success(ToolTestDemoConvert.INSTANCE.convert(testDemo));
    }

    @GetMapping("/list")
    @ApiOperation("获得测试示例列表")
    @ApiImplicitParam(name = "ids", value = "编号列表", required = true, dataTypeClass = List.class)
    @PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
//    @RateLimiter(name = "backendA")
    @BizTrace(id = "#ids", type = "'user'")
    public CommonResult<List<ToolTestDemoRespVO>> getTestDemoList(@RequestParam("ids") Collection<Long> ids) {
        List<ToolTestDemoDO> list = testDemoService.getTestDemoList(ids);
        return success(ToolTestDemoConvert.INSTANCE.convertList(list));
    }

    @GetMapping("/page")
    @ApiOperation("获得测试示例分页")
    @PreAuthorize("@ss.hasPermission('tool:test-demo:query')")
    public CommonResult<PageResult<ToolTestDemoRespVO>> getTestDemoPage(@Valid ToolTestDemoPageReqVO pageVO) {
        PageResult<ToolTestDemoDO> pageResult = testDemoService.getTestDemoPage(pageVO);
        return success(ToolTestDemoConvert.INSTANCE.convertPage(pageResult));
    }

    @GetMapping("/export-excel")
    @ApiOperation("导出测试示例 Excel")
    @PreAuthorize("@ss.hasPermission('tool:test-demo:export')")
    @OperateLog(type = EXPORT)
    public void exportTestDemoExcel(@Valid ToolTestDemoExportReqVO exportReqVO,
                                    HttpServletResponse response) throws IOException {
        List<ToolTestDemoDO> list = testDemoService.getTestDemoList(exportReqVO);
        // 导出 Excel
        List<ToolTestDemoExcelVO> datas = ToolTestDemoConvert.INSTANCE.convertList02(list);
        ExcelUtils.write(response, "测试示例.xls", "数据", ToolTestDemoExcelVO.class, datas);
    }

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/package-info.java<|end_filename|>
/**
 * 使用 SkyWalking 组件，作为链路追踪、日志中心。
 *
 * @author 芋道源码
 */
package cn.iocoder.yudao.framework.tracer;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/package-info.java<|end_filename|>
/**
 * tool 包下，我们放研发工具，提升研发效率与质量。
 * 例如说：代码生成器、接口文档等等
 *
 * 缩写：tool
 */
package cn.iocoder.yudao.adminserver.modules.tool;


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/dataobject/sms/SysSmsCodeDO.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.system.dal.dataobject.sms;

import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import lombok.experimental.Accessors;

import java.util.Date;

/**
 * 手机验证码 DO
 *
 * idx_mobile 索引：基于 {@link #mobile} 字段
 *
 * @author 芋道源码
 */
@TableName("sys_sms_code")
@Data
@EqualsAndHashCode(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SysSmsCodeDO extends BaseDO {

    /**
     * 编号
     */
    private Integer id;
    /**
     * 手机号
     */
    private String mobile;
    /**
     * 验证码
     */
    private String code;
    /**
     * 发送场景
     *
     * 枚举 {@link SysSmsCodeDO}
     */
    private Integer scene;
    /**
     * 创建 IP
     */
    private String createIp;
    /**
     * 今日发送的第几条
     */
    private Integer todayIndex;
    /**
     * 是否使用
     */
    private Boolean used;
    /**
     * 使用时间
     */
    private Date usedTime;
    /**
     * 使用 IP
     */
    private String usedIp;

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/convert/logger/SysLoginLogCoreConvert.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.convert.logger;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger.SysLoginLogDO;
import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface SysLoginLogCoreConvert {

    SysLoginLogCoreConvert INSTANCE = Mappers.getMapper(SysLoginLogCoreConvert.class);

    SysLoginLogDO convert(SysLoginLogCreateReqDTO bean);

}


<|start_filename|>yudao-admin-ui/src/components/bpmnProcessDesigner/package/penal/index.js<|end_filename|>
import MyPropertiesPanel from "./PropertiesPanel.vue";

MyPropertiesPanel.install = function(Vue) {
  Vue.component(MyPropertiesPanel.name, MyPropertiesPanel);
};

export default MyPropertiesPanel;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-read-more/props.js<|end_filename|>
export default {
    props: {
        // 默认的显示占位高度
        showHeight: {
            type: [String, Number],
            default: uni.$u.props.readMore.showHeight
        },
        // 展开后是否显示"收起"按钮
        toggle: {
            type: Boolean,
            default: uni.$u.props.readMore.toggle
        },
        // 关闭时的提示文字
        closeText: {
            type: String,
            default: uni.$u.props.readMore.closeText
        },
        // 展开时的提示文字
        openText: {
            type: String,
            default: uni.$u.props.readMore.openText
        },
        // 提示的文字颜色
        color: {
            type: String,
            default: uni.$u.props.readMore.color
        },
        // 提示文字的大小
        fontSize: {
            type: [String, Number],
            default: uni.$u.props.readMore.fontSize
        },
        // 是否显示阴影
        // 此参数不能写在props/readMore.js中进行默认配置，因为使用了条件编译，在外部js中
        // uni无法准确识别当前是否处于nvue还是非nvue下
        shadowStyle: {
            type: Object,
            default: () => ({
                // #ifndef APP-NVUE
                backgroundImage: 'linear-gradient(-180deg, rgba(255, 255, 255, 0) 0%, #fff 80%)',
                // #endif
                // #ifdef APP-NVUE
                // nvue上不支持设置复杂的backgroundImage属性
                backgroundImage: 'linear-gradient(to top, #fff, rgba(255, 255, 255, 0.5))',
                // #endif
                paddingTop: '100px',
                marginTop: '-100px'
            })
        },
        // 段落首行缩进的字符个数
        textIndent: {
            type: String,
            default: uni.$u.props.readMore.textIndent
        },
        // open和close事件时，将此参数返回在回调参数中
        name: {
            type: [String, Number],
            default: uni.$u.props.readMore.name
        }
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/dept/vo/post/SysPostCreateReqVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.post;

import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;

@ApiModel("岗位创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class SysPostCreateReqVO extends SysPostBaseVO {
}


<|start_filename|>yudao-admin-ui/src/api/system/errorCode.js<|end_filename|>
import request from '@/utils/request'

// 创建错误码
export function createErrorCode(data) {
  return request({
    url: '/system/error-code/create',
    method: 'post',
    data: data
  })
}

// 更新错误码
export function updateErrorCode(data) {
  return request({
    url: '/system/error-code/update',
    method: 'put',
    data: data
  })
}

// 删除错误码
export function deleteErrorCode(id) {
  return request({
    url: '/system/error-code/delete?id=' + id,
    method: 'delete'
  })
}

// 获得错误码
export function getErrorCode(id) {
  return request({
    url: '/system/error-code/get?id=' + id,
    method: 'get'
  })
}

// 获得错误码分页
export function getErrorCodePage(query) {
  return request({
    url: '/system/error-code/page',
    method: 'get',
    params: query
  })
}

// 导出错误码 Excel
export function exportErrorCodeExcel(query) {
  return request({
    url: '/system/error-code/export-excel',
    method: 'get',
    params: query,
    responseType: 'blob'
  })
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-image/props.js<|end_filename|>
export default {
    props: {
        // 图片地址
        src: {
            type: String,
            default: uni.$u.props.image.src
        },
        // 裁剪模式
        mode: {
            type: String,
            default: uni.$u.props.image.mode
        },
        // 宽度，单位任意
        width: {
            type: [String, Number],
            default: uni.$u.props.image.width
        },
        // 高度，单位任意
        height: {
            type: [String, Number],
            default: uni.$u.props.image.height
        },
        // 图片形状，circle-圆形，square-方形
        shape: {
            type: String,
            default: uni.$u.props.image.shape
        },
        // 圆角，单位任意
        radius: {
            type: [String, Number],
            default: uni.$u.props.image.radius
        },
        // 是否懒加载，微信小程序、App、百度小程序、字节跳动小程序
        lazyLoad: {
            type: Boolean,
            default: uni.$u.props.image.lazyLoad
        },
        // 开启长按图片显示识别微信小程序码菜单
        showMenuByLongpress: {
            type: Boolean,
            default: uni.$u.props.image.showMenuByLongpress
        },
        // 加载中的图标，或者小图片
        loadingIcon: {
            type: String,
            default: uni.$u.props.image.loadingIcon
        },
        // 加载失败的图标，或者小图片
        errorIcon: {
            type: String,
            default: uni.$u.props.image.errorIcon
        },
        // 是否显示加载中的图标或者自定义的slot
        showLoading: {
            type: Boolean,
            default: uni.$u.props.image.showLoading
        },
        // 是否显示加载错误的图标或者自定义的slot
        showError: {
            type: Boolean,
            default: uni.$u.props.image.showError
        },
        // 是否需要淡入效果
        fade: {
            type: Boolean,
            default: uni.$u.props.image.fade
        },
        // 只支持网络资源，只对微信小程序有效
        webp: {
            type: Boolean,
            default: uni.$u.props.image.webp
        },
        // 过渡时间，单位ms
        duration: {
            type: [String, Number],
            default: uni.$u.props.image.duration
        },
        // 背景颜色，用于深色页面加载图片时，为了和背景色融合
        bgColor: {
            type: String,
            default: uni.$u.props.image.bgColor
        }
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/mq/consumer/package-info.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.mq.consumer;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/permission/SysRoleDO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission;

import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler;
import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum;
import cn.iocoder.yudao.adminserver.modules.system.enums.permission.RoleCodeEnum;
import cn.iocoder.yudao.adminserver.modules.system.enums.permission.SysRoleTypeEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.util.Set;

/**
 * 角色 DO
 *
 * @author ruoyi
 */
@TableName(value = "sys_role", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
public class SysRoleDO extends BaseDO {

    /**
     * 角色ID
     */
    @TableId
    private Long id;
    /**
     * 角色名称
     */
    private String name;
    /**
     * 角色标识
     *
     * 枚举 {@link RoleCodeEnum}
     */
    private String code;
    /**
     * 角色排序
     */
    private Integer sort;
    /**
     * 角色状态
     *
     * 枚举 {@link CommonStatusEnum}
     */
    private Integer status;
    /**
     * 角色类型
     *
     * 枚举 {@link SysRoleTypeEnum}
     */
    private Integer type;
    /**
     * 备注
     */
    private String remark;

    /**
     * 数据范围
     *
     * 枚举 {@link DataScopeEnum}
     */
    private Integer dataScope;
    /**
     * 数据范围(指定部门数组)
     *
     * 适用于 {@link #dataScope} 的值为 {@link DataScopeEnum#DEPT_CUSTOM} 时
     */
    @TableField(typeHandler = JsonLongSetTypeHandler.class)
    private Set<Long> dataScopeDeptIds;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/sms/SysSmsLogConvert.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.convert.sms;

import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.log.SysSmsLogExcelVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.log.SysSmsLogRespVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsLogDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import java.util.List;

/**
 * 短信日志 Convert
 *
 * @author 芋道源码
 */
@Mapper
public interface SysSmsLogConvert {

    SysSmsLogConvert INSTANCE = Mappers.getMapper(SysSmsLogConvert.class);

    SysSmsLogRespVO convert(SysSmsLogDO bean);

    List<SysSmsLogRespVO> convertList(List<SysSmsLogDO> list);

    PageResult<SysSmsLogRespVO> convertPage(PageResult<SysSmsLogDO> page);

    List<SysSmsLogExcelVO> convertList02(List<SysSmsLogDO> list);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/permission/SysRoleTypeEnum.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.enums.permission;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum SysRoleTypeEnum {

    /**
     * 内置角色
     */
    SYSTEM(1),
    /**
     * 自定义角色
     */
    CUSTOM(2);

    private final Integer type;

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-tooltip/props.js<|end_filename|>
export default {
    props: {
        // 需要显示的提示文字
        text: {
            type: [String, Number],
            default: uni.$u.props.tooltip.text
        },
        // 点击复制按钮时，复制的文本，为空则使用text值
        copyText: {
            type: [String, Number],
            default: uni.$u.props.tooltip.copyText
        },
        // 文本大小
        size: {
            type: [String, Number],
            default: uni.$u.props.tooltip.size
        },
        // 字体颜色
        color: {
            type: String,
            default: uni.$u.props.tooltip.color
        },
        // 弹出提示框时，文本的背景色
        bgColor: {
            type: String,
            default: uni.$u.props.tooltip.bgColor
        },
        // 弹出提示的方向，top-上方，bottom-下方
        direction: {
            type: String,
            default: uni.$u.props.tooltip.direction
        },
        // 弹出提示的z-index，nvue无效
        zIndex: {
            type: [String, Number],
            default: uni.$u.props.tooltip.zIndex
        },
        // 是否显示复制按钮
        showCopy: {
            type: Boolean,
            default: uni.$u.props.tooltip.showCopy
        },
        // 扩展的按钮组
        buttons: {
            type: Array,
            default: uni.$u.props.tooltip.buttons
        },
        // 是否显示透明遮罩以防止触摸穿透
        overlay: {
            type: Boolean,
            default: uni.$u.props.tooltip.overlay
        },
        // 是否显示复制成功或者失败的toast
        showToast: {
            type: Boolean,
            default: uni.$u.props.tooltip.showToast
        }
    }
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/package-info.java<|end_filename|>
/**
 * member 包下，我们放会员业务.
 * 例如说：会员中心等等
 *
 * 缩写：mbr
 */
package cn.iocoder.yudao.coreservice.modules.member;


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/convert/dict/SysDictDataCoreConvert.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.convert.dict;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dict.SysDictDataDO;
import cn.iocoder.yudao.framework.dict.core.dto.DictDataRespDTO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import java.util.Collection;
import java.util.List;

@Mapper
public interface SysDictDataCoreConvert {

    SysDictDataCoreConvert INSTANCE = Mappers.getMapper(SysDictDataCoreConvert.class);

    DictDataRespDTO convert02(SysDictDataDO bean);

    List<DictDataRespDTO> convertList03(Collection<SysDictDataDO> list);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/job/impl/InfJobLogServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.service.job.impl;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.infra.controller.job.vo.log.InfJobLogExportReqVO;
import cn.iocoder.yudao.adminserver.modules.infra.controller.job.vo.log.InfJobLogPageReqVO;
import cn.iocoder.yudao.adminserver.modules.infra.dal.dataobject.job.InfJobLogDO;
import cn.iocoder.yudao.adminserver.modules.infra.dal.mysql.job.InfJobLogMapper;
import cn.iocoder.yudao.adminserver.modules.infra.enums.job.InfJobLogStatusEnum;
import cn.iocoder.yudao.adminserver.modules.infra.service.job.InfJobLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * Job 日志 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class InfJobLogServiceImpl implements InfJobLogService {

    @Resource
    private InfJobLogMapper jobLogMapper;

    @Override
    public Long createJobLog(Long jobId, Date beginTime, String jobHandlerName, String jobHandlerParam, Integer executeIndex) {
        InfJobLogDO log = InfJobLogDO.builder().jobId(jobId).handlerName(jobHandlerName).handlerParam(jobHandlerParam).executeIndex(executeIndex)
                .beginTime(beginTime).status(InfJobLogStatusEnum.RUNNING.getStatus()).build();
        jobLogMapper.insert(log);
        return log.getId();
    }

    @Override
    @Async
    public void updateJobLogResultAsync(Long logId, Date endTime, Integer duration, boolean success, String result) {
        try {
            InfJobLogDO updateObj = InfJobLogDO.builder().id(logId).endTime(endTime).duration(duration)
                    .status(success ? InfJobLogStatusEnum.SUCCESS.getStatus() : InfJobLogStatusEnum.FAILURE.getStatus()).result(result).build();
            jobLogMapper.updateById(updateObj);
        } catch (Exception ex) {
            log.error("[updateJobLogResultAsync][logId({}) endTime({}) duration({}) success({}) result({})]",
                    logId, endTime, duration, success, result);
        }
    }

    @Override
    public InfJobLogDO getJobLog(Long id) {
        return jobLogMapper.selectById(id);
    }

    @Override
    public List<InfJobLogDO> getJobLogList(Collection<Long> ids) {
        return jobLogMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<InfJobLogDO> getJobLogPage(InfJobLogPageReqVO pageReqVO) {
        return jobLogMapper.selectPage(pageReqVO);
    }

    @Override
    public List<InfJobLogDO> getJobLogList(InfJobLogExportReqVO exportReqVO) {
        return jobLogMapper.selectList(exportReqVO);
    }

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/mysql/dict/SysDictDataCoreMapper.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.dict;


import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dict.SysDictDataDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;

import java.util.Date;

@Mapper
public interface SysDictDataCoreMapper extends BaseMapperX<SysDictDataDO> {

    default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) {
        return selectOne(new QueryWrapper<SysDictDataDO>().select("id")
                .gt("update_time", maxUpdateTime).last("LIMIT 1")) != null;
    }

}


<|start_filename|>yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/system/service/logger/SysLoginLogServiceImplTest.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.logger;

import cn.iocoder.yudao.coreservice.BaseDbUnitTest;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger.SysLoginLogDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.logger.SysLoginLogCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginLogTypeEnum;
import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginResultEnum;
import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
import cn.iocoder.yudao.coreservice.modules.system.service.logger.impl.SysLoginLogCoreServiceImpl;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;

import javax.annotation.Resource;

import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;

@Import(SysLoginLogCoreServiceImpl.class)
public class SysLoginLogServiceImplTest extends BaseDbUnitTest {

    @Resource
    private SysLoginLogCoreServiceImpl loginLogCoreService;

    @Resource
    private SysLoginLogCoreMapper loginLogCoreMapper;

    @Test
    public void testCreateLoginLog() {
        SysLoginLogCreateReqDTO reqDTO = RandomUtils.randomPojo(SysLoginLogCreateReqDTO.class, vo -> {
            // 指定随机的范围,避免超出范围入库失败
            vo.setUserType(randomEle(UserTypeEnum.values()).getValue());
            vo.setLogType(randomEle(SysLoginLogTypeEnum.values()).getType());
            vo.setResult(randomEle(SysLoginResultEnum.values()).getResult());
            vo.setTraceId(TracerUtils.getTraceId());
        });

        // 调用
        loginLogCoreService.createLoginLog(reqDTO);
        // 断言，忽略基本字段
        SysLoginLogDO sysLoginLogDO = loginLogCoreMapper.selectOne(null);
        assertPojoEquals(reqDTO, sysLoginLogDO);
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/luch-request/helpers/combineURLs.js<|end_filename|>
'use strict'

/**
 * Creates a new URL by combining the specified URLs
 *
 * @param {string} baseURL The base URL
 * @param {string} relativeURL The relative URL
 * @returns {string} The combined URL
 */
export default function combineURLs(baseURL, relativeURL) {
    return relativeURL
        ? `${baseURL.replace(/\/+$/, '')}/${relativeURL.replace(/^\/+/, '')}`
        : baseURL
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/avatar.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 16:49:22
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/avatar.js
 */
export default {
    // avatar 组件
    avatar: {
        src: '',
        shape: 'circle',
        size: 40,
        mode: 'scaleToFill',
        text: '',
        bgColor: '#c0c4cc',
        color: '#ffffff',
        fontSize: 18,
        icon: '',
        mpAvatar: false,
        randomBgColor: false,
        defaultUrl: '',
        colorIndex: '',
        name: ''
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/controller/test/vo/ToolTestDemoExcelVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.controller.test.vo;

import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.adminserver.modules.infra.enums.InfDictTypeConstants;
import cn.iocoder.yudao.adminserver.modules.system.enums.SysDictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.util.Date;

/**
 * 测试示例 Excel VO
 *
 * @author 芋艿
 */
@Data
public class ToolTestDemoExcelVO {

    @ExcelProperty("编号")
    private Long id;

    @ExcelProperty("名字")
    private String name;

    @ExcelProperty(value = "状态", converter = DictConvert.class)
    @DictFormat(SysDictTypeConstants.COMMON_STATUS)
    private Integer status;

    @ExcelProperty(value = "类型", converter = DictConvert.class)
    @DictFormat(SysDictTypeConstants.OPERATE_TYPE)
    private Integer type;

    @ExcelProperty(value = "分类", converter = DictConvert.class)
    @DictFormat(InfDictTypeConstants.REDIS_TIMEOUT_TYPE)
    private Integer category;

    @ExcelProperty("备注")
    private String remark;

    @ExcelProperty("创建时间")
    private Date createTime;

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/modal.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:15:59
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/modal.js
 */
export default {
    // modal 组件
    modal: {
        show: false,
        title: '',
        content: '',
        confirmText: '确认',
        cancelText: '取消',
        showConfirmButton: true,
        showCancelButton: false,
        confirmColor: '#2979ff',
        cancelColor: '#606266',
        buttonReverse: false,
        zoom: true,
        asyncClose: false,
        closeOnClickOverlay: false,
        negativeTop: 0,
        width: '650rpx',
        confirmButtonShape: ''
    }
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/config/YudaoSmsAutoConfiguration.java<|end_filename|>
package cn.iocoder.yudao.framework.sms.config;

import cn.iocoder.yudao.framework.sms.core.client.SmsClientFactory;
import cn.iocoder.yudao.framework.sms.core.client.impl.SmsClientFactoryImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 短信配置类
 *
 * @author 芋道源码
 */
@Configuration
public class YudaoSmsAutoConfiguration {

    @Bean
    public SmsClientFactory smsClientFactory() {
        return new SmsClientFactoryImpl();
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-swiper-indicator/props.js<|end_filename|>
export default {
    props: {
        // 轮播的长度
        length: {
            type: [String, Number],
            default: uni.$u.props.swiperIndicator.length
        },
        // 当前处于活动状态的轮播的索引
        current: {
            type: [String, Number],
            default: uni.$u.props.swiperIndicator.current
        },
        // 指示器非激活颜色
        indicatorActiveColor: {
            type: String,
            default: uni.$u.props.swiperIndicator.indicatorActiveColor
        },
        // 指示器的激活颜色
        indicatorInactiveColor: {
            type: String,
            default: uni.$u.props.swiperIndicator.indicatorInactiveColor
        },
		// 指示器模式，line-线型，dot-点型
		indicatorMode: {
		    type: String,
		    default: uni.$u.props.swiperIndicator.indicatorMode
		}
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/dept/vo/dept/SysDeptListReqVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@ApiModel("部门列表 Request VO")
@Data
public class SysDeptListReqVO {

    @ApiModelProperty(value = "部门名称", example = "芋道", notes = "模糊匹配")
    private String name;

    @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
    private Integer status;

}


<|start_filename|>yudao-vue-ui/components/mescroll-uni/mixins/mescroll-comp.js<|end_filename|>
/**
 * mescroll-body写在子组件时,需通过mescroll的mixins补充子组件缺少的生命周期:
 * 当一个页面只有一个mescroll-body写在子组件时, 则使用mescroll-comp.js (参考 mescroll-comp 案例)
 * 当一个页面有多个mescroll-body写在子组件时, 则使用mescroll-more.js (参考 mescroll-more 案例)
 */
const MescrollCompMixin = {
	// 因为子组件无onPageScroll和onReachBottom的页面生命周期，需在页面传递进到子组件
	onPageScroll(e) {
		let item = this.$refs["mescrollItem"];
		if(item && item.mescroll) item.mescroll.onPageScroll(e);
	},
	onReachBottom() {
		let item = this.$refs["mescrollItem"];
		if(item && item.mescroll) item.mescroll.onReachBottom();
	},
	// 当down的native: true时, 还需传递此方法进到子组件
	onPullDownRefresh(){
		let item = this.$refs["mescrollItem"];
		if(item && item.mescroll) item.mescroll.onPullDownRefresh();
	}
}

export default MescrollCompMixin;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/sms/SysSmsTemplateConvert.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.convert.sms;

import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.template.SysSmsTemplateCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.template.SysSmsTemplateExcelVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.template.SysSmsTemplateRespVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.template.SysSmsTemplateUpdateReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import java.util.List;

@Mapper
public interface SysSmsTemplateConvert {

    SysSmsTemplateConvert INSTANCE = Mappers.getMapper(SysSmsTemplateConvert.class);

    SysSmsTemplateDO convert(SysSmsTemplateCreateReqVO bean);

    SysSmsTemplateDO convert(SysSmsTemplateUpdateReqVO bean);

    SysSmsTemplateRespVO convert(SysSmsTemplateDO bean);

    List<SysSmsTemplateRespVO> convertList(List<SysSmsTemplateDO> list);

    PageResult<SysSmsTemplateRespVO> convertPage(PageResult<SysSmsTemplateDO> page);

    List<SysSmsTemplateExcelVO> convertList02(List<SysSmsTemplateDO> list);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/framework/errorcode/core/generator/ErrorCodeAutoGenerator.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.framework.errorcode.core.generator;

/**
 * 错误码的自动生成器
 *
 * @author dylan
 */
public interface ErrorCodeAutoGenerator {

    /**
     * 将配置类到错误码写入数据库
     */
    void execute();

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/client/impl/debug/DebugDingTalkCodeMapping.java<|end_filename|>
package cn.iocoder.yudao.framework.sms.core.client.impl.debug;

import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.sms.core.client.SmsCodeMapping;
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;

import java.util.Objects;

/**
 * 钉钉的 SmsCodeMapping 实现类
 *
 * @author 芋道源码
 */
public class DebugDingTalkCodeMapping implements SmsCodeMapping {

    @Override
    public ErrorCode apply(String apiCode) {
        return Objects.equals(apiCode, "0") ? GlobalErrorCodeConstants.SUCCESS : SmsFrameworkErrorCodeConstants.SMS_UNKNOWN;
    }

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-excel/src/main/java/cn/iocoder/yudao/framework/excel/core/annotations/DictFormat.java<|end_filename|>
package cn.iocoder.yudao.framework.excel.core.annotations;

import java.lang.annotation.*;

/**
 * 字典格式化
 *
 * 实现将字典数据的值，格式化成字典数据的标签
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface DictFormat {

    /**
     * 例如说，SysDictTypeConstants、InfDictTypeConstants
     *
     * @return 字典类型
     */
    String value();

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/dal/mysql/file/InfFileMapper.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.dal.mysql.file;

import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import org.apache.ibatis.annotations.Mapper;

/**
 * admin 文件操作 Mapper
 *
 * @author 芋道源码
 */
@Mapper
public interface InfFileMapper extends BaseMapperX<InfFileDO> {
    default PageResult<InfFileDO> selectPage(InfFilePageReqVO reqVO) {
        return selectPage(reqVO, new QueryWrapperX<InfFileDO>()
                .likeIfPresent("id", reqVO.getId())
                .likeIfPresent("type", reqVO.getType())
                .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
                .orderByDesc("create_time"));
    }
}


<|start_filename|>yudao-vue-ui/components/uni-popup/popup.js<|end_filename|>
import message from './message.js';
// 定义 type 类型:弹出类型：top/bottom/center
const config = {
	// 顶部弹出
	top:'top',
	// 底部弹出
	bottom:'bottom',
	// 居中弹出
	center:'center',
	// 消息提示
	message:'top',
	// 对话框
	dialog:'center',
	// 分享
	share:'bottom',
}

export default {
	data(){
		return {
			config:config
		}
	},
	mixins: [message],
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-sms/src/main/java/cn/iocoder/yudao/framework/sms/core/enums/SmsFrameworkErrorCodeConstants.java<|end_filename|>
package cn.iocoder.yudao.framework.sms.core.enums;

import cn.iocoder.yudao.framework.common.exception.ErrorCode;

/**
 * 短信框架的错误码枚举
 *
 * 短信框架，使用 2-001-000-000 段
 *
 * @author 芋道源码
 */
public interface SmsFrameworkErrorCodeConstants {

    ErrorCode SMS_UNKNOWN = new ErrorCode(2001000000, "未知错误，需要解析");

    // ========== 权限 / 限流等相关 2001000100 ==========

    ErrorCode SMS_PERMISSION_DENY = new ErrorCode(2001000100, "没有发送短信的权限");
    // 云片：可以配置 IP 白名单，只有在白名单中才可以发送短信
    ErrorCode SMS_IP_DENY = new ErrorCode(2001000100, "IP 不允许发送短信");

    // 阿里云：将短信发送频率限制在正常的业务限流范围内。默认短信验证码：使用同一签名，对同一个手机号验证码，支持 1 条 / 分钟，5 条 / 小时，累计 10 条 / 天。
    ErrorCode SMS_SEND_BUSINESS_LIMIT_CONTROL = new ErrorCode(2001000102, "指定手机的发送限流");
    // 阿里云：已经达到您在控制台设置的短信日发送量限额值。在国内消息设置 > 安全设置，修改发送总量阈值。
    ErrorCode SMS_SEND_DAY_LIMIT_CONTROL = new ErrorCode(2001000103, "每天的发送限流");

    ErrorCode SMS_SEND_CONTENT_INVALID = new ErrorCode(2001000104, "短信内容有敏感词");

    // ========== 模板相关 2001000200 ==========
    ErrorCode SMS_TEMPLATE_INVALID = new ErrorCode(2001000200, "短信模板不合法"); // 包括短信模板不存在
    ErrorCode SMS_TEMPLATE_PARAM_ERROR = new ErrorCode(2001000201, "模板参数不正确");

    // ========== 签名相关 2001000300 ==========
    ErrorCode SMS_SIGN_INVALID = new ErrorCode(2001000300, "短信签名不可用");

    // ========== 账户相关 2001000400 ==========
    ErrorCode SMS_ACCOUNT_MONEY_NOT_ENOUGH = new ErrorCode(2001000400, "账户余额不足");
    ErrorCode SMS_ACCOUNT_INVALID = new ErrorCode(2001000401, "apiKey 不存在");

    // ========== 其它相关 2001000900 开头 ==========
    ErrorCode SMS_API_PARAM_ERROR = new ErrorCode(2001000900, "请求参数缺失");
    ErrorCode SMS_MOBILE_INVALID = new ErrorCode(2001000901, "手机格式不正确");
    ErrorCode SMS_MOBILE_BLACK = new ErrorCode(2001000902, "手机号在黑名单中");

    ErrorCode EXCEPTION = new ErrorCode(2001000999, "调用异常");

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/dept/SysDeptConvert.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.convert.dept;

import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptRespVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptSimpleRespVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.dept.SysDeptUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import java.util.List;

@Mapper
public interface SysDeptConvert {

    SysDeptConvert INSTANCE = Mappers.getMapper(SysDeptConvert.class);

    List<SysDeptRespVO> convertList(List<SysDeptDO> list);

    List<SysDeptSimpleRespVO> convertList02(List<SysDeptDO> list);

    SysDeptRespVO convert(SysDeptDO bean);

    SysDeptDO convert(SysDeptCreateReqVO bean);

    SysDeptDO convert(SysDeptUpdateReqVO bean);

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/scrollList.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:19:28
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/scrollList.js
 */
export default {
    // scrollList
    scrollList: {
        indicatorWidth: 50,
        indicatorBarWidth: 20,
        indicator: true,
        indicatorColor: '#f2f2f2',
        indicatorActiveColor: '#3c9cff',
        indicatorStyle: ''
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/logger/SysLoginLogService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.logger;

import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.loginlog.SysLoginLogPageReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.logger.SysLoginLogDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import java.util.List;

/**
 * 登录日志 Service 接口
 */
public interface SysLoginLogService {

    /**
     * 获得登录日志分页
     *
     * @param reqVO 分页条件
     * @return 登录日志分页
     */
    PageResult<SysLoginLogDO> getLoginLogPage(SysLoginLogPageReqVO reqVO);

    /**
     * 获得登录日志列表
     *
     * @param reqVO 列表条件
     * @return 登录日志列表
     */
    List<SysLoginLogDO> getLoginLogList(SysLoginLogExportReqVO reqVO);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/framework/package-info.java<|end_filename|>
/**
 * 属于 tool 模块的 framework 封装
 *
 * @author 芋道源码
 */
package cn.iocoder.yudao.adminserver.modules.tool.framework;


<|start_filename|>yudao-admin-ui/src/components/render/slots/el-input.js<|end_filename|>
export default {
  prepend(h, conf, key) {
    return <template slot="prepend">{conf.__slot__[key]}</template>
  },
  append(h, conf, key) {
    return <template slot="append">{conf.__slot__[key]}</template>
  }
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-swiper/props.js<|end_filename|>
export default {
    props: {
        // 列表数组，元素可为字符串，如为对象可通过keyName指定目标属性名
        list: {
            type: Array,
            default: uni.$u.props.swiper.list
        },
        // 是否显示面板指示器
        indicator: {
            type: Boolean,
            default: uni.$u.props.swiper.indicator
        },
        // 指示器非激活颜色
        indicatorActiveColor: {
            type: String,
            default: uni.$u.props.swiper.indicatorActiveColor
        },
        // 指示器的激活颜色
        indicatorInactiveColor: {
            type: String,
            default: uni.$u.props.swiper.indicatorInactiveColor
        },
        // 指示器样式，可通过bottom，left，right进行定位
        indicatorStyle: {
            type: [String, Object],
            default: uni.$u.props.swiper.indicatorStyle
        },
        // 指示器模式，line-线型，dot-点型
        indicatorMode: {
            type: String,
            default: uni.$u.props.swiper.indicatorMode
        },
        // 是否自动切换
        autoplay: {
            type: Boolean,
            default: uni.$u.props.swiper.autoplay
        },
        // 当前所在滑块的 index
        current: {
            type: [String, Number],
            default: uni.$u.props.swiper.current
        },
        // 当前所在滑块的 item-id ，不能与 current 被同时指定
        currentItemId: {
            type: String,
            default: uni.$u.props.swiper.currentItemId
        },
        // 滑块自动切换时间间隔
        interval: {
            type: [String, Number],
            default: uni.$u.props.swiper.interval
        },
        // 滑块切换过程所需时间
        duration: {
            type: [String, Number],
            default: uni.$u.props.swiper.duration
        },
        // 播放到末尾后是否重新回到开头
        circular: {
            type: Boolean,
            default: uni.$u.props.swiper.circular
        },
        // 前边距，可用于露出前一项的一小部分，nvue和支付宝不支持
        previousMargin: {
            type: [String, Number],
            default: uni.$u.props.swiper.previousMargin
        },
        // 后边距，可用于露出后一项的一小部分，nvue和支付宝不支持
        nextMargin: {
            type: [String, Number],
            default: uni.$u.props.swiper.nextMargin
        },
        // 当开启时，会根据滑动速度，连续滑动多屏，支付宝不支持
        acceleration: {
            type: Boolean,
            default: uni.$u.props.swiper.acceleration
        },
        // 同时显示的滑块数量，nvue、支付宝小程序不支持
        displayMultipleItems: {
            type: Number,
            default: uni.$u.props.swiper.displayMultipleItems
        },
        // 指定swiper切换缓动动画类型，有效值：default、linear、easeInCubic、easeOutCubic、easeInOutCubic
        // 只对微信小程序有效
        easingFunction: {
            type: String,
            default: uni.$u.props.swiper.easingFunction
        },
        // list数组中指定对象的目标属性名
        keyName: {
            type: String,
            default: uni.$u.props.swiper.keyName
        },
        // 图片的裁剪模式
        imgMode: {
            type: String,
            default: uni.$u.props.swiper.imgMode
        },
        // 组件高度
        height: {
            type: [String, Number],
            default: uni.$u.props.swiper.height
        },
        // 背景颜色
        bgColor: {
            type: String,
            default: uni.$u.props.swiper.bgColor
        },
        // 组件圆角，数值或带单位的字符串
        radius: {
            type: [String, Number],
            default: uni.$u.props.swiper.radius
        },
        // 是否加载中
        loading: {
            type: Boolean,
            default: uni.$u.props.swiper.loading
        },
        // 是否显示标题，要求数组对象中有title属性
        showTitle: {
            type: Boolean,
            default: uni.$u.props.swiper.showTitle
        }
    }
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-gap/props.js<|end_filename|>
export default {
    props: {
        // 背景颜色（默认transparent）
        bgColor: {
            type: String,
            default: uni.$u.props.gap.bgColor
        },
        // 分割槽高度，单位px（默认30）
        height: {
            type: [String, Number],
            default: uni.$u.props.gap.height
        },
        // 与上一个组件的距离
        marginTop: {
            type: [String, Number],
            default: uni.$u.props.gap.marginTop
        },
        // 与下一个组件的距离
        marginBottom: {
            type: [String, Number],
            default: uni.$u.props.gap.marginBottom
        }
    }
}


<|start_filename|>yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/ArrayUtils.java<|end_filename|>
package cn.iocoder.yudao.framework.common.util.collection;

import cn.hutool.core.util.ArrayUtil;

import java.util.function.Consumer;

/**
 * Array 工具类
 *
 * @author 芋道源码
 */
public class ArrayUtils {

    /**
     * 将 object 和 newElements 合并成一个数组
     *
     * @param object 对象
     * @param newElements 数组
     * @param <T> 泛型
     * @return 结果数组
     */
    @SafeVarargs
    public static <T> Consumer<T>[] append(Consumer<T> object, Consumer<T>... newElements) {
        if (object == null) {
            return newElements;
        }
        Consumer<T>[] result = ArrayUtil.newArray(Consumer.class, 1 + newElements.length);
        result[0] = object;
        System.arraycopy(newElements, 0, result, 1, newElements.length);
        return result;
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/mq/consumer/permission/SysRoleRefreshConsumer.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.mq.consumer.permission;

import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.permission.SysRoleRefreshMessage;
import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 针对 {@link SysRoleRefreshMessage} 的消费者
 *
 * @author 芋道源码
 */
@Component
@Slf4j
public class SysRoleRefreshConsumer extends AbstractChannelMessageListener<SysRoleRefreshMessage> {

    @Resource
    private SysRoleService roleService;

    @Override
    public void onMessage(SysRoleRefreshMessage message) {
        log.info("[onMessage][收到 Role 刷新消息]");
        roleService.initLocalCache();
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/keyboard.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:07:49
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/keyboard.js
 */
export default {
    // 键盘组件
    keyboard: {
        mode: 'number',
        dotDisabled: false,
        tooltip: true,
        showTips: true,
        tips: '',
        showCancel: true,
        showConfirm: true,
        random: false,
        safeAreaInsetBottom: true,
        closeOnClickOverlay: true,
        show: false,
        overlay: true,
        zIndex: 10075,
        cancelText: '取消',
        confirmText: '确定',
        autoChange: false
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/sms/SysSmsChannelMapper.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.sms;

import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.channel.SysSmsChannelPageReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsChannelDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.Date;

@Mapper
public interface SysSmsChannelMapper extends BaseMapperX<SysSmsChannelDO> {

    default PageResult<SysSmsChannelDO> selectPage(SysSmsChannelPageReqVO reqVO) {
        return selectPage(reqVO, new QueryWrapperX<SysSmsChannelDO>()
                .likeIfPresent("signature", reqVO.getSignature())
                .eqIfPresent("status", reqVO.getStatus())
                .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
                .orderByDesc("id"));
    }

    @Select("SELECT id FROM sys_sms_channel WHERE update_time > #{maxUpdateTime} LIMIT 1")
    Long selectExistsByUpdateTimeAfter(Date maxUpdateTime);

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/package-info.java<|end_filename|>
package cn.iocoder.yudao.framework.operatelog.core;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-row/props.js<|end_filename|>
export default {
    props: {
        // 给col添加间距，左右边距各占一半
        gutter: {
            type: [String, Number],
            default: uni.$u.props.row.gutter
        },
        // 水平排列方式，可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`)
        justify: {
            type: String,
            default: uni.$u.props.row.justify
        },
        // 垂直对齐方式，可选值为top、center、bottom
        align: {
            type: String,
            default: uni.$u.props.row.align
        }
    }
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/auth/impl/SysUserSessionCoreServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.auth.impl;

import cn.hutool.core.util.IdUtil;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.auth.SysUserSessionCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.dal.redis.auth.SysLoginUserCoreRedisDAO;
import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
import cn.iocoder.yudao.framework.security.config.SecurityProperties;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.Date;

import static cn.iocoder.yudao.framework.common.util.date.DateUtils.addTime;

/**
 * 在线用户 Session Core Service 实现类
 *
 * @author 芋道源码
 */
@Service
public class SysUserSessionCoreServiceImpl implements SysUserSessionCoreService {

    @Resource
    private SysUserSessionCoreMapper userSessionCoreMapper;

    @Resource
    private SysLoginUserCoreRedisDAO loginUserCoreRedisDAO;

    @Resource
    private SecurityProperties securityProperties;

    @Override
    public String createUserSession(LoginUser loginUser, String userIp, String userAgent) {
        // 生成 Session 编号
        String sessionId = generateSessionId();
        // 写入 Redis 缓存
        loginUser.setUpdateTime(new Date());
        loginUserCoreRedisDAO.set(sessionId, loginUser);
        // 写入 DB 中
        SysUserSessionDO userSession = SysUserSessionDO.builder().id(sessionId)
                .userId(loginUser.getId()).userType(loginUser.getUserType())
                .userIp(userIp).userAgent(userAgent).username(loginUser.getUsername())
                .sessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())))
                .build();
        userSessionCoreMapper.insert(userSession);
        // 返回 Session 编号
        return sessionId;
    }

    @Override
    public void refreshUserSession(String sessionId, LoginUser loginUser) {
        // 写入 Redis 缓存
        loginUser.setUpdateTime(new Date());
        loginUserCoreRedisDAO.set(sessionId, loginUser);
        // 更新 DB 中
        SysUserSessionDO updateObj = SysUserSessionDO.builder().id(sessionId).build();
        updateObj.setUsername(loginUser.getUsername());
        updateObj.setUpdateTime(new Date());
        updateObj.setSessionTimeout(addTime(Duration.ofMillis(getSessionTimeoutMillis())));
        userSessionCoreMapper.updateById(updateObj);
    }

    @Override
    public void deleteUserSession(String sessionId) {
        // 删除 Redis 缓存
        loginUserCoreRedisDAO.delete(sessionId);
        // 删除 DB 记录
        userSessionCoreMapper.deleteById(sessionId);
    }

    @Override
    public LoginUser getLoginUser(String sessionId) {
        return loginUserCoreRedisDAO.get(sessionId);
    }

    @Override
    public Long getSessionTimeoutMillis() {
        return securityProperties.getSessionTimeout().toMillis();
    }

    /**
     * 生成 Session 编号，目前采用 UUID 算法
     *
     * @return Session 编号
     */
    private static String generateSessionId() {
        return IdUtil.fastSimpleUUID();
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-loading-page/props.js<|end_filename|>
export default {
    props: {
        // 提示内容
        loadingText: {
            type: [String, Number],
            default: uni.$u.props.loadingPage.loadingText
        },
        // 文字上方用于替换loading动画的图片
        image: {
            type: String,
            default: uni.$u.props.loadingPage.image
        },
        // 加载动画的模式，circle-圆形，spinner-花朵形，semicircle-半圆形
        loadingMode: {
            type: String,
            default: uni.$u.props.loadingPage.loadingMode
        },
        // 是否加载中
        loading: {
            type: Boolean,
            default: uni.$u.props.loadingPage.loading
        },
        // 背景色
        bgColor: {
            type: String,
            default: uni.$u.props.loadingPage.bgColor
        },
        // 文字颜色
        color: {
            type: String,
            default: uni.$u.props.loadingPage.color
        },
        // 文字大小
        fontSize: {
            type: [String, Number],
            default: uni.$u.props.loadingPage.fontSize
        },
        // 加载中图标的颜色，只能rgb或者十六进制颜色值
        loadingColor: {
            type: String,
            default: uni.$u.props.loadingPage.loadingColor
        }
    }
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-steps/props.js<|end_filename|>
export default {
    props: {
        // 排列方向
        direction: {
            type: String,
            default: uni.$u.props.steps.direction
        },
        // 设置第几个步骤
        current: {
            type: [String, Number],
            default: uni.$u.props.steps.current
        },
        // 激活状态颜色
        activeColor: {
            type: String,
            default: uni.$u.props.steps.activeColor
        },
        // 未激活状态颜色
        inactiveColor: {
            type: String,
            default: uni.$u.props.steps.inactiveColor
        },
        // 激活状态的图标
        activeIcon: {
            type: String,
            default: uni.$u.props.steps.activeIcon
        },
        // 未激活状态图标
        inactiveIcon: {
            type: String,
            default: uni.$u.props.steps.inactiveIcon
        },
        // 是否显示点类型
        dot: {
            type: Boolean,
            default: uni.$u.props.steps.dot
        }
    }
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/numberKeyboard.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:08:05
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/numberKeyboard.js
 */
export default {
    // 数字键盘
    numberKeyboard: {
        mode: 'number',
        dotDisabled: false,
        random: false
    }
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/checkboxGroup.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 16:54:47
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/checkboxGroup.js
 */
export default {
    // checkbox-group组件
    checkboxGroup: {
        name: '',
        value: () => [],
        shape: 'square',
        disabled: false,
        activeColor: '#2979ff',
        inactiveColor: '#c8c9cc',
        size: 18,
        placement: 'row',
        labelSize: 14,
        labelColor: '#303133',
        labelDisabled: false,
        iconColor: '#ffffff',
        iconSize: 12,
        iconPlacement: 'left',
        borderBottom: false
    }
}


<|start_filename|>yudao-admin-ui/src/components/bpmnProcessDesigner/package/designer/plugins/palette/index.js<|end_filename|>
// import PaletteModule from "diagram-js/lib/features/palette";
// import CreateModule from "diagram-js/lib/features/create";
// import SpaceToolModule from "diagram-js/lib/features/space-tool";
// import LassoToolModule from "diagram-js/lib/features/lasso-tool";
// import HandToolModule from "diagram-js/lib/features/hand-tool";
// import GlobalConnectModule from "diagram-js/lib/features/global-connect";
// import translate from "diagram-js/lib/i18n/translate";
//
// import PaletteProvider from "./paletteProvider";
//
// export default {
//   __depends__: [PaletteModule, CreateModule, SpaceToolModule, LassoToolModule, HandToolModule, GlobalConnectModule, translate],
//   __init__: ["paletteProvider"],
//   paletteProvider: ["type", PaletteProvider]
// };

// custom/index.js
import CustomPalette from "./CustomPalette";

export default {
  __init__: ["paletteProvider"],
  paletteProvider: ["type", CustomPalette]
};


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/dal/mysql/test/ToolTestDemoMapper.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.dal.mysql.test;

import java.util.*;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.adminserver.modules.tool.dal.dataobject.test.ToolTestDemoDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.adminserver.modules.tool.controller.test.vo.*;

/**
 * 字典类型 Mapper
 *
 * @author 芋艿
 */
@Mapper
public interface ToolTestDemoMapper extends BaseMapperX<ToolTestDemoDO> {

    default PageResult<ToolTestDemoDO> selectPage(ToolTestDemoPageReqVO reqVO) {
        return selectPage(reqVO, new QueryWrapperX<ToolTestDemoDO>()
                .likeIfPresent("name", reqVO.getName())
                .eqIfPresent("status", reqVO.getStatus())
                .eqIfPresent("type", reqVO.getType())
                .eqIfPresent("category", reqVO.getCategory())
                .eqIfPresent("remark", reqVO.getRemark())
                .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
                .orderByDesc("id"));
    }

    default List<ToolTestDemoDO> selectList(ToolTestDemoExportReqVO reqVO) {
        return selectList(new QueryWrapperX<ToolTestDemoDO>()
                .likeIfPresent("name", reqVO.getName())
                .eqIfPresent("status", reqVO.getStatus())
                .eqIfPresent("type", reqVO.getType())
                .eqIfPresent("category", reqVO.getCategory())
                .eqIfPresent("remark", reqVO.getRemark())
                .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime())
                .orderByDesc("id"));
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/job/package-info.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.job;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/util/emitter.js<|end_filename|>
/**
 * 递归使用 call 方式this指向
 * @param componentName // 需要找的组件的名称
 * @param eventName // 事件名称
 * @param params // 需要传递的参数
 */
function broadcast(componentName, eventName, params) {
    // 循环子节点找到名称一样的子节点 否则 递归 当前子节点
    this.$children.map((child) => {
        if (componentName === child.$options.name) {
            child.$emit.apply(child, [eventName].concat(params))
        } else {
            broadcast.apply(child, [componentName, eventName].concat(params))
        }
    })
}
export default {
    methods: {
        /**
         * 派发 (向上查找) (一个)
         * @param componentName // 需要找的组件的名称
         * @param eventName // 事件名称
         * @param params // 需要传递的参数
         */
        dispatch(componentName, eventName, params) {
            let parent = this.$parent || this.$root// $parent 找到最近的父节点 $root 根节点
            let { name } = parent.$options // 获取当前组件实例的name
            // 如果当前有节点 && 当前没名称 且 当前名称等于需要传进来的名称的时候就去查找当前的节点
            // 循环出当前名称的一样的组件实例
            while (parent && (!name || name !== componentName)) {
                parent = parent.$parent
                if (parent) {
                    name = parent.$options.name
                }
            }
            // 有节点表示当前找到了name一样的实例
            if (parent) {
                parent.$emit.apply(parent, [eventName].concat(params))
            }
        },
        /**
         * 广播 (向下查找) (广播多个)
         * @param componentName // 需要找的组件的名称
         * @param eventName // 事件名称
         * @param params // 需要传递的参数
         */
        broadcast(componentName, eventName, params) {
            broadcast.call(this, componentName, eventName, params)
        }
    }
}


<|start_filename|>yudao-admin-ui/src/utils/loadScript.js<|end_filename|>
const callbacks = {}

/**
 * 加载一个远程脚本
 * @param {String} src 一个远程脚本
 * @param {Function} callback 回调
 */
function loadScript(src, callback) {
  const existingScript = document.getElementById(src)
  const cb = callback || (() => {})
  if (!existingScript) {
    callbacks[src] = []
    const $script = document.createElement('script')
    $script.src = src
    $script.id = src
    $script.async = 1
    document.body.appendChild($script)
    const onEnd = 'onload' in $script ? stdOnEnd.bind($script) : ieOnEnd.bind($script)
    onEnd($script)
  }

  callbacks[src].push(cb)

  function stdOnEnd(script) {
    script.onload = () => {
      this.onerror = this.onload = null
      callbacks[src].forEach(item => {
        item(null, script)
      })
      delete callbacks[src]
    }
    script.onerror = () => {
      this.onerror = this.onload = null
      cb(new Error(`Failed to load ${src}`), script)
    }
  }

  function ieOnEnd(script) {
    script.onreadystatechange = () => {
      if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
      this.onreadystatechange = null
      callbacks[src].forEach(item => {
        item(null, script)
      })
      delete callbacks[src]
    }
  }
}

/**
 * 顺序加载一组远程脚本
 * @param {Array} list 一组远程脚本
 * @param {Function} cb 回调
 */
export function loadScriptQueue(list, cb) {
  const first = list.shift()
  list.length ? loadScript(first, () => loadScriptQueue(list, cb)) : loadScript(first, cb)
}

export default loadScript


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-alert/props.js<|end_filename|>
export default {
    props: {
        // 显示文字
        title: {
            type: String,
            default: uni.$u.props.alert.title
        },
        // 主题，success/warning/info/error
        type: {
            type: String,
            default: uni.$u.props.alert.type
        },
        // 辅助性文字
        description: {
            type: String,
            default: uni.$u.props.alert.description
        },
        // 是否可关闭
        closable: {
            type: Boolean,
            default: uni.$u.props.alert.closable
        },
        // 是否显示图标
        showIcon: {
            type: Boolean,
            default: uni.$u.props.alert.showIcon
        },
        // 浅或深色调，light-浅色，dark-深色
        effect: {
            type: String,
            default: uni.$u.props.alert.effect
        },
        // 文字是否居中
        center: {
            type: Boolean,
            default: uni.$u.props.alert.center
        },
        // 字体大小
        fontSize: {
            type: [String, Number],
            default: uni.$u.props.alert.fontSize
        }
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/sms/vo/template/SysSmsTemplateCreateReqVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.template;

import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

@ApiModel("短信模板创建 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysSmsTemplateCreateReqVO extends SysSmsTemplateBaseVO {

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-job/src/main/java/cn/iocoder/yudao/framework/quartz/core/scheduler/SchedulerManager.java<|end_filename|>
package cn.iocoder.yudao.framework.quartz.core.scheduler;

import cn.iocoder.yudao.framework.quartz.core.enums.JobDataKeyEnum;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandlerInvoker;
import org.quartz.*;

/**
 * {@link org.quartz.Scheduler} 的管理器，负责创建任务
 *
 * 考虑到实现的简洁性，我们使用 jobHandlerName 作为唯一标识，即：
 * 1. Job 的 {@link JobDetail#getKey()}
 * 2. Trigger 的 {@link Trigger#getKey()}
 *
 * 另外，jobHandlerName 对应到 Spring Bean 的名字，直接调用
 *
 * @author 芋道源码
 */
public class SchedulerManager {

    private final Scheduler scheduler;

    public SchedulerManager(Scheduler scheduler) {
        this.scheduler = scheduler;
    }

    /**
     * 添加 Job 到 Quartz 中
     *
     * @param jobId 任务编号
     * @param jobHandlerName 任务处理器的名字
     * @param jobHandlerParam 任务处理器的参数
     * @param cronExpression CRON 表达式
     * @param retryCount 重试次数
     * @param retryInterval 重试间隔
     * @throws SchedulerException 添加异常
     */
    public void addJob(Long jobId, String jobHandlerName, String jobHandlerParam, String cronExpression,
                       Integer retryCount, Integer retryInterval)
            throws SchedulerException {
        // 创建 JobDetail 对象
        JobDetail jobDetail = JobBuilder.newJob(JobHandlerInvoker.class)
                .usingJobData(JobDataKeyEnum.JOB_ID.name(), jobId)
                .usingJobData(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName)
                .withIdentity(jobHandlerName).build();
        // 创建 Trigger 对象
        Trigger trigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval);
        // 新增调度
        scheduler.scheduleJob(jobDetail, trigger);
    }

    /**
     * 更新 Job 到 Quartz
     *
     * @param jobHandlerName 任务处理器的名字
     * @param jobHandlerParam 任务处理器的参数
     * @param cronExpression CRON 表达式
     * @param retryCount 重试次数
     * @param retryInterval 重试间隔
     * @throws SchedulerException 更新异常
     */
    public void updateJob(String jobHandlerName, String jobHandlerParam, String cronExpression,
                          Integer retryCount, Integer retryInterval)
            throws SchedulerException {
        // 创建新 Trigger 对象
        Trigger newTrigger = this.buildTrigger(jobHandlerName, jobHandlerParam, cronExpression, retryCount, retryInterval);
        // 修改调度
        scheduler.rescheduleJob(new TriggerKey(jobHandlerName), newTrigger);
    }

    /**
     * 删除 Quartz 中的 Job
     *
     * @param jobHandlerName 任务处理器的名字
     * @throws SchedulerException 删除异常
     */
    public void deleteJob(String jobHandlerName) throws SchedulerException {
        scheduler.deleteJob(new JobKey(jobHandlerName));
    }

    /**
     * 暂停 Quartz 中的 Job
     *
     * @param jobHandlerName 任务处理器的名字
     * @throws SchedulerException 暂停异常
     */
    public void pauseJob(String jobHandlerName) throws SchedulerException {
        scheduler.pauseJob(new JobKey(jobHandlerName));
    }

    /**
     * 启动 Quartz 中的 Job
     *
     * @param jobHandlerName 任务处理器的名字
     * @throws SchedulerException 启动异常
     */
    public void resumeJob(String jobHandlerName) throws SchedulerException {
        scheduler.resumeJob(new JobKey(jobHandlerName));
        scheduler.resumeTrigger(new TriggerKey(jobHandlerName));
    }

    /**
     * 立即触发一次 Quartz 中的 Job
     *
     * @param jobId 任务编号
     * @param jobHandlerName 任务处理器的名字
     * @param jobHandlerParam 任务处理器的参数
     * @throws SchedulerException 触发异常
     */
    public void triggerJob(Long jobId, String jobHandlerName, String jobHandlerParam)
            throws SchedulerException {
        JobDataMap data = new JobDataMap(); // 无需重试，所以不设置 retryCount 和 retryInterval
        data.put(JobDataKeyEnum.JOB_ID.name(), jobId);
        data.put(JobDataKeyEnum.JOB_HANDLER_NAME.name(), jobHandlerName);
        data.put(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam);
        // 触发任务
        scheduler.triggerJob(new JobKey(jobHandlerName), data);
    }

    private Trigger buildTrigger(String jobHandlerName, String jobHandlerParam, String cronExpression,
                                 Integer retryCount, Integer retryInterval) {
        return TriggerBuilder.newTrigger()
                .withIdentity(jobHandlerName)
                .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
                .usingJobData(JobDataKeyEnum.JOB_HANDLER_PARAM.name(), jobHandlerParam)
                .usingJobData(JobDataKeyEnum.JOB_RETRY_COUNT.name(), retryCount)
                .usingJobData(JobDataKeyEnum.JOB_RETRY_INTERVAL.name(), retryInterval)
                .build();
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/enums/config/InfConfigTypeEnum.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.enums.config;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum InfConfigTypeEnum {

    /**
     * 系统配置
     */
    SYSTEM(1),
    /**
     * 自定义配置
     */
    CUSTOM(2);

    private final Integer type;

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/YudaoTracerAutoConfiguration.java<|end_filename|>
package cn.iocoder.yudao.framework.tracer.config;

import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.framework.tracer.core.aop.BizTraceAspect;
import cn.iocoder.yudao.framework.tracer.core.filter.TraceFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Tracer 配置类
 *
 * @author mashu
 */
@Configuration
@ConditionalOnClass({BizTraceAspect.class})
@EnableConfigurationProperties(TracerProperties.class)
@ConditionalOnProperty(prefix = "yudao.tracer", value = "enable", matchIfMissing = true)
public class YudaoTracerAutoConfiguration {

    // TODO @芋艿：重要。目前 opentracing 版本存在冲突，要么保证 skywalking，要么保证阿里云短信 sdk
//    @Bean
//    public TracerProperties bizTracerProperties() {
//        return new TracerProperties();
//    }
//
//    @Bean
//    public BizTraceAspect bizTracingAop() {
//        return new BizTraceAspect(tracer());
//    }
//
//    @Bean
//    public Tracer tracer() {
//        // 创建 SkywalkingTracer 对象
//        SkywalkingTracer tracer = new SkywalkingTracer();
//        // 设置为 GlobalTracer 的追踪器
//        GlobalTracer.register(tracer);
//        return tracer;
//    }

    /**
     * 创建 TraceFilter 过滤器，响应 header 设置 traceId
     */
    @Bean
    public FilterRegistrationBean<TraceFilter> traceFilter() {
        FilterRegistrationBean<TraceFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new TraceFilter());
        registrationBean.setOrder(WebFilterOrderEnum.TRACE_FILTER);
        return registrationBean;
    }

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/package-info.java<|end_filename|>
/**
 * 分布式锁组件，使用 https://gitee.com/baomidou/lock4j 开源项目
 */
package cn.iocoder.yudao.framework.lock4j;


<|start_filename|>yudao-admin-ui/src/components/tinymce/config.js<|end_filename|>
/* eslint-disable max-len */

export const plugins = [
  'advlist anchor autolink autosave code codesample directionality emoticons fullscreen hr image imagetools insertdatetime link lists media nonbreaking noneditable pagebreak paste preview print save searchreplace spellchecker tabfocus table template textpattern visualblocks visualchars wordcount'
]
export const toolbar = [
  'code searchreplace bold italic underline strikethrough alignleft aligncenter alignright outdent indent blockquote removeformat subscript superscript codesample hr bullist numlist link image charmap preview anchor pagebreak insertdatetime media table emoticons forecolor backcolor fullscreen'
]


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/permission/MenuTypeEnum.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.enums.permission;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 菜单类型枚举类
 *
 * @author 芋道源码
 */
@Getter
@AllArgsConstructor
public enum MenuTypeEnum {

    DIR(1), // 目录
    MENU(2), // 菜单
    BUTTON(3) // 按钮
    ;

    /**
     * 类型
     */
    private final Integer type;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/sms/SysSmsLogService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.sms;

import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.log.SysSmsLogExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.log.SysSmsLogPageReqVO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsLogDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import java.util.List;

/**
 * 短信日志 Service 接口
 *
 * @author zzf
 * @date 13:48 2021/3/2
 */
public interface SysSmsLogService {

    /**
     * 获得短信日志分页
     *
     * @param pageReqVO 分页查询
     * @return 短信日志分页
     */
    PageResult<SysSmsLogDO> getSmsLogPage(SysSmsLogPageReqVO pageReqVO);

    /**
     * 获得短信日志列表, 用于 Excel 导出
     *
     * @param exportReqVO 查询条件
     * @return 短信日志列表
     */
    List<SysSmsLogDO> getSmsLogList(SysSmsLogExportReqVO exportReqVO);

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/user/impl/SysUserCoreServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.user.impl;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.user.SysUserCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 后台用户 Service Core 实现
 *
 * @author 芋道源码
 */
@Service
public class SysUserCoreServiceImpl implements SysUserCoreService {

    @Resource
    private SysUserCoreMapper userCoreMapper;

    @Override
    public SysUserDO getUser(Long id) {
        return userCoreMapper.selectById(id);
    }

}


<|start_filename|>yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/package-info.java<|end_filename|>
/**
 * 基础的通用类，和框架无关
 *
 * 例如说，CommonResult 为通用返回
 */
package cn.iocoder.yudao.framework.common;


<|start_filename|>yudao-admin-ui/src/components/bpmnProcessDesigner/src/modules/custom-renderer/CustomRenderer.js<|end_filename|>
import BpmnRenderer from "bpmn-js/lib/draw/BpmnRenderer";

export default function CustomRenderer(config, eventBus, styles, pathMap, canvas, textRenderer) {
  BpmnRenderer.call(this, config, eventBus, styles, pathMap, canvas, textRenderer, 2000);

  this.handlers["label"] = function() {
    return null;
  };
}

const F = function() {}; // 核心，利用空对象作为中介；
F.prototype = BpmnRenderer.prototype; // 核心，将父类的原型赋值给空对象F；
CustomRenderer.prototype = new F(); // 核心，将 F的实例赋值给子类；
CustomRenderer.prototype.constructor = CustomRenderer; // 修复子类CustomRenderer的构造器指向，防止原型链的混乱；


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/sms/impl/SysSmsLogServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.service.sms.impl;

import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.log.SysSmsLogExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.log.SysSmsLogPageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.sms.SysSmsLogMapper;
import cn.iocoder.yudao.adminserver.modules.system.service.sms.SysSmsLogService;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsLogDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * 短信日志 Service 实现类
 *
 * @author zzf
 * @date 2021/1/25 9:25
 */
@Slf4j
@Service
public class SysSmsLogServiceImpl implements SysSmsLogService {

    @Resource
    private SysSmsLogMapper smsLogMapper;

    @Override
    public PageResult<SysSmsLogDO> getSmsLogPage(SysSmsLogPageReqVO pageReqVO) {
        return smsLogMapper.selectPage(pageReqVO);
    }

    @Override
    public List<SysSmsLogDO> getSmsLogList(SysSmsLogExportReqVO exportReqVO) {
        return smsLogMapper.selectList(exportReqVO);
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/swipeActionItem.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:01:13
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/swipeActionItem.js
 */
export default {
    // swipeActionItem 组件
    swipeActionItem: {
        show: false,
        name: '',
        disabled: false,
        threshold: 20,
        autoClose: true,
        options: [],
        duration: 300
    }
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-test/src/main/java/cn/iocoder/yudao/framework/test/core/ut/package-info.java<|end_filename|>
/**
 * 提供单元测试 Unit Test 的基类
 */
package cn.iocoder.yudao.framework.test.core.ut;


<|start_filename|>yudao-admin-ui/src/api/infra/apiErrorLog.js<|end_filename|>
import request from '@/utils/request'

// 更新 API 错误日志的处理状态
export function updateApiErrorLogProcess(id, processStatus) {
  return request({
    url: '/infra/api-error-log/update-status?id=' + id + '&processStatus=' + processStatus,
    method: 'put',
  })
}

// 获得API 错误日志分页
export function getApiErrorLogPage(query) {
  return request({
    url: '/infra/api-error-log/page',
    method: 'get',
    params: query
  })
}

// 导出API 错误日志 Excel
export function exportApiErrorLogExcel(query) {
  return request({
    url: '/infra/api-error-log/export-excel',
    method: 'get',
    params: query,
    responseType: 'blob'
  })
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/tabbarItem.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:22:55
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/tabbarItem.js
 */
export default {
    //
    tabbarItem: {
        name: null,
        icon: '',
        badge: null,
        dot: false,
        text: '',
        badgeStyle: 'top: 6px;right:2px;'
    }
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-radio/props.js<|end_filename|>
export default {
    props: {
        // radio的名称
        name: {
            type: [String, Number, Boolean],
            default: uni.$u.props.radio.name
        },
        // 形状，square为方形，circle为圆型
        shape: {
            type: String,
            default: uni.$u.props.radio.shape
        },
        // 是否禁用
        disabled: {
            type: [String, Boolean],
            default: uni.$u.props.radio.disabled
        },
        // 是否禁止点击提示语选中单选框
        labelDisabled: {
            type: [String, Boolean],
            default: uni.$u.props.radio.labelDisabled
        },
        // 选中状态下的颜色，如设置此值，将会覆盖parent的activeColor值
        activeColor: {
            type: String,
            default: uni.$u.props.radio.activeColor
        },
        // 未选中的颜色
        inactiveColor: {
            type: String,
            default: uni.$u.props.radio.inactiveColor
        },
        // 图标的大小，单位px
        iconSize: {
            type: [String, Number],
            default: uni.$u.props.radio.iconSize
        },
        // label的字体大小，px单位
        labelSize: {
            type: [String, Number],
            default: uni.$u.props.radio.labelSize
        },
        // label提示文字，因为nvue下，直接slot进来的文字，由于特殊的结构，无法修改样式
        label: {
            type: [String, Number],
            default: uni.$u.props.radio.label
        },
        // 整体的大小
        size: {
            type: [String, Number],
            default: uni.$u.props.radio.size
        },
        // 图标颜色
        color: {
            type: String,
            default: uni.$u.props.radio.color
        },
        // label的颜色
        labelColor: {
            type: String,
            default: uni.$u.props.radio.labelColor
        }
    }
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/code.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 16:55:27
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/code.js
 */

export default {
    // code 组件
    code: {
        seconds: 60,
        startText: '获取验证码',
        changeText: 'X秒重新获取',
        endText: '重新获取',
        keepRunning: false,
        uniqueKey: ''
    }
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/mysql/auth/SysUserSessionCoreMapper.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.auth;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.auth.SysUserSessionDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface SysUserSessionCoreMapper extends BaseMapperX<SysUserSessionDO> {

}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/package-info.java<|end_filename|>
/**
 * 占位
 */
package cn.iocoder.yudao.userserver.modules.system.controller;


<|start_filename|>yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/package-info.java<|end_filename|>
/**
 * 数据库连接池，采用 Druid
 * 多数据源，采用爆米花
 */
package cn.iocoder.yudao.framework.datasource;


<|start_filename|>yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/jackson/core/package-info.java<|end_filename|>
package cn.iocoder.yudao.framework.jackson.core;


<|start_filename|>yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/system/service/sms/SysSmsTemplateServiceTest.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.sms;

import cn.iocoder.yudao.coreservice.BaseDbUnitTest;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms.SysSmsTemplateCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsTemplateTypeEnum;
import cn.iocoder.yudao.coreservice.modules.system.service.sms.impl.SysSmsTemplateCoreServiceImpl;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;
import java.util.function.Consumer;

import static cn.hutool.core.bean.BeanUtil.getFieldValue;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.max;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* {@link SysSmsTemplateCoreServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(SysSmsTemplateCoreServiceImpl.class)
public class SysSmsTemplateServiceTest extends BaseDbUnitTest {

    @Resource
    private SysSmsTemplateCoreServiceImpl smsTemplateCoreService;

    @Resource
    private SysSmsTemplateCoreMapper smsTemplateCoreMapper;

    @Test
    @SuppressWarnings("unchecked")
    void testInitLocalCache() {
        // mock 数据
        SysSmsTemplateDO smsTemplate01 = randomSmsTemplateDO();
        smsTemplateCoreMapper.insert(smsTemplate01);
        SysSmsTemplateDO smsTemplate02 = randomSmsTemplateDO();
        smsTemplateCoreMapper.insert(smsTemplate02);

        // 调用
        smsTemplateCoreService.initLocalCache();
        // 断言 deptCache 缓存
        Map<String, SysSmsTemplateDO> smsTemplateCache = (Map<String, SysSmsTemplateDO>) getFieldValue(smsTemplateCoreService, "smsTemplateCache");
        assertEquals(2, smsTemplateCache.size());
        assertPojoEquals(smsTemplate01, smsTemplateCache.get(smsTemplate01.getCode()));
        assertPojoEquals(smsTemplate02, smsTemplateCache.get(smsTemplate02.getCode()));
        // 断言 maxUpdateTime 缓存
        Date maxUpdateTime = (Date) getFieldValue(smsTemplateCoreService, "maxUpdateTime");
        assertEquals(max(smsTemplate01.getUpdateTime(), smsTemplate02.getUpdateTime()), maxUpdateTime);
    }

    // ========== 随机对象 ==========

    @SafeVarargs
    private static SysSmsTemplateDO randomSmsTemplateDO(Consumer<SysSmsTemplateDO>... consumers) {
        Consumer<SysSmsTemplateDO> consumer = (o) -> {
            o.setStatus(randomEle(CommonStatusEnum.values()).getStatus()); // 保证 status 的范围
            o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 type 的 范围
        };
        return randomPojo(SysSmsTemplateDO.class, ArrayUtils.append(consumer, consumers));
    }

}


<|start_filename|>yudao-vue-ui/components/mescroll-uni/components/mescroll-up.css<|end_filename|>
/* 上拉加载区域 */
.mescroll-upwarp {
	box-sizing: border-box;
	min-height: 110rpx;
	padding: 30rpx 0;
	text-align: center;
	clear: both;
}

/*提示文本 */
.mescroll-upwarp .upwarp-tip,
.mescroll-upwarp .upwarp-nodata {
	display: inline-block;
	font-size: 28rpx;
	vertical-align: middle;
	/* color: gray; 已在style设置color,此处删去*/
}

.mescroll-upwarp .upwarp-tip {
	margin-left: 16rpx;
}

/*旋转进度条 */
.mescroll-upwarp .upwarp-progress {
	display: inline-block;
	width: 32rpx;
	height: 32rpx;
	border-radius: 50%;
	border: 2rpx solid gray;
	border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/
	vertical-align: middle;
}

/* 旋转动画 */
.mescroll-upwarp .mescroll-rotate {
	animation: mescrollUpRotate 0.6s linear infinite;
}

@keyframes mescrollUpRotate {
	0% {
		transform: rotate(0deg);
	}

	100% {
		transform: rotate(360deg);
	}
}

<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-empty/props.js<|end_filename|>
export default {
    props: {
        // 内置图标名称，或图片路径，建议绝对路径
        icon: {
            type: String,
            default: uni.$u.props.empty.icon
        },
        // 提示文字
        text: {
            type: String,
            default: uni.$u.props.empty.text
        },
        // 文字颜色
        textColor: {
            type: String,
            default: uni.$u.props.empty.textColor
        },
        // 文字大小
        textSize: {
            type: [String, Number],
            default: uni.$u.props.empty.textSize
        },
        // 图标的颜色
        iconColor: {
            type: String,
            default: uni.$u.props.empty.iconColor
        },
        // 图标的大小
        iconSize: {
            type: [String, Number],
            default: uni.$u.props.empty.iconSize
        },
        // 选择预置的图标类型
        mode: {
            type: String,
            default: uni.$u.props.empty.mode
        },
        //  图标宽度，单位px
        width: {
            type: [String, Number],
            default: uni.$u.props.empty.width
        },
        // 图标高度，单位px
        height: {
            type: [String, Number],
            default: uni.$u.props.empty.height
        },
        // 是否显示组件
        show: {
            type: Boolean,
            default: uni.$u.props.empty.show
        },
        // 组件距离上一个元素之间的距离，默认px单位
        marginTop: {
            type: [String, Number],
            default: uni.$u.props.empty.marginTop
        }
    }
}


<|start_filename|>yudao-admin-ui/src/api/system/sms/smsChannel.js<|end_filename|>
import request from '@/utils/request'

// 创建短信渠道
export function createSmsChannel(data) {
  return request({
    url: '/system/sms-channel/create',
    method: 'post',
    data: data
  })
}

// 更新短信渠道
export function updateSmsChannel(data) {
  return request({
    url: '/system/sms-channel/update',
    method: 'put',
    data: data
  })
}

// 删除短信渠道
export function deleteSmsChannel(id) {
  return request({
    url: '/system/sms-channel/delete?id=' + id,
    method: 'delete'
  })
}

// 获得短信渠道
export function getSmsChannel(id) {
  return request({
    url: '/system/sms-channel/get?id=' + id,
    method: 'get'
  })
}

// 获得短信渠道分页
export function getSmsChannelPage(query) {
  return request({
    url: '/system/sms-channel/page',
    method: 'get',
    params: query
  })
}

// 获得短信渠道精简列表
export function getSimpleSmsChannels() {
  return request({
    url: '/system/sms-channel/list-all-simple',
    method: 'get',
  })
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/package-info.java<|end_filename|>
package cn.iocoder.yudao.framework;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/convert/logger/InfApiErrorLogConvert.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.convert.logger;

import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger.InfApiErrorLogDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.infra.controller.logger.vo.apierrorlog.InfApiErrorLogExcelVO;
import cn.iocoder.yudao.adminserver.modules.infra.controller.logger.vo.apierrorlog.InfApiErrorLogRespVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

import java.util.List;

/**
 * API 错误日志 Convert
 *
 * @author 芋道源码
 */
@Mapper
public interface InfApiErrorLogConvert {

    InfApiErrorLogConvert INSTANCE = Mappers.getMapper(InfApiErrorLogConvert.class);

    InfApiErrorLogRespVO convert(InfApiErrorLogDO bean);

    PageResult<InfApiErrorLogRespVO> convertPage(PageResult<InfApiErrorLogDO> page);

    List<InfApiErrorLogExcelVO> convertList02(List<InfApiErrorLogDO> list);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/service/test/impl/ToolTestDemoServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.service.test.impl;

import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import cn.iocoder.yudao.adminserver.modules.tool.controller.test.vo.*;
import cn.iocoder.yudao.adminserver.modules.tool.dal.dataobject.test.ToolTestDemoDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import cn.iocoder.yudao.adminserver.modules.tool.convert.test.ToolTestDemoConvert;
import cn.iocoder.yudao.adminserver.modules.tool.dal.mysql.test.ToolTestDemoMapper;
import cn.iocoder.yudao.adminserver.modules.tool.service.test.ToolTestDemoService;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.adminserver.modules.tool.enums.ToolErrorCodeConstants.*;

/**
 * 字典类型 Service 实现类
 *
 * @author 芋艿
 */
@Service
@Validated
public class ToolTestDemoServiceImpl implements ToolTestDemoService {

    @Resource
    private ToolTestDemoMapper testDemoMapper;

    @Override
    public Long createTestDemo(ToolTestDemoCreateReqVO createReqVO) {
        // 插入
        ToolTestDemoDO testDemo = ToolTestDemoConvert.INSTANCE.convert(createReqVO);
        testDemoMapper.insert(testDemo);
        // 返回
        return testDemo.getId();
    }

    @Override
    public void updateTestDemo(ToolTestDemoUpdateReqVO updateReqVO) {
        // 校验存在
        this.validateTestDemoExists(updateReqVO.getId());
        // 更新
        ToolTestDemoDO updateObj = ToolTestDemoConvert.INSTANCE.convert(updateReqVO);
        testDemoMapper.updateById(updateObj);
    }

    @Override
    public void deleteTestDemo(Long id) {
        // 校验存在
        this.validateTestDemoExists(id);
        // 删除
        testDemoMapper.deleteById(id);
    }

    private void validateTestDemoExists(Long id) {
        if (testDemoMapper.selectById(id) == null) {
            throw exception(TEST_DEMO_NOT_EXISTS);
        }
    }

    @Override
    public ToolTestDemoDO getTestDemo(Long id) {
        return testDemoMapper.selectById(id);
    }

    @Override
    public List<ToolTestDemoDO> getTestDemoList(Collection<Long> ids) {
        return testDemoMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<ToolTestDemoDO> getTestDemoPage(ToolTestDemoPageReqVO pageReqVO) {
        return testDemoMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ToolTestDemoDO> getTestDemoList(ToolTestDemoExportReqVO exportReqVO) {
        return testDemoMapper.selectList(exportReqVO);
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/dal/mysql/codegen/ToolCodegenTableMapper.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.dal.mysql.codegen;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.adminserver.modules.tool.controller.codegen.vo.table.ToolCodegenTablePageReqVO;
import cn.iocoder.yudao.adminserver.modules.tool.dal.dataobject.codegen.ToolCodegenTableDO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface ToolCodegenTableMapper extends BaseMapperX<ToolCodegenTableDO> {

    default ToolCodegenTableDO selectByTableName(String tableName) {
        return selectOne(new QueryWrapper<ToolCodegenTableDO>().eq("table_name", tableName));
    }

    default PageResult<ToolCodegenTableDO> selectPage(ToolCodegenTablePageReqVO pageReqVO) {
        return selectPage(pageReqVO, new QueryWrapperX<ToolCodegenTableDO>()
                .likeIfPresent("table_name", pageReqVO.getTableName())
                .likeIfPresent("table_comment", pageReqVO.getTableComment())
                .betweenIfPresent("create_time", pageReqVO.getBeginCreateTime(), pageReqVO.getEndCreateTime()));
    }

}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/controller/package-info.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.member.controller;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/loadmore.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:15:26
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/loadmore.js
 */
export default {
    // loadmore 组件
    loadmore: {
        status: 'loadmore',
        bgColor: 'transparent',
        icon: true,
        fontSize: 14,
        color: '#606266',
        loadingIcon: 'spinner',
        loadmoreText: '加载更多',
        loadingText: '正在加载...',
        nomoreText: '没有更多了',
        isDot: false,
        iconColor: '#b7b7b7',
        marginTop: 10,
        marginBottom: 10,
        height: 'auto',
        line: false
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/dept/vo/post/SysPostPageReqVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.dept.vo.post;

import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;

@ApiModel("岗位分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
public class SysPostPageReqVO extends PageParam {

    @ApiModelProperty(value = "岗位编码", example = "yudao", notes = "模糊匹配")
    private String code;

    @ApiModelProperty(value = "岗位名称", example = "芋道", notes = "模糊匹配")
    private String name;

    @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
    private Integer status;

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-parse/props.js<|end_filename|>
export default {
    props: {
        // #ifdef APP-PLUS-NVUE
        bgColor: String,
        // #endif
        content: String,
        copyLink: {
		  type: Boolean,
		  default: uni.$u.props.parse.copyLink
        },
        domain: String,
        errorImg: {
		  type: String,
		  default: uni.$u.props.parse.errorImg
        },
        lazyLoad: {
		  type: Boolean,
		  default: uni.$u.props.parse.lazyLoad
        },
        loadingImg: {
		  type: String,
		  default: uni.$u.props.parse.loadingImg
        },
        pauseVideo: {
		  type: Boolean,
		  default: uni.$u.props.parse.pauseVideo
        },
        previewImg: {
		  type: Boolean,
		  default: uni.$u.props.parse.previewImg
        },
        scrollTable: Boolean,
        selectable: Boolean,
        setTitle: {
		  type: Boolean,
		  default: uni.$u.props.parse.setTitle
        },
        showImgMenu: {
		  type: Boolean,
		  default: uni.$u.props.parse.showImgMenu
        },
        tagStyle: Object,
        useAnchor: null
	  }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/mq/consumer/mail/SysMailSendConsumer.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.mq.consumer.mail;

import cn.iocoder.yudao.framework.mq.core.stream.AbstractStreamMessageListener;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.mail.SysMailSendMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class SysMailSendConsumer extends AbstractStreamMessageListener<SysMailSendMessage> {

    @Override
    public void onMessage(SysMailSendMessage message) {
        log.info("[onMessage][消息内容({})]", message);
    }

}


<|start_filename|>yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/system/service/sms/SysSmsLogCoreServiceTest.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.sms;

import cn.hutool.core.map.MapUtil;
import cn.iocoder.yudao.coreservice.BaseDbUnitTest;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsLogDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms.SysSmsLogCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsReceiveStatusEnum;
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsSendStatusEnum;
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsTemplateTypeEnum;
import cn.iocoder.yudao.coreservice.modules.system.service.sms.impl.SysSmsLogCoreServiceImpl;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;
import java.util.function.Consumer;

import static cn.hutool.core.util.RandomUtil.randomBoolean;
import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

/**
* {@link SysSmsLogCoreServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(SysSmsLogCoreServiceImpl.class)
public class SysSmsLogCoreServiceTest extends BaseDbUnitTest {

    @Resource
    private SysSmsLogCoreServiceImpl smsLogCoreService;

    @Resource
    private SysSmsLogCoreMapper smsLogCoreMapper;

    @Test
    public void testCreateSmsLog() {
        // 准备参数
        String mobile = randomString();
        Long userId = randomLongId();
        Integer userType = randomEle(UserTypeEnum.values()).getValue();
        Boolean isSend = randomBoolean();
        SysSmsTemplateDO templateDO = randomPojo(SysSmsTemplateDO.class,
                o -> o.setType(randomEle(SysSmsTemplateTypeEnum.values()).getType()));
        String templateContent = randomString();
        Map<String, Object> templateParams = randomTemplateParams();
        // mock 方法

        // 调用
        Long logId = smsLogCoreService.createSmsLog(mobile, userId, userType, isSend,
                templateDO, templateContent, templateParams);
        // 断言
        SysSmsLogDO logDO = smsLogCoreMapper.selectById(logId);
        assertEquals(isSend ? SysSmsSendStatusEnum.INIT.getStatus() : SysSmsSendStatusEnum.IGNORE.getStatus(),
                logDO.getSendStatus());
        assertEquals(mobile, logDO.getMobile());
        assertEquals(userType, logDO.getUserType());
        assertEquals(userId, logDO.getUserId());
        assertEquals(templateDO.getId(), logDO.getTemplateId());
        assertEquals(templateDO.getCode(), logDO.getTemplateCode());
        assertEquals(templateDO.getType(), logDO.getTemplateType());
        assertEquals(templateDO.getChannelId(), logDO.getChannelId());
        assertEquals(templateDO.getChannelCode(), logDO.getChannelCode());
        assertEquals(templateContent, logDO.getTemplateContent());
        assertEquals(templateParams, logDO.getTemplateParams());
        assertEquals(SysSmsReceiveStatusEnum.INIT.getStatus(), logDO.getReceiveStatus());
    }

    @Test
    public void testUpdateSmsSendResult() {
        // mock 数据
        SysSmsLogDO dbSmsLog = randomSmsLogDO(
                o -> o.setSendStatus(SysSmsSendStatusEnum.IGNORE.getStatus()));
        smsLogCoreMapper.insert(dbSmsLog);
        // 准备参数
        Long id = dbSmsLog.getId();
        Integer sendCode = randomInteger();
        String sendMsg = randomString();
        String apiSendCode = randomString();
        String apiSendMsg = randomString();
        String apiRequestId = randomString();
        String apiSerialNo = randomString();

        // 调用
        smsLogCoreService.updateSmsSendResult(id, sendCode, sendMsg,
                apiSendCode, apiSendMsg, apiRequestId, apiSerialNo);
        // 断言
        dbSmsLog = smsLogCoreMapper.selectById(id);
        assertEquals(CommonResult.isSuccess(sendCode) ? SysSmsSendStatusEnum.SUCCESS.getStatus()
                : SysSmsSendStatusEnum.FAILURE.getStatus(), dbSmsLog.getSendStatus());
        assertNotNull(dbSmsLog.getSendTime());
        assertEquals(sendMsg, dbSmsLog.getSendMsg());
        assertEquals(apiSendCode, dbSmsLog.getApiSendCode());
        assertEquals(apiSendMsg, dbSmsLog.getApiSendMsg());
        assertEquals(apiRequestId, dbSmsLog.getApiRequestId());
        assertEquals(apiSerialNo, dbSmsLog.getApiSerialNo());
    }

    @Test
    public void testUpdateSmsReceiveResult() {
        // mock 数据
        SysSmsLogDO dbSmsLog = randomSmsLogDO(
                o -> o.setReceiveStatus(SysSmsReceiveStatusEnum.INIT.getStatus()));
        smsLogCoreMapper.insert(dbSmsLog);
        // 准备参数
        Long id = dbSmsLog.getId();
        Boolean success = randomBoolean();
        Date receiveTime = randomDate();
        String apiReceiveCode = randomString();
        String apiReceiveMsg = randomString();

        // 调用
        smsLogCoreService.updateSmsReceiveResult(id, success, receiveTime, apiReceiveCode, apiReceiveMsg);
        // 断言
        dbSmsLog = smsLogCoreMapper.selectById(id);
        assertEquals(success ? SysSmsReceiveStatusEnum.SUCCESS.getStatus()
                : SysSmsReceiveStatusEnum.FAILURE.getStatus(), dbSmsLog.getReceiveStatus());
        assertEquals(receiveTime, dbSmsLog.getReceiveTime());
        assertEquals(apiReceiveCode, dbSmsLog.getApiReceiveCode());
        assertEquals(apiReceiveMsg, dbSmsLog.getApiReceiveMsg());
    }

    // ========== 随机对象 ==========

    @SafeVarargs
    private static SysSmsLogDO randomSmsLogDO(Consumer<SysSmsLogDO>... consumers) {
        Consumer<SysSmsLogDO> consumer = (o) -> {
            o.setTemplateParams(randomTemplateParams());
            o.setTemplateType(randomEle(SysSmsTemplateTypeEnum.values()).getType()); // 保证 templateType 的范围
            o.setUserType(randomEle(UserTypeEnum.values()).getValue()); // 保证 userType 的范围
            o.setSendStatus(randomEle(SysSmsSendStatusEnum.values()).getStatus()); // 保证 sendStatus 的范围
            o.setReceiveStatus(randomEle(SysSmsReceiveStatusEnum.values()).getStatus()); // 保证 receiveStatus 的范围
        };
        return randomPojo(SysSmsLogDO.class, ArrayUtils.append(consumer, consumers));
    }


    private static Map<String, Object> randomTemplateParams() {
        return MapUtil.<String, Object>builder().put(randomString(), randomString())
                .put(randomString(), randomString()).build();
    }
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/package-info.java<|end_filename|>
/**
 * 基于 Spring Security 框架
 * 实现安全认证功能
 *
 * @author 芋道源码
 */
package cn.iocoder.yudao.framework.security;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/logger/vo/operatelog/SysOperateLogExcelVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.logger.vo.operatelog;

import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.adminserver.modules.system.enums.SysDictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.util.Date;

/**
 * 操作日志 Excel 导出响应 VO
 */
@Data
public class SysOperateLogExcelVO {

    @ExcelProperty("日志编号")
    private Long id;

    @ExcelProperty("操作模块")
    private String module;

    @ExcelProperty("操作名")
    private String name;

    @ExcelProperty(value = "操作类型", converter = DictConvert.class)
    @DictFormat(SysDictTypeConstants.OPERATE_TYPE)
    private String type;

    @ExcelProperty("操作人")
    private String userNickname;

    @ExcelProperty(value = "操作结果") // 成功 or 失败
    private String successStr;

    @ExcelProperty("操作日志")
    private Date startTime;

    @ExcelProperty("执行时长")
    private Integer duration;

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/dict/SysDictDataCoreService.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.dict;

import cn.iocoder.yudao.framework.dict.core.service.DictDataFrameworkService;

/**
 * 字典数据 Service 接口
 *
 * @author 芋道源码
 */
public interface SysDictDataCoreService extends DictDataFrameworkService {

    /**
     * 初始化字典数据的本地缓存
     */
    void initLocalCache();

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/package-info.java<|end_filename|>
/**
 * API 日志：包含两类
 * 1. API 访问日志：记录用户访问 API 的访问日志，定期归档历史日志。
 * 2. 异常日志：记录用户访问 API 的系统异常，方便日常排查问题与告警。
 *
 * @author 芋道源码
 */
package cn.iocoder.yudao.framework.apilog;


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/redis/package-info.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.system.dal.redis;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/alert.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 16:48:53
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/alert.js
 */
export default {
    // alert警告组件
    alert: {
        title: '',
        type: 'warning',
        description: '',
        closable: false,
        showIcon: false,
        effect: 'light',
        center: false,
        fontSize: 14
    }
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/filter/CacheRequestBodyFilter.java<|end_filename|>
package cn.iocoder.yudao.framework.web.core.filter;

import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Request Body 缓存 Filter，实现它的可重复读取
 *
 * @author 芋道源码
 */
public class CacheRequestBodyFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws IOException, ServletException {
        filterChain.doFilter(new CacheRequestBodyWrapper(request), response);
    }

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {
        // 只处理 json 请求内容
        return !ServletUtils.isJsonRequest(request);
    }

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/ConfigFrameworkDAO.java<|end_filename|>
package cn.iocoder.yudao.framework.apollo.internals;

import cn.iocoder.yudao.framework.apollo.internals.dto.ConfigRespDTO;

import java.util.Date;
import java.util.List;

/**
 * 配置 Framework DAO 接口
 *
 * 注意，实现类必须提供 (String jdbcUrl, String username, String password) 构造方法
 *
 * @author 芋道源码
 */
public interface ConfigFrameworkDAO {

    /**
     * 查询是否存在比 maxUpdateTime 更新记录更晚的配置
     *
     * @param maxUpdateTime 最大更新时间
     * @return 是否存在
     */
    boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime);

    /**
     * 查询配置列表
     *
     * @return 配置列表
     */
    List<ConfigRespDTO> selectList();

}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/framework/security/SecurityConfiguration.java<|end_filename|>
package cn.iocoder.yudao.userserver.framework.security;

import cn.iocoder.yudao.framework.web.config.WebProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;

import javax.annotation.Resource;

@Configuration
public class SecurityConfiguration {

    @Resource
    private WebProperties webProperties;

    @Bean
    public Customizer<ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer() {
        return registry -> {
            registry.antMatchers(api("/**")).permitAll(); // 默认 API 都是用户可访问
        };
    }

    private String api(String url) {
        return webProperties.getApiPrefix() + url;
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/file/impl/InfFileServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.service.file.impl;

import cn.iocoder.yudao.adminserver.modules.infra.dal.mysql.file.InfFileMapper;
import cn.iocoder.yudao.adminserver.modules.infra.service.file.InfFileService;
import cn.iocoder.yudao.adminserver.modules.infra.controller.file.vo.InfFilePageReqVO;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.file.InfFileDO;
import cn.iocoder.yudao.coreservice.modules.infra.service.file.InfFileCoreService;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 文件 Service 实现类
 *
 * @author 芋道源码
 */
@Service
public class InfFileServiceImpl implements InfFileService {

    @Resource
    private InfFileMapper fileMapper;

    @Override
    public PageResult<InfFileDO> getFilePage(InfFilePageReqVO pageReqVO) {
        return fileMapper.selectPage(pageReqVO);
    }

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/aop/IdempotentAspect.java<|end_filename|>
package cn.iocoder.yudao.framework.idempotent.core.aop;

import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent;
import cn.iocoder.yudao.framework.idempotent.core.keyresolver.IdempotentKeyResolver;
import cn.iocoder.yudao.framework.idempotent.core.redis.IdempotentRedisDAO;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.util.Assert;

import java.util.List;
import java.util.Map;

/**
 * 拦截声明了 {@link Idempotent} 注解的方法，实现幂等操作
 *
 * @author 芋道源码
 */
@Aspect
@Slf4j
public class IdempotentAspect {

    /**
     * IdempotentKeyResolver 集合
     */
    private final Map<Class<? extends IdempotentKeyResolver>, IdempotentKeyResolver> keyResolvers;

    private final IdempotentRedisDAO idempotentRedisDAO;

    public IdempotentAspect(List<IdempotentKeyResolver> keyResolvers, IdempotentRedisDAO idempotentRedisDAO) {
        this.keyResolvers = CollectionUtils.convertMap(keyResolvers, IdempotentKeyResolver::getClass);
        this.idempotentRedisDAO = idempotentRedisDAO;
    }

    @Before("@annotation(idempotent)")
    public void beforePointCut(JoinPoint joinPoint, Idempotent idempotent) {
        // 获得 IdempotentKeyResolver
        IdempotentKeyResolver keyResolver = keyResolvers.get(idempotent.keyResolver());
        Assert.notNull(keyResolver, "找不到对应的 IdempotentKeyResolver");
        // 解析 Key
        String key = keyResolver.resolver(joinPoint, idempotent);

        // 锁定 Key。
        boolean success = idempotentRedisDAO.setIfAbsent(key, idempotent.timeout(), idempotent.timeUnit());
        // 锁定失败，抛出异常
        if (!success) {
            log.info("[beforePointCut][方法({}) 参数({}) 存在重复请求]", joinPoint.getSignature().toString(), joinPoint.getArgs());
            throw new ServiceException(GlobalErrorCodeConstants.REPEATED_REQUESTS.getCode(), idempotent.message());
        }
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/logger/InfApiErrorLogService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.service.logger;

import cn.iocoder.yudao.adminserver.modules.infra.controller.logger.vo.apierrorlog.InfApiErrorLogExportReqVO;
import cn.iocoder.yudao.adminserver.modules.infra.controller.logger.vo.apierrorlog.InfApiErrorLogPageReqVO;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger.InfApiErrorLogDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import java.util.List;

/**
 * API 错误日志 Service 接口
 *
 * @author 芋道源码
 */
public interface InfApiErrorLogService {

    /**
     * 获得 API 错误日志分页
     *
     * @param pageReqVO 分页查询
     * @return API 错误日志分页
     */
    PageResult<InfApiErrorLogDO> getApiErrorLogPage(InfApiErrorLogPageReqVO pageReqVO);

    /**
     * 获得 API 错误日志列表, 用于 Excel 导出
     *
     * @param exportReqVO 查询条件
     * @return API 错误日志分页
     */
    List<InfApiErrorLogDO> getApiErrorLogList(InfApiErrorLogExportReqVO exportReqVO);

    /**
     * 更新 API 错误日志已处理
     *
     * @param id API 日志编号
     * @param processStatus 处理结果
     * @param processUserId 处理人
     */
    void updateApiErrorLogProcess(Long id, Integer processStatus, Long processUserId);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/permission/vo/menu/SysMenuListReqVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.permission.vo.menu;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@ApiModel("菜单列表 Request VO")
@Data
public class SysMenuListReqVO {

    @ApiModelProperty(value = "菜单名称", example = "芋道", notes = "模糊匹配")
    private String name;

    @ApiModelProperty(value = "展示状态", example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
    private Integer status;

}


<|start_filename|>yudao-admin-ui/src/api/system/loginlog.js<|end_filename|>
import request from '@/utils/request'

// 查询登录日志列表
export function list(query) {
  return request({
    url: '/system/login-log/page',
    method: 'get',
    params: query
  })
}

// 导出登录日志
export function exportLoginLog(query) {
  return request({
    url: '/system/login-log/export',
    method: 'get',
    params: query,
    responseType: 'blob'
  })
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/service/codegen/impl/ToolCodegenServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.service.codegen.impl;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.system.framework.codegen.config.CodegenProperties;
import cn.iocoder.yudao.adminserver.modules.tool.controller.codegen.vo.ToolCodegenUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.tool.controller.codegen.vo.table.ToolCodegenTablePageReqVO;
import cn.iocoder.yudao.adminserver.modules.tool.convert.codegen.ToolCodegenConvert;
import cn.iocoder.yudao.adminserver.modules.tool.dal.dataobject.codegen.ToolCodegenColumnDO;
import cn.iocoder.yudao.adminserver.modules.tool.dal.dataobject.codegen.ToolCodegenTableDO;
import cn.iocoder.yudao.adminserver.modules.tool.dal.dataobject.codegen.ToolSchemaColumnDO;
import cn.iocoder.yudao.adminserver.modules.tool.dal.dataobject.codegen.ToolSchemaTableDO;
import cn.iocoder.yudao.adminserver.modules.tool.dal.mysql.codegen.ToolCodegenColumnMapper;
import cn.iocoder.yudao.adminserver.modules.tool.dal.mysql.codegen.ToolCodegenTableMapper;
import cn.iocoder.yudao.adminserver.modules.tool.dal.mysql.codegen.ToolSchemaColumnMapper;
import cn.iocoder.yudao.adminserver.modules.tool.dal.mysql.codegen.ToolSchemaTableMapper;
import cn.iocoder.yudao.adminserver.modules.tool.enums.codegen.ToolCodegenImportTypeEnum;
import cn.iocoder.yudao.adminserver.modules.tool.service.codegen.ToolCodegenService;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import org.apache.commons.collections4.KeyValue;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.adminserver.modules.tool.enums.ToolErrorCodeConstants.*;

/**
 * 代码生成 Service 实现类
 *
 * @author 芋道源码
 */
@Service
public class ToolCodegenServiceImpl implements ToolCodegenService {

    @Resource
    private ToolSchemaTableMapper schemaTableMapper;
    @Resource
    private ToolSchemaColumnMapper schemaColumnMapper;
    @Resource
    private ToolCodegenTableMapper codegenTableMapper;
    @Resource
    private ToolCodegenColumnMapper codegenColumnMapper;

    @Resource
    private ToolCodegenBuilder codegenBuilder;
    @Resource
    private ToolCodegenEngine codegenEngine;

    @Resource
    private CodegenProperties codegenProperties;

    private Long createCodegen0(ToolCodegenImportTypeEnum importType,
                                ToolSchemaTableDO schemaTable, List<ToolSchemaColumnDO> schemaColumns) {
        // 校验导入的表和字段非空
        if (schemaTable == null) {
            throw exception(CODEGEN_IMPORT_TABLE_NULL);
        }
        if (CollUtil.isEmpty(schemaColumns)) {
            throw exception(CODEGEN_IMPORT_COLUMNS_NULL);
        }
        // 校验是否已经存在
        if (codegenTableMapper.selectByTableName(schemaTable.getTableName()) != null) {
            throw exception(CODEGEN_TABLE_EXISTS);
        }

        // 构建 ToolCodegenTableDO 对象，插入到 DB 中
        ToolCodegenTableDO table = codegenBuilder.buildTable(schemaTable);
        table.setImportType(importType.getType());
        codegenTableMapper.insert(table);
        // 构建 ToolCodegenColumnDO 数组，插入到 DB 中
        List<ToolCodegenColumnDO> columns = codegenBuilder.buildColumns(schemaColumns);
        columns.forEach(column -> {
            column.setTableId(table.getId());
            codegenColumnMapper.insert(column); // TODO 批量插入
        });
        return table.getId();
    }

    @Override
    public Long createCodegenListFromSQL(String sql) {
        // 从 SQL 中，获得数据库表结构
        ToolSchemaTableDO schemaTable;
        List<ToolSchemaColumnDO> schemaColumns;
        try {
            KeyValue<ToolSchemaTableDO, List<ToolSchemaColumnDO>> result = ToolCodegenSQLParser.parse(sql);
            schemaTable = result.getKey();
            schemaColumns = result.getValue();
        } catch (Exception ex) {
            throw exception(CODEGEN_PARSE_SQL_ERROR);
        }
        // 导入
        return this.createCodegen0(ToolCodegenImportTypeEnum.SQL, schemaTable, schemaColumns);
    }

    @Override
    public Long createCodegen(String tableName) {
        // 获取当前schema
        String tableSchema = codegenProperties.getDbSchemas().iterator().next();
        // 从数据库中，获得数据库表结构
        ToolSchemaTableDO schemaTable = schemaTableMapper.selectByTableSchemaAndTableName(tableSchema, tableName);
        List<ToolSchemaColumnDO> schemaColumns = schemaColumnMapper.selectListByTableName(tableSchema, tableName);
        // 导入
        return this.createCodegen0(ToolCodegenImportTypeEnum.DB, schemaTable, schemaColumns);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> createCodegenListFromDB(List<String> tableNames) {
        List<Long> ids = new ArrayList<>(tableNames.size());
        // 遍历添加。虽然效率会低一点，但是没必要做成完全批量，因为不会这么大量
        tableNames.forEach(tableName -> ids.add(createCodegen(tableName)));
        return ids;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCodegen(ToolCodegenUpdateReqVO updateReqVO) {
        // 校验是否已经存在
        if (codegenTableMapper.selectById(updateReqVO.getTable().getId()) == null) {
            throw exception(CODEGEN_TABLE_NOT_EXISTS);
        }

        // 更新 table 表定义
        ToolCodegenTableDO updateTableObj = ToolCodegenConvert.INSTANCE.convert(updateReqVO.getTable());
        codegenTableMapper.updateById(updateTableObj);
        // 更新 column 字段定义
        List<ToolCodegenColumnDO> updateColumnObjs = ToolCodegenConvert.INSTANCE.convertList03(updateReqVO.getColumns());
        updateColumnObjs.forEach(updateColumnObj -> codegenColumnMapper.updateById(updateColumnObj));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncCodegenFromDB(Long tableId) {
        // 校验是否已经存在
        ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
        if (table == null) {
            throw exception(CODEGEN_TABLE_NOT_EXISTS);
        }
        String tableSchema = codegenProperties.getDbSchemas().iterator().next();
        // 从数据库中，获得数据库表结构
        List<ToolSchemaColumnDO> schemaColumns = schemaColumnMapper.selectListByTableName(tableSchema, table.getTableName());

        // 执行同步
        this.syncCodegen0(tableId, schemaColumns);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncCodegenFromSQL(Long tableId, String sql) {
        // 校验是否已经存在
        ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
        if (table == null) {
            throw exception(CODEGEN_TABLE_NOT_EXISTS);
        }
        // 从 SQL 中，获得数据库表结构
        List<ToolSchemaColumnDO> schemaColumns;
        try {
            KeyValue<ToolSchemaTableDO, List<ToolSchemaColumnDO>> result = ToolCodegenSQLParser.parse(sql);
            schemaColumns = result.getValue();
        } catch (Exception ex) {
            throw exception(CODEGEN_PARSE_SQL_ERROR);
        }

        // 执行同步
        this.syncCodegen0(tableId, schemaColumns);
    }

    private void syncCodegen0(Long tableId, List<ToolSchemaColumnDO> schemaColumns) {
        // 校验导入的字段不为空
        if (CollUtil.isEmpty(schemaColumns)) {
            throw exception(CODEGEN_SYNC_COLUMNS_NULL);
        }
        Set<String> schemaColumnNames = CollectionUtils.convertSet(schemaColumns, ToolSchemaColumnDO::getColumnName);

        // 构建 ToolCodegenColumnDO 数组，只同步新增的字段
        List<ToolCodegenColumnDO> codegenColumns = codegenColumnMapper.selectListByTableId(tableId);
        Set<String> codegenColumnNames = CollectionUtils.convertSet(codegenColumns, ToolCodegenColumnDO::getColumnName);
        // 移除已经存在的字段
        schemaColumns.removeIf(column -> codegenColumnNames.contains(column.getColumnName()));
        // 计算需要删除的字段
        Set<Long> deleteColumnIds = codegenColumns.stream().filter(column -> !schemaColumnNames.contains(column.getColumnName()))
                .map(ToolCodegenColumnDO::getId).collect(Collectors.toSet());
        if (CollUtil.isEmpty(schemaColumns) && CollUtil.isEmpty(deleteColumnIds)) {
            throw exception(CODEGEN_SYNC_NONE_CHANGE);
        }

        // 插入新增的字段
        List<ToolCodegenColumnDO> columns = codegenBuilder.buildColumns(schemaColumns);
        columns.forEach(column -> {
            column.setTableId(tableId);
            codegenColumnMapper.insert(column); // TODO 批量插入
        });
        // 删除不存在的字段
        if (CollUtil.isNotEmpty(deleteColumnIds)) {
            codegenColumnMapper.deleteBatchIds(deleteColumnIds);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCodegen(Long tableId) {
        // 校验是否已经存在
        if (codegenTableMapper.selectById(tableId) == null) {
            throw exception(CODEGEN_TABLE_NOT_EXISTS);
        }

        // 删除 table 表定义
        codegenTableMapper.deleteById(tableId);
        // 删除 column 字段定义
        codegenColumnMapper.deleteListByTableId(tableId);
    }

    @Override
    public PageResult<ToolCodegenTableDO> getCodegenTablePage(ToolCodegenTablePageReqVO pageReqVO) {
        return codegenTableMapper.selectPage(pageReqVO);
    }

    @Override
    public ToolCodegenTableDO getCodegenTablePage(Long id) {
        return codegenTableMapper.selectById(id);
    }

    @Override
    public List<ToolCodegenTableDO> getCodeGenTableList() {
        return codegenTableMapper.selectList();
    }

    @Override
    public List<ToolCodegenColumnDO> getCodegenColumnListByTableId(Long tableId) {
        return codegenColumnMapper.selectListByTableId(tableId);
    }

    @Override
    public Map<String, String> generationCodes(Long tableId) {
        // 校验是否已经存在
        ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
        if (codegenTableMapper.selectById(tableId) == null) {
            throw exception(CODEGEN_TABLE_NOT_EXISTS);
        }
        List<ToolCodegenColumnDO> columns = codegenColumnMapper.selectListByTableId(tableId);
        if (CollUtil.isEmpty(columns)) {
            throw exception(CODEGEN_COLUMN_NOT_EXISTS);
        }

        // 执行生成
        return codegenEngine.execute(table, columns);
    }

    @Override
    public List<ToolSchemaTableDO> getSchemaTableList(String tableName, String tableComment) {
        List<ToolSchemaTableDO> tables = schemaTableMapper.selectList(codegenProperties.getDbSchemas(), tableName, tableComment);
        // TODO 强制移除 Quartz 的表，未来做成可配置
        tables.removeIf(table -> table.getTableName().startsWith("QRTZ_"));
        return tables;
    }

//    /**
//     * 修改保存参数校验
//     *
//     * @param genTable 业务信息
//     */
//    @Override
//    public void validateEdit(GenTable genTable) {
//        if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) {
//            String options = JSON.toJSONString(genTable.getParams());
//            JSONObject paramsObj = JSONObject.parseObject(options);
//            if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE))) {
//                throw new CustomException("树编码字段不能为空");
//            } else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE))) {
//                throw new CustomException("树父编码字段不能为空");
//            } else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME))) {
//                throw new CustomException("树名称字段不能为空");
//            }
//        }
//    }

}


<|start_filename|>yudao-admin-ui/src/components/bpmnProcessDesigner/src/modules/rules/CustomRules.js<|end_filename|>
import BpmnRules from "bpmn-js/lib/features/rules/BpmnRules";
import inherits from "inherits";

export default function CustomRules(eventBus) {
  BpmnRules.call(this, eventBus);
}

inherits(CustomRules, BpmnRules);

CustomRules.prototype.canDrop = function() {
  return false;
};

CustomRules.prototype.canMove = function() {
  return false;
};


<|start_filename|>yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java<|end_filename|>
package cn.iocoder.yudao.framework.common.util.http;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.TableMap;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.util.ReferenceUtil;
import cn.hutool.core.util.ReflectUtil;

import java.nio.charset.Charset;

/**
 * HTTP 工具类
 *
 * @author 芋道源码
 */
public class HttpUtils {

    @SuppressWarnings("unchecked")
    public static String replaceUrlQuery(String url, String key, String value) {
        UrlBuilder builder = UrlBuilder.of(url, Charset.defaultCharset());
        // 先移除
        TableMap<CharSequence, CharSequence> query = (TableMap<CharSequence, CharSequence>)
                ReflectUtil.getFieldValue(builder.getQuery(), "query");
        query.remove(key);
        // 后添加
        builder.addQuery(key, value);
        return builder.build();
    }

}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/framework/sms/SmsCodeProperties.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.system.framework.sms;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.time.Duration;
import java.util.Collection;

@ConfigurationProperties(prefix = "yudao.sms-code")
@Validated
@Data
public class SmsCodeProperties {

    /**
     * 过期时间
     */
    @NotNull(message = "过期时间不能为空")
    private Duration expireTimes;
    /**
     * 短信发送频率
     */
    @NotNull(message = "短信发送频率不能为空")
    private Duration sendFrequency;
    /**
     * 每日发送最大数量
     */
    @NotNull(message = "每日发送最大数量不能为空")
    private Integer sendMaximumQuantityPerDay;
    /**
     * 验证码最小值
     */
    @NotNull(message = "验证码最小值不能为空")
    private Integer beginCode;
    /**
     * 验证码最大值
     */
    @NotNull(message = "验证码最大值不能为空")
    private Integer endCode;

}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/convert/package-info.java<|end_filename|>
/**
 * 提供 POJO 类的实体转换
 *
 * 目前使用 MapStruct 框架
 */
package cn.iocoder.yudao.userserver.modules.system.convert;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-upload/mixin.js<|end_filename|>
export default {
    watch: {
        // 监听accept的变化，判断是否符合个平台要求
        // 只有微信小程序才支持选择媒体，文件类型，所以这里做一个判断提示
        accept: {
            immediate: true,
            handler(val) {
                // #ifndef MP-WEIXIN
                if (val === 'all' || val === 'media') {
                    uni.$u.error('只有微信小程序才支持把accept配置为all、media之一')
                }
                // #endif
                // #ifndef H5 || MP-WEIXIN
                if (val === 'file') {
                    uni.$u.error('只有微信小程序和H5(HX2.9.9)才支持把accept配置为file')
                }
                // #endif
            }
        }
    }
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/dataobject/sms/SysSmsTemplateDO.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms;

import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsTemplateTypeEnum;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

import java.util.List;

/**
 * 短信模板 DO
 *
 * @author zzf
 * @since 2021-01-25
 */
@TableName(value = "sys_sms_template", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysSmsTemplateDO extends BaseDO {

    /**
     * 自增编号
     */
    private Long id;

    // ========= 模板相关字段 =========

    /**
     * 短信类型
     *
     * 枚举 {@link SysSmsTemplateTypeEnum}
     */
    private Integer type;
    /**
     * 启用状态
     *
     * 枚举 {@link CommonStatusEnum}
     */
    private Integer status;
    /**
     * 模板编码，保证唯一
     */
    private String code;
    /**
     * 模板名称
     */
    private String name;
    /**
     * 模板内容
     *
     * 内容的参数，使用 {} 包括，例如说 {name}
     */
    private String content;
    /**
     * 参数数组(自动根据内容生成)
     */
    @TableField(typeHandler = JacksonTypeHandler.class)
    private List<String> params;
    /**
     * 备注
     */
    private String remark;
    /**
     * 短信 API 的模板编号
     */
    private String apiTemplateId;

    // ========= 渠道相关字段 =========

    /**
     * 短信渠道编号
     *
     * 关联 {@link SysSmsChannelDO#getId()}
     */
    private Long channelId;
    /**
     * 短信渠道编码
     *
     * 冗余 {@link SysSmsChannelDO#getCode()}
     */
    private String channelCode;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/controller/job/vo/job/InfJobPageReqVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.controller.job.vo.job;

import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;

@ApiModel("定时任务分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class InfJobPageReqVO extends PageParam {

    @ApiModelProperty(value = "任务名称", example = "测试任务", notes = "模糊匹配")
    private String name;

    @ApiModelProperty(value = "任务状态", example = "1", notes = "参见 InfJobStatusEnum 枚举")
    private Integer status;

    @ApiModelProperty(value = "处理器的名字", example = "sysUserSessionTimeoutJob", notes = "模糊匹配")
    private String handlerName;

}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/convert/auth/SysAuthConvert.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.system.convert.auth;

import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.security.core.LoginUser;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;

@Mapper
public interface SysAuthConvert {

    SysAuthConvert INSTANCE = Mappers.getMapper(SysAuthConvert.class);

    @Mapping(source = "mobile", target = "username")
    LoginUser convert0(MbrUserDO bean);

    default LoginUser convert(MbrUserDO bean) {
        // 目的，为了设置 UserTypeEnum.MEMBER.getValue()
        return convert0(bean).setUserType(UserTypeEnum.MEMBER.getValue());
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/package-info.java<|end_filename|>
/**
 * infra 包下，我们放基础设施的运维与管理，支撑上层的通用与核心业务。
 * 例如说：定时任务的管理、服务器的信息等等
 *
 * 缩写：inf
 */
package cn.iocoder.yudao.adminserver.modules.infra;


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/package-info.java<|end_filename|>
/**
 * 用户操作日志：记录用户的操作，用于对用户的操作的审计与追溯，永久保存。
 *
 * @author 芋道源码
 */
package cn.iocoder.yudao.framework.operatelog;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/logger/impl/InfApiAccessLogServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.service.logger.impl;

import cn.iocoder.yudao.adminserver.modules.infra.controller.logger.vo.apiaccesslog.InfApiAccessLogExportReqVO;
import cn.iocoder.yudao.adminserver.modules.infra.controller.logger.vo.apiaccesslog.InfApiAccessLogPageReqVO;
import cn.iocoder.yudao.adminserver.modules.infra.dal.mysql.logger.InfApiAccessLogMapper;
import cn.iocoder.yudao.adminserver.modules.infra.service.logger.InfApiAccessLogService;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger.InfApiAccessLogDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.List;

/**
 * API 访问日志 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class InfApiAccessLogServiceImpl implements InfApiAccessLogService {

    @Resource
    private InfApiAccessLogMapper apiAccessLogMapper;

    @Override
    public PageResult<InfApiAccessLogDO> getApiAccessLogPage(InfApiAccessLogPageReqVO pageReqVO) {
        return apiAccessLogMapper.selectPage(pageReqVO);
    }

    @Override
    public List<InfApiAccessLogDO> getApiAccessLogList(InfApiAccessLogExportReqVO exportReqVO) {
        return apiAccessLogMapper.selectList(exportReqVO);
    }

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-operatelog/src/main/java/cn/iocoder/yudao/framework/operatelog/core/annotations/OperateLog.java<|end_filename|>
package cn.iocoder.yudao.framework.operatelog.core.annotations;

import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 操作日志注解
 *
 * @author 芋道源码
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface OperateLog {

    // ========== 模块字段 ==========

    /**
     * 操作模块
     *
     * 为空时，会尝试读取 {@link Api#value()} 属性
     */
    String module() default "";
    /**
     * 操作名
     *
     * 为空时，会尝试读取 {@link ApiOperation#value()} 属性
     */
    String name() default "";
    /**
     * 操作分类
     *
     * 实际并不是数组，因为枚举不能设置 null 作为默认值
     */
    OperateTypeEnum[] type() default {};

    // ========== 开关字段 ==========

    /**
     * 是否记录操作日志
     */
    boolean enable() default true;
    /**
     * 是否记录方法参数
     */
    boolean logArgs() default true;
    /**
     * 是否记录方法结果的数据
     */
    boolean logResultData() default true;

}


<|start_filename|>yudao-admin-ui/src/api/system/menu.js<|end_filename|>
import request from '@/utils/request'

// 查询菜单列表
export function listMenu(query) {
  return request({
    url: '/system/menu/list',
    method: 'get',
    params: query
  })
}

// 查询菜单（精简)列表
export function listSimpleMenus() {
  return request({
    url: '/system/menu/list-all-simple',
    method: 'get'
  })
}

// 查询菜单详细
export function getMenu(id) {
  return request({
    url: '/system/menu/get?id=' + id,
    method: 'get'
  })
}

// 新增菜单
export function addMenu(data) {
  return request({
    url: '/system/menu/create',
    method: 'post',
    data: data
  })
}

// 修改菜单
export function updateMenu(data) {
  return request({
    url: '/system/menu/update',
    method: 'put',
    data: data
  })
}

// 删除菜单
export function delMenu(id) {
  return request({
    url: '/system/menu/delete?id=' + id,
    method: 'delete'
  })
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/mq/producer/package-info.java<|end_filename|>
/**
 * 占位
 */
package cn.iocoder.yudao.coreservice.modules.system.mq.producer;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/captcha/package-info.java<|end_filename|>
/**
 * 基于 Hutool captcha 库，实现验证码功能
 */
package cn.iocoder.yudao.adminserver.modules.system.framework.captcha;


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/user/SysUserCoreService.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.user;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;

/**
 * 后台用户 Service Core 接口
 *
 * @author 芋道源码
 */
public interface SysUserCoreService {

    /**
     * 通过用户 ID 查询用户
     *
     * @param id 用户ID
     * @return 用户对象信息
     */
    SysUserDO getUser(Long id);

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/notice/SysNoticeMapper.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.notice;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.adminserver.modules.system.controller.notice.vo.SysNoticePageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.notice.SysNoticeDO;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface SysNoticeMapper extends BaseMapperX<SysNoticeDO> {

    default PageResult<SysNoticeDO> selectPage(SysNoticePageReqVO reqVO) {
        return selectPage(reqVO, new QueryWrapperX<SysNoticeDO>()
                .likeIfPresent("title", reqVO.getTitle())
                .eqIfPresent("status", reqVO.getStatus()));
    }

}


<|start_filename|>yudao-admin-ui/src/components/bpmnProcessDesigner/package/utils.js<|end_filename|>
// 创建监听器实例
export function createListenerObject(options, isTask, prefix) {
  const listenerObj = Object.create(null);
  listenerObj.event = options.event;
  isTask && (listenerObj.id = options.id); // 任务监听器特有的 id 字段
  switch (options.listenerType) {
    case "scriptListener":
      listenerObj.script = createScriptObject(options, prefix);
      break;
    case "expressionListener":
      listenerObj.expression = options.expression;
      break;
    case "delegateExpressionListener":
      listenerObj.delegateExpression = options.delegateExpression;
      break;
    default:
      listenerObj.class = options.class;
  }
  // 注入字段
  if (options.fields) {
    listenerObj.fields = options.fields.map(field => {
      return createFieldObject(field, prefix);
    });
  }
  // 任务监听器的 定时器 设置
  if (isTask && options.event === "timeout" && !!options.eventDefinitionType) {
    const timeDefinition = window.bpmnInstances.moddle.create("bpmn:FormalExpression", { body: options.eventTimeDefinitions });
    const TimerEventDefinition = window.bpmnInstances.moddle.create("bpmn:TimerEventDefinition", {
      id: `TimerEventDefinition_${uuid(8)}`,
      [`time${options.eventDefinitionType.replace(/^\S/, s => s.toUpperCase())}`]: timeDefinition
    });
    listenerObj.eventDefinitions = [TimerEventDefinition];
  }
  return window.bpmnInstances.moddle.create(`${prefix}:${isTask ? "TaskListener" : "ExecutionListener"}`, listenerObj);
}

// 创建 监听器的注入字段 实例
export function createFieldObject(option, prefix) {
  const { name, fieldType, string, expression } = option;
  const fieldConfig = fieldType === "string" ? { name, string } : { name, expression };
  return window.bpmnInstances.moddle.create(`${prefix}:Field`, fieldConfig);
}

// 创建脚本实例
export function createScriptObject(options, prefix) {
  const { scriptType, scriptFormat, value, resource } = options;
  const scriptConfig = scriptType === "inlineScript" ? { scriptFormat, value } : { scriptFormat, resource };
  return window.bpmnInstances.moddle.create(`${prefix}:Script`, scriptConfig);
}

// 更新元素扩展属性
export function updateElementExtensions(element, extensionList) {
  const extensions = window.bpmnInstances.moddle.create("bpmn:ExtensionElements", {
    values: extensionList
  });
  window.bpmnInstances.modeling.updateProperties(element, {
    extensionElements: extensions
  });
}

// 创建一个id
export function uuid(length = 8, chars) {
  let result = "";
  let charsString = chars || "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  for (let i = length; i > 0; --i) {
    result += charsString[Math.floor(Math.random() * charsString.length)];
  }
  return result;
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/vo/profile/SysUserProfileRespVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.profile;

import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.SysUserBaseVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.util.Date;
import java.util.List;


@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
@AllArgsConstructor
@ApiModel("用户个人中心信息 Response VO")
public class SysUserProfileRespVO extends SysUserBaseVO {

    @ApiModelProperty(value = "用户编号", required = true, example = "1")
    private Long id;

    @ApiModelProperty(value = "状态", required = true, example = "1", notes = "参见 SysCommonStatusEnum 枚举类")
    private Integer status;

    @ApiModelProperty(value = "最后登录 IP", required = true, example = "192.168.1.1")
    private String loginIp;

    @ApiModelProperty(value = "最后登录时间", required = true, example = "时间戳格式")
    private Date loginDate;

    @ApiModelProperty(value = "创建时间", required = true, example = "时间戳格式")
    private Date createTime;

    /**
     * 所属角色
     */
    private List<Role> roles;

    /**
     * 所在部门
     */
    private Dept dept;

    /**
     * 所属岗位数组
     */
    private List<Post> posts;
    /**
     * 社交用户数组
     */
    private List<SocialUser> socialUsers;

    @ApiModel("角色")
    @Data
    public static class Role {

        @ApiModelProperty(value = "角色编号", required = true, example = "1")
        private Long id;

        @ApiModelProperty(value = "角色名称", required = true, example = "普通角色")
        private String name;

    }

    @ApiModel("部门")
    @Data
    public static class Dept {

        @ApiModelProperty(value = "部门编号", required = true, example = "1")
        private Long id;

        @ApiModelProperty(value = "部门名称", required = true, example = "研发部")
        private String name;

    }

    @ApiModel("岗位")
    @Data
    public static class Post {

        @ApiModelProperty(value = "岗位编号", required = true, example = "1")
        private Long id;

        @ApiModelProperty(value = "岗位名称", required = true, example = "开发")
        private String name;

    }

    @ApiModel("社交用户")
    @Data
    public static class SocialUser {

        @ApiModelProperty(value = "社交平台的类型", required = true, example = "10", notes = "参见 SysSocialTypeEnum 枚举类")
        private Integer type;

        @ApiModelProperty(value = "社交的全局编号", required = true, example = "IPRmJ0wvBptiPIlGEZiPewGwiEiE")
        private String unionId;

    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/dict/vo/data/SysDictDataExcelVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.data;

import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.adminserver.modules.system.enums.SysDictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

/**
 * 字典数据 Excel 导出响应 VO
 */
@Data
public class SysDictDataExcelVO {

    @ExcelProperty("字典编码")
    private Long id;

    @ExcelProperty("字典排序")
    private Integer sort;

    @ExcelProperty("字典标签")
    private String label;

    @ExcelProperty("字典键值")
    private String value;

    @ExcelProperty("字典类型")
    private String dictType;

    @ExcelProperty(value = "状态", converter = DictConvert.class)
    @DictFormat(SysDictTypeConstants.COMMON_STATUS)
    private Integer status;

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/service/user/MbrUserCoreService.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.member.service.user;

import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;

/**
 * 前台用户 Core Service 接口
 *
 * @author 芋道源码
 */
public interface MbrUserCoreService {
    /**
     * 通过用户 ID 查询用户
     *
     * @param id 用户ID
     * @return 用户对象信息
     */
    MbrUserDO getUser(Long id);

}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/package-info.java<|end_filename|>
/**
 * system 包下，我们放通用业务，支撑上层的核心业务。
 * 例如说：用户、部门、权限、数据字典等等
 *
 * 缩写：sys
 */
package cn.iocoder.yudao.userserver.modules.system;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/sms/vo/template/SysSmsTemplateExcelVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.sms.vo.template;

import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.adminserver.modules.system.enums.SysDictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.util.Date;

/**
 * 短信模板 Excel VO
 *
 * @author 芋道源码
 */
@Data
public class SysSmsTemplateExcelVO {

    @ExcelProperty("编号")
    private Long id;

    @ExcelProperty(value = "短信签名", converter = DictConvert.class)
    @DictFormat(SysDictTypeConstants.SMS_TEMPLATE_TYPE)
    private Integer type;

    @ExcelProperty(value = "开启状态", converter = DictConvert.class)
    @DictFormat(SysDictTypeConstants.COMMON_STATUS)
    private Integer status;

    @ExcelProperty("模板编码")
    private String code;

    @ExcelProperty("模板名称")
    private String name;

    @ExcelProperty("模板内容")
    private String content;

    @ExcelProperty("备注")
    private String remark;

    @ExcelProperty("短信 API 的模板编号")
    private String apiTemplateId;

    @ExcelProperty("短信渠道编号")
    private Long channelId;

    @ExcelProperty(value = "短信渠道编码", converter = DictConvert.class)
    @DictFormat(SysDictTypeConstants.SMS_CHANNEL_CODE)
    private String channelCode;

    @ExcelProperty("创建时间")
    private Date createTime;

}


<|start_filename|>yudao-admin-ui/src/components/parser/index.js<|end_filename|>
import Parser from './Parser'

export default Parser


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/function/platform.js<|end_filename|>
/**
 * 注意：
 * 此部分内容，在vue-cli模式下，需要在vue.config.js加入如下内容才有效：
 * module.exports = {
 *     transpileDependencies: ['uview-v2']
 * }
 */

let platform = 'none'

// #ifdef VUE3
platform = 'vue3'
// #endif

// #ifdef VUE2
platform = 'vue2'
// #endif

// #ifdef APP-PLUS
platform = 'plus'
// #endif

// #ifdef APP-NVUE
platform = 'nvue'
// #endif

// #ifdef H5
platform = 'h5'
// #endif

// #ifdef MP-WEIXIN
platform = 'weixin'
// #endif

// #ifdef MP-ALIPAY
platform = 'alipay'
// #endif

// #ifdef MP-BAIDU
platform = 'baidu'
// #endif

// #ifdef MP-TOUTIAO
platform = 'toutiao'
// #endif

// #ifdef MP-QQ
platform = 'qq'
// #endif

// #ifdef MP-KUAISHOU
platform = 'kuaishou'
// #endif

// #ifdef MP-360
platform = '360'
// #endif

// #ifdef MP
platform = 'mp'
// #endif

// #ifdef QUICKAPP-WEBVIEW
platform = 'quickapp-webview'
// #endif

// #ifdef QUICKAPP-WEBVIEW-HUAWEI
platform = 'quickapp-webview-huawei'
// #endif

// #ifdef QUICKAPP-WEBVIEW-UNION
platform = 'quckapp-webview-union'
// #endif

export default platform


<|start_filename|>yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/config/XssProperties.java<|end_filename|>
package cn.iocoder.yudao.framework.web.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

import java.util.Collections;
import java.util.List;

/**
 * Xss 配置属性
 *
 * @author 芋道源码
 */
@ConfigurationProperties(prefix = "yudao.xss")
@Validated
@Data
public class XssProperties {

    /**
     * 是否开启，默认为 true
     */
    private boolean enable = true;
    /**
     * 需要排除的 URL，默认为空
     */
    private List<String> excludeUrls = Collections.emptyList();

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/mysql/package-info.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.dal.mysql;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/album.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 16:47:24
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/album.js
 */
export default {
    // album 组件
    album: {
        urls: () => [],
        keyName: '',
        singleSize: 180,
        multipleSize: 70,
        space: 6,
        singleMode: 'scaleToFill',
        multipleMode: 'aspectFill',
        maxCount: 9,
        previewFullImage: true,
        rowCount: 3,
        showMore: true
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/enums/codegen/ToolCodegenColumnHtmlTypeEnum.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.enums.codegen;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 代码生成器的字段 HTML 展示枚举
 */
@AllArgsConstructor
@Getter
public enum ToolCodegenColumnHtmlTypeEnum {

    INPUT("input"), // 文本框
    TEXTAREA("textarea"), // 文本域
    SELECT("select"), // 下拉框
    RADIO("radio"), // 单选框
    CHECKBOX("checkbox"), // 复选框
    DATETIME("datetime"), // 日期控件
    UPLOAD_IMAGE("upload_image"), // 上传图片
    UPLOAD_FILE("upload_file"), // 上传文件
    EDITOR("editor"), // 富文本控件
    ;

    /**
     * 条件
     */
    private final String type;

}


<|start_filename|>yudao-admin-server/src/test-integration/java/cn/iocoder/yudao/adminserver/modules/tool/dal/mysql/codegen/ToolInformationSchemaColumnMapperTest.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.dal.mysql.codegen;

import cn.iocoder.yudao.adminserver.BaseDbUnitTest;
import cn.iocoder.yudao.adminserver.modules.tool.dal.dataobject.codegen.ToolSchemaColumnDO;
import org.junit.jupiter.api.Test;

import javax.annotation.Resource;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class ToolInformationSchemaColumnMapperTest extends BaseDbUnitTest {

    @Resource
    private ToolSchemaColumnMapper toolInformationSchemaColumnMapper;

    @Test
    public void testSelectListByTableName() {
        List<ToolSchemaColumnDO> columns = toolInformationSchemaColumnMapper
                .selectListByTableName("", "inf_config");
        assertTrue(columns.size() > 0);
    }

}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/dal/dataobject/package-info.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.system.dal.dataobject;


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/enums/package-info.java<|end_filename|>
/**
 * 占位类，可以无视
 */
package cn.iocoder.yudao.coreservice.modules.infra.enums;


<|start_filename|>yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/idempotent/core/redis/IdempotentRedisDAO.java<|end_filename|>
package cn.iocoder.yudao.framework.idempotent.core.redis;

import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.concurrent.TimeUnit;

import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;

/**
 * 幂等 Redis DAO
 *
 * @author 芋道源码
 */
@AllArgsConstructor
public class IdempotentRedisDAO {

    private static final RedisKeyDefine IDEMPOTENT = new RedisKeyDefine("幂等操作",
            "idempotent:%s", // 参数为 uuid
            STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);

    private final StringRedisTemplate redisTemplate;

    public Boolean setIfAbsent(String key, long timeout, TimeUnit timeUnit) {
        String redisKey = formatKey(key);
        return redisTemplate.opsForValue().setIfAbsent(redisKey, "", timeout, timeUnit);
    }

    private static String formatKey(String key) {
        return String.format(IDEMPOTENT.getKeyTemplate(), key);
    }

}


<|start_filename|>yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/system/service/package-info.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service;


<|start_filename|>yudao-framework/yudao-spring-boot-starter-protection/src/main/java/cn/iocoder/yudao/framework/lock4j/config/YudaoLock4jConfiguration.java<|end_filename|>
package cn.iocoder.yudao.framework.lock4j.config;

import cn.hutool.core.util.ClassUtil;
import cn.iocoder.yudao.framework.lock4j.core.DefaultLockFailureStrategy;
import cn.iocoder.yudao.framework.lock4j.core.Lock4jRedisKeyConstants;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class YudaoLock4jConfiguration {

    static {
        // 手动加载 Lock4jRedisKeyConstants 类，因为它不会被使用到
        // 如果不加载，会导致 Redis 监控，看到它的 Redis Key 枚举
        ClassUtil.loadClass(Lock4jRedisKeyConstants.class.getName());
    }

    @Bean
    public DefaultLockFailureStrategy lockFailureStrategy() {
        return new DefaultLockFailureStrategy();
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/columnNotice.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 16:57:16
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/columnNotice.js
 */
export default {
    // columnNotice 组件
    columnNotice: {
        text: '',
        icon: 'volume',
        mode: '',
        color: '#f9ae3d',
        bgColor: '#fdf6ec',
        fontSize: 14,
        speed: 80,
        step: false,
        duration: 1500,
        disableTouch: true
    }
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-tag/props.js<|end_filename|>
export default {
    props: {
        // 标签类型info、primary、success、warning、error
        type: {
            type: String,
            default: uni.$u.props.tag.type
        },
        // 不可用
        disabled: {
            type: [Boolean, String],
            default: uni.$u.props.tag.disabled
        },
        // 标签的大小，large，medium，mini
        size: {
            type: String,
            default: uni.$u.props.tag.size
        },
        // tag的形状，circle（两边半圆形）, square（方形，带圆角）
        shape: {
            type: String,
            default: uni.$u.props.tag.shape
        },
        // 标签文字
        text: {
            type: [String, Number],
            default: uni.$u.props.tag.text
        },
        // 背景颜色，默认为空字符串，即不处理
        bgColor: {
            type: String,
            default: uni.$u.props.tag.bgColor
        },
        // 标签字体颜色，默认为空字符串，即不处理
        color: {
            type: String,
            default: uni.$u.props.tag.color
        },
        // 标签的边框颜色
        borderColor: {
            type: String,
            default: uni.$u.props.tag.borderColor
        },
        // 关闭按钮图标的颜色
        closeColor: {
            type: String,
            default: uni.$u.props.tag.closeColor
        },
        // 点击时返回的索引值，用于区分例遍的数组哪个元素被点击了
        name: {
            type: [String, Number],
            default: uni.$u.props.tag.name
        },
        // // 模式选择，dark|light|plain
        // mode: {
        // 	type: String,
        // 	default: 'light'
        // },
        // 镂空时是否填充背景色
        plainFill: {
            type: Boolean,
            default: uni.$u.props.tag.plainFill
        },
        // 是否镂空
        plain: {
            type: Boolean,
            default: uni.$u.props.tag.plain
        },
        // 是否可关闭
        closable: {
            type: Boolean,
            default: uni.$u.props.tag.closable
        },
        // 是否显示
        show: {
            type: Boolean,
            default: uni.$u.props.tag.show
        },
        // 内置图标，或绝对路径的图片
        icon: {
            type: String,
            default: uni.$u.props.tag.icon
        }
    }
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/dal/mysql/logger/InfApiErrorLogCoreMapper.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.logger;

import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger.InfApiErrorLogDO;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface InfApiErrorLogCoreMapper extends BaseMapperX<InfApiErrorLogDO> {
}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/datasource/core/enums/DataSourceEnum.java<|end_filename|>
package cn.iocoder.yudao.framework.datasource.core.enums;

/**
 * 对应于多数据源中不同数据源配置
 *
 * 通过在方法上，使用 {@link com.baomidou.dynamic.datasource.annotation.DS} 注解，设置使用的数据源。
 * 注意，默认是 {@link #MASTER} 数据源
 *
 * 对应官方文档为 http://dynamic-datasource.com/guide/customize/Annotation.html
 */
public interface DataSourceEnum {

    /**
     * 主库，推荐使用 {@link com.baomidou.dynamic.datasource.annotation.Master} 注解
     */
    String MASTER = "master";
    /**
     * 从库，推荐使用 {@link com.baomidou.dynamic.datasource.annotation.Slave} 注解
     */
    String SLAVE = "slave";

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/mq/message/package-info.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.mq.message;


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/aliyun/AliyunSmsClientTest.java<|end_filename|>
package cn.iocoder.yudao.framework.sms.core.client.impl.aliyun;

import cn.hutool.core.util.ReflectUtil;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.sms.core.enums.SmsFrameworkErrorCodeConstants;
import com.aliyuncs.AcsRequest;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateRequest;
import com.aliyuncs.dysmsapi.model.v20170525.QuerySmsTemplateResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.google.common.collect.Lists;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentMatcher;
import org.mockito.InjectMocks;
import org.mockito.Mock;

import java.util.List;
import java.util.function.Function;

import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Mockito.when;

/**
 * {@link AliyunSmsClient} 的单元测试
 *
 * @author 芋道源码
 */
public class AliyunSmsClientTest extends BaseMockitoUnitTest {

    private final SmsChannelProperties properties = new SmsChannelProperties()
            .setApiKey(randomString()) // 随机一个 apiKey，避免构建报错
            .setApiSecret(randomString()) // 随机一个 apiSecret，避免构建报错
            .setSignature("芋道源码");

    @InjectMocks
    private final AliyunSmsClient smsClient = new AliyunSmsClient(properties);

    @Mock
    private IAcsClient client;

    @Test
    public void testDoInit() {
        // 准备参数
        // mock 方法

        // 调用
        smsClient.doInit();
        // 断言
        assertNotSame(client, ReflectUtil.getFieldValue(smsClient, "acsClient"));
    }

    @Test
    @SuppressWarnings("unchecked")
    public void testDoSendSms() throws ClientException {
        // 准备参数
        Long sendLogId = randomLongId();
        String mobile = randomString();
        String apiTemplateId = randomString();
        List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
                new KeyValue<>("code", 1234), new KeyValue<>("op", "login"));
        // mock 方法
        SendSmsResponse response = randomPojo(SendSmsResponse.class, o -> o.setCode("OK"));
        when(client.getAcsResponse(argThat((ArgumentMatcher<SendSmsRequest>) acsRequest -> {
            assertEquals(mobile, acsRequest.getPhoneNumbers());
            assertEquals(properties.getSignature(), acsRequest.getSignName());
            assertEquals(apiTemplateId, acsRequest.getTemplateCode());
            assertEquals(toJsonString(MapUtils.convertMap(templateParams)), acsRequest.getTemplateParam());
            assertEquals(sendLogId.toString(), acsRequest.getOutId());
            return true;
        }))).thenReturn(response);

        // 调用
        SmsCommonResult<SmsSendRespDTO> result = smsClient.doSendSms(sendLogId, mobile,
                apiTemplateId, templateParams);
        // 断言
        assertEquals(response.getCode(), result.getApiCode());
        assertEquals(response.getMessage(), result.getApiMsg());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
        assertEquals(response.getRequestId(), result.getApiRequestId());
        // 断言结果
        assertEquals(response.getBizId(), result.getData().getSerialNo());
    }

    @Test
    public void testDoTParseSmsReceiveStatus() throws Throwable {
        // 准备参数
        String text = "[\n" +
                "  {\n" +
                "    \"phone_number\" : \"13900000001\",\n" +
                "    \"send_time\" : \"2017-01-01 11:12:13\",\n" +
                "    \"report_time\" : \"2017-02-02 22:23:24\",\n" +
                "    \"success\" : true,\n" +
                "    \"err_code\" : \"DELIVERED\",\n" +
                "    \"err_msg\" : \"用户接收成功\",\n" +
                "    \"sms_size\" : \"1\",\n" +
                "    \"biz_id\" : \"12345\",\n" +
                "    \"out_id\" : \"67890\"\n" +
                "  }\n" +
                "]";
        // mock 方法

        // 调用
        List<SmsReceiveRespDTO> statuses = smsClient.doParseSmsReceiveStatus(text);
        // 断言
        assertEquals(1, statuses.size());
        assertTrue(statuses.get(0).getSuccess());
        assertEquals("DELIVERED", statuses.get(0).getErrorCode());
        assertEquals("用户接收成功", statuses.get(0).getErrorMsg());
        assertEquals("13900000001", statuses.get(0).getMobile());
        assertEquals(DateUtils.buildTime(2017, 2, 2, 22, 23, 24), statuses.get(0).getReceiveTime());
        assertEquals("12345", statuses.get(0).getSerialNo());
        assertEquals(67890L, statuses.get(0).getLogId());
    }

    @Test
    public void testDoGetSmsTemplate() throws ClientException {
        // 准备参数
        String apiTemplateId = randomString();
        // mock 方法
        QuerySmsTemplateResponse response = randomPojo(QuerySmsTemplateResponse.class, o -> {
            o.setCode("OK");
            o.setTemplateStatus(1); // 设置模板通过
        });
        when(client.getAcsResponse(argThat((ArgumentMatcher<QuerySmsTemplateRequest>) acsRequest -> {
            assertEquals(apiTemplateId, acsRequest.getTemplateCode());
            return true;
        }))).thenReturn(response);

        // 调用
        SmsCommonResult<SmsTemplateRespDTO> result = smsClient.doGetSmsTemplate(apiTemplateId);
        // 断言
        assertEquals(response.getCode(), result.getApiCode());
        assertEquals(response.getMessage(), result.getApiMsg());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
        assertEquals(response.getRequestId(), result.getApiRequestId());
        // 断言结果
        assertEquals(response.getTemplateCode(), result.getData().getId());
        assertEquals(response.getTemplateContent(), result.getData().getContent());
        assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());
        assertEquals(response.getReason(), result.getData().getAuditReason());
    }

    @Test
    public void testConvertSmsTemplateAuditStatus() {
        assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(),
                smsClient.convertSmsTemplateAuditStatus(0));
        assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(),
                smsClient.convertSmsTemplateAuditStatus(1));
        assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(),
                smsClient.convertSmsTemplateAuditStatus(2));
        assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus(3),
                "未知审核状态(3)");
    }

    @Test
    @SuppressWarnings("unchecked")
    public void testInvoke_throwable() throws ClientException {
        // 准备参数
        QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
        // mock 方法
        ClientException ex = new ClientException("isv.INVALID_PARAMETERS", "参数不正确", randomString());
        when(client.getAcsResponse(any(AcsRequest.class))).thenThrow(ex);

        // 调用，并断言异常
        SmsCommonResult<?> result = smsClient.invoke(request,null);
        // 断言
        assertEquals(ex.getErrCode(), result.getApiCode());
        assertEquals(ex.getErrMsg(), result.getApiMsg());
        Assertions.assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR.getCode(), result.getCode());
        Assertions.assertEquals(SmsFrameworkErrorCodeConstants.SMS_API_PARAM_ERROR.getMsg(), result.getMsg());
        assertEquals(ex.getRequestId(), result.getApiRequestId());
    }

    @Test
    public void testInvoke_success() throws ClientException {
        // 准备参数
        QuerySmsTemplateRequest request = new QuerySmsTemplateRequest();
        Function<QuerySmsTemplateResponse, SmsTemplateRespDTO> responseConsumer = response -> {
            SmsTemplateRespDTO data = new SmsTemplateRespDTO();
            data.setId(response.getTemplateCode()).setContent(response.getTemplateContent());
            data.setAuditStatus(SmsTemplateAuditStatusEnum.SUCCESS.getStatus()).setAuditReason(response.getReason());
            return data;
        };
        // mock 方法
        QuerySmsTemplateResponse response = randomPojo(QuerySmsTemplateResponse.class, o -> {
            o.setCode("OK");
            o.setTemplateStatus(1); // 设置模板通过
        });
        when(client.getAcsResponse(any(AcsRequest.class))).thenReturn(response);

        // 调用
        SmsCommonResult<SmsTemplateRespDTO> result = smsClient.invoke(request, responseConsumer);
        // 断言
        assertEquals(response.getCode(), result.getApiCode());
        assertEquals(response.getMessage(), result.getApiMsg());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
        assertEquals(response.getRequestId(), result.getApiRequestId());
        // 断言结果
        assertEquals(response.getTemplateCode(), result.getData().getId());
        assertEquals(response.getTemplateContent(), result.getData().getContent());
        assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());
        assertEquals(response.getReason(), result.getData().getAuditReason());
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/convert/package-info.java<|end_filename|>
/**
 * 提供 POJO 类的实体转换
 *
 * 目前使用 MapStruct 框架
 */
package cn.iocoder.yudao.adminserver.modules.infra.convert;


<|start_filename|>yudao-admin-ui/src/api/infra/jobLog.js<|end_filename|>
import request from '@/utils/request'

// 获得定时任务
export function getJobLog(id) {
  return request({
    url: '/infra/job-log/get?id=' + id,
    method: 'get'
  })
}

// 获得定时任务分页
export function getJobLogPage(query) {
  return request({
    url: '/infra/job-log/page',
    method: 'get',
    params: query
  })
}

// 导出定时任务 Excel
export function exportJobLogExcel(query) {
  return request({
    url: '/infra/job-log/export-excel',
    method: 'get',
    params: query,
    responseType: 'blob'
  })
}


<|start_filename|>yudao-core-service/src/test/java/cn/iocoder/yudao/coreservice/modules/system/service/dict/SysDictDataCoreServiceTest.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.dict;

import cn.iocoder.yudao.coreservice.BaseDbUnitTest;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.dict.SysDictDataDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.dict.SysDictDataCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.service.dict.impl.SysDictDataCoreServiceImpl;
import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import com.google.common.collect.ImmutableTable;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.Import;

import javax.annotation.Resource;
import java.util.Date;
import java.util.function.Consumer;

import static cn.hutool.core.bean.BeanUtil.getFieldValue;
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomCommonStatus;
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* {@link SysDictDataCoreServiceImpl} 的单元测试类
*
* @author 芋道源码
*/
@Import(SysDictDataCoreServiceImpl.class)
public class SysDictDataCoreServiceTest extends BaseDbUnitTest {

    @Resource
    private SysDictDataCoreServiceImpl dictDataCoreService;

    @Resource
    private SysDictDataCoreMapper dictDataMapper;

    /**
     * 测试加载到新的字典数据的情况
     */
    @Test
    @SuppressWarnings("unchecked")
    public void testInitLocalCache() {
        // mock 数据
        SysDictDataDO dictData01 = randomDictDataDO();
        dictDataMapper.insert(dictData01);
        SysDictDataDO dictData02 = randomDictDataDO();
        dictDataMapper.insert(dictData02);

        // 调用
        dictDataCoreService.initLocalCache();
        // 断言 labelDictDataCache 缓存
        ImmutableTable<String, String, SysDictDataDO> labelDictDataCache =
                (ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataCoreService, "labelDictDataCache");
        assertEquals(2, labelDictDataCache.size());
        assertPojoEquals(dictData01, labelDictDataCache.get(dictData01.getDictType(), dictData01.getLabel()));
        assertPojoEquals(dictData02, labelDictDataCache.get(dictData02.getDictType(), dictData02.getLabel()));
        // 断言 valueDictDataCache 缓存
        ImmutableTable<String, String, SysDictDataDO> valueDictDataCache =
                (ImmutableTable<String, String, SysDictDataDO>) getFieldValue(dictDataCoreService, "valueDictDataCache");
        assertEquals(2, valueDictDataCache.size());
        assertPojoEquals(dictData01, valueDictDataCache.get(dictData01.getDictType(), dictData01.getValue()));
        assertPojoEquals(dictData02, valueDictDataCache.get(dictData02.getDictType(), dictData02.getValue()));
        // 断言 maxUpdateTime 缓存
        Date maxUpdateTime = (Date) getFieldValue(dictDataCoreService, "maxUpdateTime");
        assertEquals(ObjectUtils.max(dictData01.getUpdateTime(), dictData02.getUpdateTime()), maxUpdateTime);
    }

    // ========== 随机对象 ==========

    @SafeVarargs
    private static SysDictDataDO randomDictDataDO(Consumer<SysDictDataDO>... consumers) {
        Consumer<SysDictDataDO> consumer = (o) -> {
            o.setStatus(randomCommonStatus()); // 保证 status 的范围
        };
        return randomPojo(SysDictDataDO.class, ArrayUtils.append(consumer, consumers));
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/monitor/config/AdminServerConfiguration.java<|end_filename|>
package cn.iocoder.yudao.adminserver.framework.monitor.config;

import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAdminServer
public class AdminServerConfiguration {
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/framework/errorcode/package-info.java<|end_filename|>
/**
 * 错误码组件
 *
 * 将错误码缓存在内存中，同时通过定时器每 n 分钟更新
 */
package cn.iocoder.yudao.adminserver.modules.tool.framework.errorcode;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/dict/SysDictTypeMapper.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.dict;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.type.SysDictTypeExportReqVO;
import cn.iocoder.yudao.adminserver.modules.system.controller.dict.vo.type.SysDictTypePageReqVO;
import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dict.SysDictTypeDO;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface SysDictTypeMapper extends BaseMapperX<SysDictTypeDO> {

    default PageResult<SysDictTypeDO> selectPage(SysDictTypePageReqVO reqVO) {
        return selectPage(reqVO, new QueryWrapperX<SysDictTypeDO>()
                .likeIfPresent("name", reqVO.getName())
                .likeIfPresent("`type`", reqVO.getType())
                .eqIfPresent("status", reqVO.getStatus())
                .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()));
    }

    default List<SysDictTypeDO> selectList(SysDictTypeExportReqVO reqVO) {
        return selectList(new QueryWrapperX<SysDictTypeDO>()
                .likeIfPresent("name", reqVO.getName())
                .likeIfPresent("`type`", reqVO.getType())
                .eqIfPresent("status", reqVO.getStatus())
                .betweenIfPresent("create_time", reqVO.getBeginCreateTime(), reqVO.getEndCreateTime()));
    }

    default SysDictTypeDO selectByType(String type) {
        return selectOne(new QueryWrapperX<SysDictTypeDO>().eq("`type`", type));
    }

    default SysDictTypeDO selectByName(String name) {
        return selectOne(new QueryWrapperX<SysDictTypeDO>().eq("name", name));
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/mq/consumer/sms/SysSmsChannelRefreshConsumer.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.mq.consumer.sms;

import cn.iocoder.yudao.framework.mq.core.pubsub.AbstractChannelMessageListener;
import cn.iocoder.yudao.adminserver.modules.system.mq.message.sms.SysSmsChannelRefreshMessage;
import cn.iocoder.yudao.adminserver.modules.system.service.sms.SysSmsChannelService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 针对 {@link SysSmsChannelRefreshMessage} 的消费者
 *
 * @author 芋道源码
 */
@Component
@Slf4j
public class SysSmsChannelRefreshConsumer extends AbstractChannelMessageListener<SysSmsChannelRefreshMessage> {

    @Resource
    private SysSmsChannelService smsChannelService;

    @Override
    public void onMessage(SysSmsChannelRefreshMessage message) {
        log.info("[onMessage][收到 SmsChannel 刷新消息]");
        smsChannelService.initSmsClients();
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-sticky/props.js<|end_filename|>
export default {
    props: {
        // 吸顶容器到顶部某个距离的时候，进行吸顶，在H5平台，NavigationBar为44px
        offsetTop: {
            type: [String, Number],
            default: uni.$u.props.sticky.offsetTop
        },
        // 自定义导航栏的高度
        customNavHeight: {
            type: [String, Number],
            // #ifdef H5
            // H5端的导航栏属于“自定义”导航栏的范畴，因为它是非原生的，与普通元素一致
            default: 44,
            // #endif
            // #ifndef H5
            default: uni.$u.props.sticky.customNavHeight
            // #endif
        },
        // 是否开启吸顶功能
        disabled: {
            type: Boolean,
            default: uni.$u.props.sticky.disabled
        },
        // 吸顶区域的背景颜色
        bgColor: {
            type: String,
            default: uni.$u.props.sticky.bgColor
        },
        // z-index值
        zIndex: {
            type: [String, Number],
            default: uni.$u.props.sticky.zIndex
        },
        // 列表中的索引值
        index: {
            type: [String, Number],
            default: uni.$u.props.sticky.index
        }
    }
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/sms/impl/SysSmsLogCoreServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.sms.impl;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsLogDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;
import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.sms.SysSmsLogCoreMapper;
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsReceiveStatusEnum;
import cn.iocoder.yudao.coreservice.modules.system.enums.sms.SysSmsSendStatusEnum;
import cn.iocoder.yudao.coreservice.modules.system.service.sms.SysSmsLogCoreService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * 短信日志 Core Service 实现类
 *
 * @author zzf
 * @date 2021/1/25 9:25
 */
@Slf4j
@Service
public class SysSmsLogCoreServiceImpl implements SysSmsLogCoreService {

    @Resource
    private SysSmsLogCoreMapper smsLogCoreMapper;

    @Override
    public Long createSmsLog(String mobile, Long userId, Integer userType, Boolean isSend,
                             SysSmsTemplateDO template, String templateContent, Map<String, Object> templateParams) {
        SysSmsLogDO.SysSmsLogDOBuilder logBuilder = SysSmsLogDO.builder();
        // 根据是否要发送，设置状态
        logBuilder.sendStatus(Objects.equals(isSend, true) ? SysSmsSendStatusEnum.INIT.getStatus()
                : SysSmsSendStatusEnum.IGNORE.getStatus());
        // 设置手机相关字段
        logBuilder.mobile(mobile).userId(userId).userType(userType);
        // 设置模板相关字段
        logBuilder.templateId(template.getId()).templateCode(template.getCode()).templateType(template.getType());
        logBuilder.templateContent(templateContent).templateParams(templateParams).apiTemplateId(template.getApiTemplateId());
        // 设置渠道相关字段
        logBuilder.channelId(template.getChannelId()).channelCode(template.getChannelCode());
        // 设置接收相关字段
        logBuilder.receiveStatus(SysSmsReceiveStatusEnum.INIT.getStatus());

        // 插入数据库
        SysSmsLogDO logDO = logBuilder.build();
        smsLogCoreMapper.insert(logDO);
        return logDO.getId();
    }

    @Override
    public void updateSmsSendResult(Long id, Integer sendCode, String sendMsg,
                                    String apiSendCode, String apiSendMsg, String apiRequestId, String apiSerialNo) {
        SysSmsSendStatusEnum sendStatus = CommonResult.isSuccess(sendCode) ? SysSmsSendStatusEnum.SUCCESS
                : SysSmsSendStatusEnum.FAILURE;
        smsLogCoreMapper.updateById(SysSmsLogDO.builder().id(id).sendStatus(sendStatus.getStatus()).sendTime(new Date())
                .sendCode(sendCode).sendMsg(sendMsg).apiSendCode(apiSendCode).apiSendMsg(apiSendMsg)
                .apiRequestId(apiRequestId).apiSerialNo(apiSerialNo).build());
    }

    @Override
    public void updateSmsReceiveResult(Long id, Boolean success, Date receiveTime, String apiReceiveCode, String apiReceiveMsg) {
        SysSmsReceiveStatusEnum receiveStatus = Objects.equals(success, true) ? SysSmsReceiveStatusEnum.SUCCESS
                : SysSmsReceiveStatusEnum.FAILURE;
        smsLogCoreMapper.updateById(SysSmsLogDO.builder().id(id).receiveStatus(receiveStatus.getStatus()).receiveTime(receiveTime)
                .apiReceiveCode(apiReceiveCode).apiReceiveMsg(apiReceiveMsg).build());
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-rate/props.js<|end_filename|>
export default {
    props: {
        // 用于v-model双向绑定选中的星星数量
        value: {
            type: [String, Number],
            default: uni.$u.props.rate.value
        },
        // 要显示的星星数量
        count: {
            type: [String, Number],
            default: uni.$u.props.rate.count
        },
        // 是否不可选中
        disabled: {
            type: Boolean,
            default: uni.$u.props.rate.disabled
        },
        // 星星的大小，单位px
        size: {
            type: [String, Number],
            default: uni.$u.props.rate.size
        },
        // 未选中时的颜色
        inactiveColor: {
            type: String,
            default: uni.$u.props.rate.inactiveColor
        },
        // 选中的颜色
        activeColor: {
            type: String,
            default: uni.$u.props.rate.activeColor
        },
        // 星星之间的间距，单位px
        gutter: {
            type: [String, Number],
            default: uni.$u.props.rate.gutter
        },
        // 最少能选择的星星个数
        minCount: {
            type: [String, Number],
            default: uni.$u.props.rate.minCount
        },
        // 是否允许半星
        allowHalf: {
            type: Boolean,
            default: uni.$u.props.rate.allowHalf
        },
        // 选中时的图标(星星)
        activeIcon: {
            type: String,
            default: uni.$u.props.rate.activeIcon
        },
        // 未选中时的图标(星星)
        inactiveIcon: {
            type: String,
            default: uni.$u.props.rate.inactiveIcon
        },
        // 是否可以通过滑动手势选择评分
        touchable: {
            type: Boolean,
            default: uni.$u.props.rate.touchable
        }
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/tool/convert/test/ToolTestDemoConvert.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.tool.convert.test;

import java.util.*;

import cn.iocoder.yudao.framework.common.pojo.PageResult;

import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import cn.iocoder.yudao.adminserver.modules.tool.controller.test.vo.*;
import cn.iocoder.yudao.adminserver.modules.tool.dal.dataobject.test.ToolTestDemoDO;

/**
 * 字典类型 Convert
 *
 * @author 芋艿
 */
@Mapper
public interface ToolTestDemoConvert {

    ToolTestDemoConvert INSTANCE = Mappers.getMapper(ToolTestDemoConvert.class);

    ToolTestDemoDO convert(ToolTestDemoCreateReqVO bean);

    ToolTestDemoDO convert(ToolTestDemoUpdateReqVO bean);

    ToolTestDemoRespVO convert(ToolTestDemoDO bean);

    List<ToolTestDemoRespVO> convertList(List<ToolTestDemoDO> list);

    PageResult<ToolTestDemoRespVO> convertPage(PageResult<ToolTestDemoDO> page);

    List<ToolTestDemoExcelVO> convertList02(List<ToolTestDemoDO> list);

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/member/service/user/impl/MbrUserCoreServiceImpl.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.member.service.user.impl;

import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
import cn.iocoder.yudao.coreservice.modules.member.dal.mysql.user.MbrUserCoreMapper;
import cn.iocoder.yudao.coreservice.modules.member.service.user.MbrUserCoreService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * User Core Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Slf4j
public class MbrUserCoreServiceImpl implements MbrUserCoreService {

    @Resource
    private MbrUserCoreMapper userCoreMapper;

    @Override
    public MbrUserDO getUser(Long id) {
        return userCoreMapper.selectById(id);
    }

}


<|start_filename|>yudao-admin-ui/src/components/tinymce/index.js<|end_filename|>
import Index from './index.vue'

export default Index


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/steps.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:12:37
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/steps.js
 */
export default {
    // steps组件
    steps: {
        direction: 'row',
        current: 0,
        activeColor: '#3c9cff',
        inactiveColor: '#969799',
        activeIcon: '',
        inactiveIcon: '',
        dot: false
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/permission/vo/permission/SysPermissionAssignUserRoleReqVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.permission.vo.permission;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.NotNull;
import java.util.Collections;
import java.util.Set;

@ApiModel("赋予用户角色 Request VO")
@Data
public class SysPermissionAssignUserRoleReqVO {

    @ApiModelProperty(value = "角色编号", required = true, example = "1")
    @NotNull(message = "角色编号不能为空")
    private Long userId;

    @ApiModelProperty(value = "角色编号列表", example = "1,3,5")
    private Set<Long> roleIds = Collections.emptySet(); // 兜底

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/package-info.java<|end_filename|>
/**
 * 使用 MyBatis Plus 提升使用 MyBatis 的开发效率
 */
package cn.iocoder.yudao.framework.mybatis;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/permission/vo/permission/SysPermissionAssignRoleDataScopeReqVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.permission.vo.permission;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.NotNull;
import java.util.Collections;
import java.util.Set;

@ApiModel("赋予角色数据权限 Request VO")
@Data
public class SysPermissionAssignRoleDataScopeReqVO {

    @ApiModelProperty(value = "角色编号", required = true, example = "1")
    @NotNull(message = "角色编号不能为空")
    private Long roleId;

    @ApiModelProperty(value = "数据范围", required = true, example = "1", notes = "参见 SysDataScopeEnum 枚举类")
    @NotNull(message = "数据范围不能为空")
//    TODO 这里要多一个枚举校验
    private Integer dataScope;

    @ApiModelProperty(value = "部门编号列表", example = "1,3,5", notes = "只有范围类型为 DEPT_CUSTOM 时，该字段才需要")
    private Set<Long> dataScopeDeptIds = Collections.emptySet(); // 兜底

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/infra/dal/mysql/logger/InfApiAccessLogCoreMapper.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.infra.dal.mysql.logger;

import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.coreservice.modules.infra.dal.dataobject.logger.InfApiAccessLogDO;
import org.apache.ibatis.annotations.Mapper;

/**
 * API 访问日志 Mapper
 *
 * @author 芋道源码
 */
@Mapper
public interface InfApiAccessLogCoreMapper extends BaseMapperX<InfApiAccessLogDO> {
}


<|start_filename|>yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/dal/mysql/user/MbrUserMapper.java<|end_filename|>
package cn.iocoder.yudao.userserver.modules.member.dal.mysql.user;

import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import org.apache.ibatis.annotations.Mapper;

/**
 * MbrUserDO Mapper
 *
 * @author 芋道源码
 */
@Mapper
public interface MbrUserMapper extends BaseMapperX<MbrUserDO> {

    default MbrUserDO selectByMobile(String mobile) {
        return selectOne("mobile", mobile);
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/enums/job/InfJobStatusEnum.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.enums.job;

import com.google.common.collect.Sets;
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.Collections;
import java.util.Set;

import static org.quartz.impl.jdbcjobstore.Constants.*;

/**
 * 任务状态的枚举
 *
 * @author 芋道源码
 */
@Getter
@AllArgsConstructor
public enum InfJobStatusEnum {

    /**
     * 初始化中
     */
    INIT(0, Collections.emptySet()),
    /**
     * 开启
     */
    NORMAL(1, Sets.newHashSet(STATE_WAITING, STATE_ACQUIRED, STATE_BLOCKED)),
    /**
     * 暂停
     */
    STOP(2, Sets.newHashSet(STATE_PAUSED, STATE_PAUSED_BLOCKED));

    /**
     * 状态
     */
    private final Integer status;
    /**
     * 对应的 Quartz 触发器的状态集合
     */
    private final Set<String> quartzStates;

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/service/job/InfJobService.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.service.job;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.adminserver.modules.infra.controller.job.vo.job.InfJobCreateReqVO;
import cn.iocoder.yudao.adminserver.modules.infra.controller.job.vo.job.InfJobExportReqVO;
import cn.iocoder.yudao.adminserver.modules.infra.controller.job.vo.job.InfJobPageReqVO;
import cn.iocoder.yudao.adminserver.modules.infra.controller.job.vo.job.InfJobUpdateReqVO;
import cn.iocoder.yudao.adminserver.modules.infra.dal.dataobject.job.InfJobDO;
import org.quartz.SchedulerException;

import javax.validation.Valid;
import java.util.Collection;
import java.util.List;

/**
 * 定时任务 Service 接口
 *
 * @author 芋道源码
 */
public interface InfJobService {

    /**
     * 创建定时任务
     *
     * @param createReqVO 创建信息
     * @return 编号
     */
    Long createJob(@Valid InfJobCreateReqVO createReqVO) throws SchedulerException;

    /**
     * 更新定时任务
     *
     * @param updateReqVO 更新信息
     */
    void updateJob(@Valid InfJobUpdateReqVO updateReqVO) throws SchedulerException;

    /**
     * 更新定时任务的状态
     *
     * @param id 任务编号
     * @param status 状态
     */
    void updateJobStatus(Long id, Integer status) throws SchedulerException;

    /**
     * 触发定时任务
     *
     * @param id 任务编号
     */
    void triggerJob(Long id) throws SchedulerException;

    /**
     * 删除定时任务
     *
     * @param id 编号
     */
    void deleteJob(Long id) throws SchedulerException;

    /**
     * 获得定时任务
     *
     * @param id 编号
     * @return 定时任务
     */
    InfJobDO getJob(Long id);

    /**
     * 获得定时任务列表
     *
     * @param ids 编号
     * @return 定时任务列表
     */
    List<InfJobDO> getJobList(Collection<Long> ids);

    /**
     * 获得定时任务分页
     *
     * @param pageReqVO 分页查询
     * @return 定时任务分页
     */
    PageResult<InfJobDO> getJobPage(InfJobPageReqVO pageReqVO);

    /**
     * 获得定时任务列表, 用于 Excel 导出
     *
     * @param exportReqVO 查询条件
     * @return 定时任务分页
     */
    List<InfJobDO> getJobList(InfJobExportReqVO exportReqVO);

}


<|start_filename|>yudao-framework/yudao-spring-boot-starter-config/src/main/java/cn/iocoder/yudao/framework/apollo/internals/dto/ConfigRespDTO.java<|end_filename|>
package cn.iocoder.yudao.framework.apollo.internals.dto;

import lombok.Data;

import java.util.Date;

/**
 * 配置 Response DTO
 *
 * @author 芋道源码
 */
@Data
public class ConfigRespDTO {

    /**
     * 参数键名
     */
    private String key;
    /**
     * 参数键值
     */
    private String value;

    /**
     * 是否删除
     */
    private Boolean deleted;
    /**
     * 更新时间
     */
    private Date updateTime;

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/empty.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:03:27
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/empty.js
 */
export default {
    // empty组件
    empty: {
        icon: '',
        text: '',
        textColor: '#c0c4cc',
        textSize: 14,
        iconColor: '#c0c4cc',
        iconSize: 90,
        mode: 'data',
        width: 160,
        height: 160,
        show: true,
        marginTop: 0
    }

}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/infra/mq/producer/package-info.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.infra.mq.producer;


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/tool/package-info.java<|end_filename|>
/**
 * tool 包下，我们放研发工具，提升研发效率与质量。
 * 例如说：代码生成器、接口文档等等
 *
 * 缩写：tool
 */
package cn.iocoder.yudao.coreservice.modules.tool;


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/function/colorGradient.js<|end_filename|>
/**
 * 求两个颜色之间的渐变值
 * @param {string} startColor 开始的颜色
 * @param {string} endColor 结束的颜色
 * @param {number} step 颜色等分的份额
 * */
function colorGradient(startColor = 'rgb(0, 0, 0)', endColor = 'rgb(255, 255, 255)', step = 10) {
    const startRGB = hexToRgb(startColor, false) // 转换为rgb数组模式
    const startR = startRGB[0]
    const startG = startRGB[1]
    const startB = startRGB[2]

    const endRGB = hexToRgb(endColor, false)
    const endR = endRGB[0]
    const endG = endRGB[1]
    const endB = endRGB[2]

    const sR = (endR - startR) / step // 总差值
    const sG = (endG - startG) / step
    const sB = (endB - startB) / step
    const colorArr = []
    for (let i = 0; i < step; i++) {
        // 计算每一步的hex值
        let hex = rgbToHex(`rgb(${Math.round((sR * i + startR))},${Math.round((sG * i + startG))},${Math.round((sB
			* i + startB))})`)
        // 确保第一个颜色值为startColor的值
        if (i === 0) hex = rgbToHex(startColor)
        // 确保最后一个颜色值为endColor的值
        if (i === step - 1) hex = rgbToHex(endColor)
        colorArr.push(hex)
    }
    return colorArr
}

// 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式)
function hexToRgb(sColor, str = true) {
    const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
    sColor = String(sColor).toLowerCase()
    if (sColor && reg.test(sColor)) {
        if (sColor.length === 4) {
            let sColorNew = '#'
            for (let i = 1; i < 4; i += 1) {
                sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
            }
            sColor = sColorNew
        }
        // 处理六位的颜色值
        const sColorChange = []
        for (let i = 1; i < 7; i += 2) {
            sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`))
        }
        if (!str) {
            return sColorChange
        }
        return `rgb(${sColorChange[0]},${sColorChange[1]},${sColorChange[2]})`
    } if (/^(rgb|RGB)/.test(sColor)) {
        const arr = sColor.replace(/(?:\(|\)|rgb|RGB)*/g, '').split(',')
        return arr.map((val) => Number(val))
    }
    return sColor
}

// 将rgb表示方式转换为hex表示方式
function rgbToHex(rgb) {
    const _this = rgb
    const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
    if (/^(rgb|RGB)/.test(_this)) {
        const aColor = _this.replace(/(?:\(|\)|rgb|RGB)*/g, '').split(',')
        let strHex = '#'
        for (let i = 0; i < aColor.length; i++) {
            let hex = Number(aColor[i]).toString(16)
            hex = String(hex).length == 1 ? `${0}${hex}` : hex // 保证每个rgb的值为2位
            if (hex === '0') {
                hex += hex
            }
            strHex += hex
        }
        if (strHex.length !== 7) {
            strHex = _this
        }
        return strHex
    } if (reg.test(_this)) {
        const aNum = _this.replace(/#/, '').split('')
        if (aNum.length === 6) {
            return _this
        } if (aNum.length === 3) {
            let numHex = '#'
            for (let i = 0; i < aNum.length; i += 1) {
                numHex += (aNum[i] + aNum[i])
            }
            return numHex
        }
    } else {
        return _this
    }
}

/**
* JS颜色十六进制转换为rgb或rgba,返回的格式为 rgba（255，255，255，0.5）字符串
* sHex为传入的十六进制的色值
* alpha为rgba的透明度
*/
function colorToRgba(color, alpha) {
    color = rgbToHex(color)
    // 十六进制颜色值的正则表达式
    const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/
    /* 16进制颜色转为RGB格式 */
    let sColor = String(color).toLowerCase()
    if (sColor && reg.test(sColor)) {
        if (sColor.length === 4) {
            let sColorNew = '#'
            for (let i = 1; i < 4; i += 1) {
                sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
            }
            sColor = sColorNew
        }
        // 处理六位的颜色值
        const sColorChange = []
        for (let i = 1; i < 7; i += 2) {
            sColorChange.push(parseInt(`0x${sColor.slice(i, i + 2)}`))
        }
        // return sColorChange.join(',')
        return `rgba(${sColorChange.join(',')},${alpha})`
    }

    return sColor
}

export default {
    colorGradient,
    hexToRgb,
    rgbToHex,
    colorToRgba
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/luch-request/core/settle.js<|end_filename|>
/**
 * Resolve or reject a Promise based on response status.
 *
 * @param {Function} resolve A function that resolves the promise.
 * @param {Function} reject A function that rejects the promise.
 * @param {object} response The response.
 */
export default function settle(resolve, reject, response) {
    const { validateStatus } = response.config
    const status = response.statusCode
    if (status && (!validateStatus || validateStatus(status))) {
        resolve(response)
    } else {
        reject(response)
    }
}


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/errorcode/vo/SysErrorCodeExcelVO.java<|end_filename|>
package cn.iocoder.yudao.adminserver.modules.system.controller.errorcode.vo;

import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
import cn.iocoder.yudao.adminserver.modules.infra.enums.InfDictTypeConstants;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;

import java.util.Date;

/**
 * 错误码 Excel VO
 *
 * @author 芋道源码
 */
@Data
public class SysErrorCodeExcelVO {

    @ExcelProperty("错误码编号")
    private Long id;

    @ExcelProperty(value = "错误码类型", converter = DictConvert.class)
    @DictFormat(InfDictTypeConstants.ERROR_CODE_TYPE)
    private Integer type;

    @ExcelProperty("应用名")
    private String applicationName;

    @ExcelProperty("错误码编码")
    private Integer code;

    @ExcelProperty("错误码错误提示")
    private String message;

    @ExcelProperty("备注")
    private String memo;

    @ExcelProperty("创建时间")
    private Date createTime;

}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/dataobject/package-info.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject;


<|start_filename|>yudao-framework/yudao-spring-boot-starter-biz-sms/src/test/java/cn/iocoder/yudao/framework/sms/core/client/impl/yunpian/YunpianSmsClientTest.java<|end_filename|>
package cn.iocoder.yudao.framework.sms.core.client.impl.yunpian;

import cn.hutool.core.util.ReflectUtil;
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.yudao.framework.sms.core.client.SmsCommonResult;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsReceiveRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsSendRespDTO;
import cn.iocoder.yudao.framework.sms.core.client.dto.SmsTemplateRespDTO;
import cn.iocoder.yudao.framework.sms.core.enums.SmsTemplateAuditStatusEnum;
import cn.iocoder.yudao.framework.sms.core.property.SmsChannelProperties;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import com.google.common.collect.Lists;
import com.yunpian.sdk.YunpianClient;
import com.yunpian.sdk.api.SmsApi;
import com.yunpian.sdk.api.TplApi;
import com.yunpian.sdk.constant.YunpianConstant;
import com.yunpian.sdk.model.Result;
import com.yunpian.sdk.model.SmsSingleSend;
import com.yunpian.sdk.model.Template;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;

import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
import static com.yunpian.sdk.constant.Code.OK;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

/**
 * 对 {@link YunpianSmsClient} 的单元测试
 *
 * @author 芋道源码
 */
public class YunpianSmsClientTest extends BaseMockitoUnitTest {

    private final SmsChannelProperties properties = new SmsChannelProperties()
            .setApiKey(randomString()); // 随机一个 apiKey，避免构建报错

    @InjectMocks
    private final YunpianSmsClient smsClient = new YunpianSmsClient(properties);

    @Mock
    private YunpianClient client;

    @Test
    public void testDoInit() {
        // 准备参数
        // mock 方法

        // 调用
        smsClient.doInit();
        // 断言
        assertNotEquals(client, ReflectUtil.getFieldValue(smsClient, "client"));
        verify(client, times(1)).close();
    }

    @Test
    @SuppressWarnings("unchecked")
    public void testDoSendSms() throws Throwable {
        // 准备参数
        Long sendLogId = randomLongId();
        String mobile = randomString();
        String apiTemplateId = randomString();
        List<KeyValue<String, Object>> templateParams = Lists.newArrayList(
                new KeyValue<>("code", 1234), new KeyValue<>("op", "login"));
        // mock sms 方法
        SmsApi smsApi = mock(SmsApi.class);
        when(client.sms()).thenReturn(smsApi);
        // mock tpl_single_send 方法
        Map<String, String> request = new HashMap<>();
        request.put(YunpianConstant.MOBILE, mobile);
        request.put(YunpianConstant.TPL_ID, apiTemplateId);
        request.put(YunpianConstant.TPL_VALUE, "#code#=1234&#op#=login");
        request.put(YunpianConstant.UID, String.valueOf(sendLogId));
        request.put(YunpianConstant.CALLBACK_URL, properties.getCallbackUrl());
        Result<SmsSingleSend> responseResult = randomPojo(Result.class, SmsSingleSend.class,
                o -> o.setCode(OK)); // API 发送成功的 code
        when(smsApi.tpl_single_send(eq(request))).thenReturn(responseResult);

        // 调用
        SmsCommonResult<SmsSendRespDTO> result = smsClient.doSendSms(sendLogId, mobile,
                apiTemplateId, templateParams);
        // 断言
        assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode());
        assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
        assertNull(result.getApiRequestId());
        // 断言结果
        assertEquals(String.valueOf(responseResult.getData().getSid()), result.getData().getSerialNo());
    }

    @Test
    public void testDoParseSmsReceiveStatus() throws Throwable {
        // 准备参数
        String text = "[{\"sid\":9527,\"uid\":1024,\"user_receive_time\":\"2014-03-17 22:55:21\",\"error_msg\":\"\",\"mobile\":\"15205201314\",\"report_status\":\"SUCCESS\"}]";
        // mock 方法

        // 调用

        // 断言
        // 调用
        List<SmsReceiveRespDTO> statuses = smsClient.doParseSmsReceiveStatus(text);
        // 断言
        assertEquals(1, statuses.size());
        assertTrue(statuses.get(0).getSuccess());
        assertEquals("", statuses.get(0).getErrorCode());
        assertNull(statuses.get(0).getErrorMsg());
        assertEquals("15205201314", statuses.get(0).getMobile());
        assertEquals(DateUtils.buildTime(2014, 3, 17, 22, 55, 21), statuses.get(0).getReceiveTime());
        assertEquals("9527", statuses.get(0).getSerialNo());
        assertEquals(1024L, statuses.get(0).getLogId());
    }

    @Test
    @SuppressWarnings("unchecked")
    public void testDoGetSmsTemplate() throws Throwable {
        // 准备参数
        String apiTemplateId = randomString();
        // mock tpl 方法
        TplApi tplApi = mock(TplApi.class);
        when(client.tpl()).thenReturn(tplApi);
        // mock get 方法
        Map<String, String> request = new HashMap<>();
        request.put(YunpianConstant.APIKEY, properties.getApiKey());
        request.put(YunpianConstant.TPL_ID, apiTemplateId);
        Result<List<Template>> responseResult = randomPojo(Result.class, List.class, o -> {
            o.setCode(OK); // API 发送成功的 code
            o.setData(randomPojoList(Template.class, t -> t.setCheck_status("SUCCESS")));
        });
        when(tplApi.get(eq(request))).thenReturn(responseResult);

        // 调用
        SmsCommonResult<SmsTemplateRespDTO> result = smsClient.doGetSmsTemplate(apiTemplateId);
        // 断言
        assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode());
        assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
        assertNull(result.getApiRequestId());
        // 断言结果
        Template template = responseResult.getData().get(0);
        assertEquals(template.getTpl_id().toString(), result.getData().getId());
        assertEquals(template.getTpl_content(), result.getData().getContent());
        assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(), result.getData().getAuditStatus());
        assertEquals(template.getReason(), result.getData().getAuditReason());
    }

    @Test
    public void testConvertSmsTemplateAuditStatus() {
        assertEquals(SmsTemplateAuditStatusEnum.CHECKING.getStatus(),
                smsClient.convertSmsTemplateAuditStatus("CHECKING"));
        assertEquals(SmsTemplateAuditStatusEnum.SUCCESS.getStatus(),
                smsClient.convertSmsTemplateAuditStatus("SUCCESS"));
        assertEquals(SmsTemplateAuditStatusEnum.FAIL.getStatus(),
                smsClient.convertSmsTemplateAuditStatus("FAIL"));
        assertThrows(IllegalArgumentException.class, () -> smsClient.convertSmsTemplateAuditStatus("test"),
                "未知审核状态(test)");
    }

    @Test
    public void testInvoke_throwable() {
        // 准备参数
        Supplier<Result<Object>> requestConsumer =
                () -> new Result<>().setThrowable(new NullPointerException());
        // mock 方法

        // 调用，并断言异常
        assertThrows(NullPointerException.class,
                () -> smsClient.invoke(requestConsumer, null));
    }

    @Test
    @SuppressWarnings("unchecked")
    public void testInvoke_success() throws Throwable {
        // 准备参数
        Result<SmsSingleSend> responseResult = randomPojo(Result.class, SmsSingleSend.class, o -> o.setCode(OK));
        Supplier<Result<SmsSingleSend>> requestConsumer = () -> responseResult;
        Function<SmsSingleSend, SmsSendRespDTO> responseConsumer =
                smsSingleSend -> new SmsSendRespDTO().setSerialNo(String.valueOf(responseResult.getData().getSid()));
        // mock 方法

        // 调用
        SmsCommonResult<SmsSendRespDTO> result = smsClient.invoke(requestConsumer, responseConsumer);
        // 断言
        assertEquals(String.valueOf(responseResult.getCode()), result.getApiCode());
        assertEquals(responseResult.getMsg() + " => " + responseResult.getDetail(), result.getApiMsg());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getCode(), result.getCode());
        assertEquals(GlobalErrorCodeConstants.SUCCESS.getMsg(), result.getMsg());
        assertNull(result.getApiRequestId());
        assertEquals(String.valueOf(responseResult.getData().getSid()), result.getData().getSerialNo());
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-transition/props.js<|end_filename|>
export default {
    props: {
        // 是否展示组件
        show: {
            type: Boolean,
            default: uni.$u.props.transition.show
        },
        // 使用的动画模式
        mode: {
            type: String,
            default: uni.$u.props.transition.mode
        },
        // 动画的执行时间，单位ms
        duration: {
            type: [String, Number],
            default: uni.$u.props.transition.duration
        },
        // 使用的动画过渡函数
        timingFunction: {
            type: String,
            default: uni.$u.props.transition.timingFunction
        }
    }
}


<|start_filename|>yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/monitor/TracerUtils.java<|end_filename|>
package cn.iocoder.yudao.framework.common.util.monitor;

import org.apache.skywalking.apm.toolkit.trace.TraceContext;

/**
 * 链路追踪工具类
 *
 * 考虑到每个 starter 都需要用到该工具类，所以放到 common 模块下的 util 包下
 *
 * @author 芋道源码
 */
public class TracerUtils {

    /**
     * 私有化构造方法
     */
    private TracerUtils() {
    }

    /**
     * 获得链路追踪编号，直接返回 SkyWalking 的 TraceId。
     * 如果不存在的话为空字符串！！！
     *
     * @return 链路追踪编号
     */
    public static String getTraceId() {
        return TraceContext.traceId();
    }

}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/libs/config/props/swipterIndicator.js<|end_filename|>
/*
 * @Author       : LQ
 * @Description  :
 * @version      : 1.0
 * @Date         : 2021-08-20 16:44:21
 * @LastAuthor   : LQ
 * @lastTime     : 2021-08-20 17:22:07
 * @FilePath     : /u-view2.0/uview-ui/libs/config/props/swiperIndicator.js
 */
export default {
    // swiperIndicator 组件
    swiperIndicator: {
        length: 0,
        current: 0,
        indicatorActiveColor: '',
        indicatorInactiveColor: '',
		indicatorMode: 'line'
    }
}


<|start_filename|>yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/sms/SysSmsTemplateCoreService.java<|end_filename|>
package cn.iocoder.yudao.coreservice.modules.system.service.sms;

import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.sms.SysSmsTemplateDO;

import java.util.Map;

/**
 * 短信模板 Core Service 接口
 *
 * @author 芋道源码
 */
public interface SysSmsTemplateCoreService {

    /**
     * 初始化短信模板的本地缓存
     */
    void initLocalCache();

    /**
     * 获得短信模板，从缓存中
     *
     * @param code 模板编码
     * @return 短信模板
     */
    SysSmsTemplateDO getSmsTemplateByCodeFromCache(String code);

    /**
     * 格式化短信内容
     *
     * @param content 短信模板的内容
     * @param params 内容的参数
     * @return 格式化后的内容
     */
    String formatSmsTemplateContent(String content, Map<String, Object> params);

}


<|start_filename|>yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/validation/package-info.java<|end_filename|>
/**
 * 使用 Hibernate Validator 实现参数校验
 */
package cn.iocoder.yudao.framework.common.validation;


<|start_filename|>yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/framework/codegen/package-info.java<|end_filename|>
/**
 * 代码生成器
 */
package cn.iocoder.yudao.adminserver.modules.system.framework.codegen;


<|start_filename|>yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalResponseBodyHandler.java<|end_filename|>
package cn.iocoder.yudao.framework.web.core.handler;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * 全局响应结果（ResponseBody）处理器
 *
 * 不同于在网上看到的很多文章，会选择自动将 Controller 返回结果包上 {@link CommonResult}，
 * 在 onemall 中，是 Controller 在返回时，主动自己包上 {@link CommonResult}。
 * 原因是，GlobalResponseBodyHandler 本质上是 AOP，它不应该改变 Controller 返回的数据结构
 *
 * 目前，GlobalResponseBodyHandler 的主要作用是，记录 Controller 的返回结果，
 * 方便 {@link cn.iocoder.yudao.framework.apilog.core.filter.ApiAccessLogFilter} 记录访问日志
 */
@ControllerAdvice
public class GlobalResponseBodyHandler implements ResponseBodyAdvice {

    @Override
    @SuppressWarnings("NullableProblems") // 避免 IDEA 警告
    public boolean supports(MethodParameter returnType, Class converterType) {
        if (returnType.getMethod() == null) {
            return false;
        }
        // 只拦截返回结果为 CommonResult 类型
        return returnType.getMethod().getReturnType() == CommonResult.class;
    }

    @Override
    @SuppressWarnings("NullableProblems") // 避免 IDEA 警告
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        // 记录 Controller 结果
        WebFrameworkUtils.setCommonResult(((ServletServerHttpRequest) request).getServletRequest(), (CommonResult<?>) body);
        return body;
    }

}


<|start_filename|>yudao-admin-ui/src/api/system/permission.js<|end_filename|>
import request from '@/utils/request'

// 查询角色拥有的菜单数组
export function listRoleMenus(roleId) {
  return request({
    url: '/system/permission/list-role-resources?roleId=' + roleId,
    method: 'get'
  })
}

// 赋予角色菜单
export function assignRoleMenu(data) {
  return request({
    url: '/system/permission/assign-role-menu',
    method: 'post',
    data: data
  })
}

// 查询用户拥有的角色数组
export function listUserRoles(userId) {
  return request({
    url: '/system/permission/list-user-roles?userId=' + userId,
    method: 'get'
  })
}

// 赋予用户角色
export function assignUserRole(data) {
  return request({
    url: '/system/permission/assign-user-role',
    method: 'post',
    data: data
  })
}

// 赋予角色数据权限
export function assignRoleDataScope(data) {
  return request({
    url: '/system/permission/assign-role-data-scope',
    method: 'post',
    data: data
  })
}


<|start_filename|>yudao-vue-ui/uni_modules/uview-ui/components/u-count-down/props.js<|end_filename|>
export default {
    props: {
        // 倒计时时长，单位ms
        time: {
            type: [String, Number],
            default: uni.$u.props.countDown.time
        },
        // 时间格式，DD-日，HH-时，mm-分，ss-秒，SSS-毫秒
        format: {
            type: String,
            default: uni.$u.props.countDown.format
        },
        // 是否自动开始倒计时
        autoStart: {
            type: Boolean,
            default: uni.$u.props.countDown.autoStart
        },
        // 是否展示毫秒倒计时
        millisecond: {
            type: Boolean,
            default: uni.$u.props.countDown.millisecond
        }
    }
}
