1 员工端审批

  • 需求分析

1.1 查询审批分类与模板接口

  • 需求分析
  • 企业微信审批模板template_id_java

  • 返回的数据格式(ProcessType实体类)
  • 同时返回审批类型和所有的审批模板processTemplateList
@TableField(exist = false)
	private List<ProcessTemplate> processTemplateList;
  • 在controllerr下新建一个包api,专门用来存放客户端的代码
  • com.atguigu.serviceoa.process.controller.api.ProcessApiController
package com.atguigu.serviceoa.process.controller.api;
import com.atguigu.common.result.Result;
import com.atguigu.enity.model.process.ProcessType;
import com.atguigu.serviceoa.process.service.ProcessTemplateService;
import com.atguigu.serviceoa.process.service.ProcessTypeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@Api(tags = "员工端审批流管理")
@RestController
@RequestMapping(value="/admin/process")
@CrossOrigin  //解决跨域(访问协议、IP地址、端口号有一个不一样)
public class ProcessApiController {
    @Autowired
    private ProcessTypeService processTypeService;

    @ApiOperation(value = "获取全部审批分类及审批分类的所有模板")
    @GetMapping("findProcessType")
    public Result findProcessType() {

        List<ProcessType> list= processTypeService.findProcessType();
        return Result.ok(list);

    }
}
  • com.atguigu.serviceoa.process.service.ProcessTypeService
// 获取全部审批分类及审批分类的所有模板
    List<ProcessType> findProcessType();
  • com.atguigu.serviceoa.process.service.impl.ProcessTypeServiceImpl
@Autowired
    private ProcessTemplateService processTemplateService;

    // 获取全部审批分类及审批分类的所有模板
    @Override
    public List<ProcessType> findProcessType() {

        // 1 查询所有审批分类,返回list集合
        List<ProcessType> processTypeList = baseMapper.selectList(null);

        // 2 遍历list集合,返回每一个审批分类
        processTypeList.stream().forEach( item -> {

            // 3 得到每一个审批分类,根据审批分类ID查询对应的审批模板
            LambdaQueryWrapper<ProcessTemplate> lqw = new LambdaQueryWrapper<>();
            lqw.eq(ProcessTemplate::getProcessTypeId,item.getId());
            List<ProcessTemplate> processTemplateList = processTemplateService.list(lqw);

            // 4 把审批模板数据封装到对应的审批的分类中
            item.setProcessTemplateList(processTemplateList);
        });

        // 5 返回数据
        return processTypeList;
    }
  • 前端整合:复制粘贴即可

1.2 审批申请

1.3 启动流程实例

1.3.1 修改认证过滤器

  • 创建用户信息帮助类,获取当前用户信息帮助类
  • com.atguigu.common.springSecurity.custom.LoginUserInfoHelper
package com.atguigu.common.springSecurity.custom;
/**
 * 获取当前用户信息帮助类
 */
public class LoginUserInfoHelper {
    private static ThreadLocal<Long> userId = new ThreadLocal<Long>();
    private static ThreadLocal<String> username = new ThreadLocal<String>();

    public static void setUserId(Long _userId) {
        userId.set(_userId);
    }
    public static Long getUserId() {
        return userId.get();
    }
    public static void removeUserId() {
        userId.remove();
    }
    public static void setUsername(String _username) {
        username.set(_username);
    }
    public static String getUsername() {
        return username.get();
    }
    public static void removeUsername() {
        username.remove();
    }
}
  • 修改过滤器TokenAuthenticationFilter
  • 通过ThreadLocal记录当前登录人信息
// token不为空
        if (!StringUtils.isEmpty(token)) {
            String username = JwtHelper.getUsername(token);
            // usename不为空 返回返回封装的对象
            if (!StringUtils.isEmpty(username)) {

                //通过ThreadLocal记录当前登录人信息
                LoginUserInfoHelper.setUserId(JwtHelper.getUserId(token));
                LoginUserInfoHelper.setUsername(username);

                // 通过用户名称从redis中获取权限数据
                String authorString = (String) redisTemplate.opsForValue().get(username);
  • 封装启动流程对象
  • com.atguigu.enity.vo.process.ProcessFormVo
package com.atguigu.enity.vo.process;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel(description = "流程表单")
public class ProcessFormVo {

	@ApiModelProperty(value = "审批模板id")
	private Long processTemplateId;

	@ApiModelProperty(value = "审批类型id")
	private Long processTypeId;

	@ApiModelProperty(value = "表单值")
	private String formValues;

}
  • 前端返回的数据格式

企业微信审批模板template_id_java_02

  • com.atguigu.serviceoa.process.controller.api.ProcessApiController
@ApiOperation(value = "启动流程实例")
    @PostMapping("/startUp")
    public Result start(@RequestBody ProcessFormVo processFormVo) {
        processService.startUp(processFormVo);
        return Result.ok();
    }
  • com.atguigu.serviceoa.process.service.ProcessService
// 启动流程实例
    void startUp(ProcessFormVo processFormVo);
  • com.atguigu.serviceoa.process.service.impl.ProcessServiceImpl
// 启动流程实例
    @Override
    public void startUp(ProcessFormVo processFormVo) {
        // 1 根据当前用户ID获取用户信息
        // 用户ID保存在LoginUserInfoHelper中,直接取就好
        SysUser sysUser = sysUserService.getById(LoginUserInfoHelper.getUserId());

        // 2 根据审批模板id查询审批模板信息
        ProcessTemplate processTemplate = processTemplateService.getById(processFormVo.getProcessTemplateId());

        // 3 保存用户提交的审批信息到业务表:oa-process
        // 定义一个新的oa_process
        Process process = new Process();
        // 使用一个工具类  processFormVo的值复制到process 对应值可以全部复制进去
        BeanUtils.copyProperties(processFormVo,process);
        // 其他值  一个一个set
        // 加空格 转化为string
        String workNo = System.currentTimeMillis() + "";
        process.setProcessCode(workNo);
        process.setUserId(LoginUserInfoHelper.getUserId());
        process.setFormValues(processFormVo.getFormValues());
        process.setTitle(sysUser.getName() + "发起" + processTemplate.getName() + "申请");
        process.setStatus(1);
        baseMapper.insert(process);


        // 4 启动流程实例
        // 4.1 流程定义key
        String processDefinitionKey = processTemplate.getProcessDefinitionKey();
        // 4.2 业务Key  用processId表示  Long类型转化为String类型
        String businessId = String.valueOf(process.getId());
        // 4.3 流程参数 form表单数据-json格式,转化为map集合
        // 后台是json数据格式,传到前台变成了string
        String formValues = processFormVo.getFormValues();
        // Object格式逆转为JOSN格式
        JSONObject jsonObject = JSON.parseObject(formValues);
        // 取出JOSN数据中  formData对应的数据
        JSONObject formData = jsonObject.getJSONObject("formData");
        // 遍历formData得到里面的数据,封装集合
        Map<String,Object> map = new HashMap<>();
        // 这段代码在复习一下java基础
        for (Map.Entry<String, Object> entry : formData.entrySet()) {
            map.put(entry.getKey(), entry.getValue());
        }
        // 定义一个新的map,key:data  value:map
        Map<String,Object> variables = new HashMap<>();
        variables.put("data", map);
        // 重载了很多方法,这次我们用包含三个参数的,启动流程实例
        // 第二个参数必须是string类型
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey
                (processDefinitionKey,businessId,variables);

        // 5 查询下一个审批人
        // 审批人可能有多个
        // Task的包不要导错啦
        // 根据id返回当前任务列表  activity的知识点
        List<Task> taskList = this.getCurrentTaskList(processInstance.getId());
        // 遍历任务列表 返回下一个审批人集合
        List<Object> nameList = taskList.stream().map(item -> {
            // 从任务列表中得到审批人是谁
            String assignee = item.getAssignee();
            // 自己之前写的一个方法 通过用户名取得用户对象
            SysUser sysUserByUserName = sysUserService.getUserByUsername(assignee);
            // name里面才是真实姓名
            String name = sysUserByUserName.getName();
            return name;
        }).collect(Collectors.toList());

        //TODO 6 推送消息到微信公众号

        // 7 业务和流程关联 更新oa-process,保存最完整的数据
        // 流程实例id
        process.setProcessInstanceId(processInstance.getId());
        // 描述信息  nameList变成数组,并且用逗号隔开
        process.setDescription("等待" + StringUtils.join(nameList.toArray(), ",") + "审批");
        baseMapper.updateById(process);
    }

    // 根据id返回当前任务列表
    private List<Task> getCurrentTaskList(String id) {
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(id).list();
        return tasks;
    }

1.4 记录提交记录

  • 需求分析
  • 代码生成器生成service和mapper,不需要controller
  • com.atguigu.serviceoa.process.service.ProcessRecordService
package com.atguigu.serviceoa.process.service;
import com.atguigu.enity.model.process.ProcessRecord;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.stereotype.Service;

/**
 * 审批记录 服务类
 */
@Service
public interface ProcessRecordService extends IService<ProcessRecord> {

    // 记录提交记录
    void record(Long processId,Integer status,String description);

}
  • com.atguigu.serviceoa.process.service.impl.ProcessRecordServiceImpl
package com.atguigu.serviceoa.process.service.impl;

import com.atguigu.common.springSecurity.custom.LoginUserInfoHelper;
import com.atguigu.enity.model.process.ProcessRecord;
import com.atguigu.enity.model.system.SysUser;
import com.atguigu.serviceoa.auth.service.SysUserService;
import com.atguigu.serviceoa.process.mapper.ProcessRecordMapper;
import com.atguigu.serviceoa.process.service.ProcessRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 审批记录 服务实现类
 */
@Service
public class ProcessRecordServiceImpl extends ServiceImpl<ProcessRecordMapper, ProcessRecord> implements ProcessRecordService {

    @Autowired
    private SysUserService sysUserService;

    @Override
    public void record(Long processId, Integer status, String description) {
        // 定义一个实例对象
        ProcessRecord processRecord = new ProcessRecord();

        // 获取当前登录用户ID
        Long userId = LoginUserInfoHelper.getUserId();
        SysUser sysUser = sysUserService.getById(userId);

        // 往里面set数据
        processRecord.setProcessId(processId);
        processRecord.setStatus(status);
        processRecord.setDescription(description);
        // 放的应该是发出申请的人的信息
        processRecord.setOperateUserId(userId);
        processRecord.setOperateUser(sysUser.getName());

        baseMapper.insert(processRecord);
    }
}
  • 修改com.atguigu.serviceoa.process.service.impl.ProcessServiceImpl
  • 加上第八步
// 7 业务和流程关联 更新oa-process,保存最完整的数据
        // 流程实例id
        process.setProcessInstanceId(processInstance.getId());
        // 描述信息  nameList变成数组,并且用逗号隔开
        process.setDescription("等待" + StringUtils.join(nameList.toArray(), ",") + "审批");
        baseMapper.updateById(process);

        // 8 记录操作审批记录
        // TODO 这里有个疑问:process是我们自己set的,还没有存入数据库,会带有id吗
        processRecordService.record(process.getId(),1,"发起申请");

1.5 待处理列表

  • 启动流程后,审批人就可以在待处理列表中获取审批列表了

1.6 执行审批

  • com.atguigu.serviceoa.process.service.ProcessService
// 执行审批
    void approve(ApprovalVo approvalVo);
  • com.atguigu.serviceoa.process.service.impl.ProcessServiceImpl
// 执行审批
    public void approve(ApprovalVo approvalVo) {

        // 1 从approvalVo中获取任务id 根据任务id获取流程变量
        String taskId = approvalVo.getTaskId();
        // TODO 这一段不太懂
        Map<String, Object> variables = taskService.getVariables(taskId);
        for (Map.Entry<String, Object> entry : variables.entrySet()) {
            System.out.println("Key = " + entry.getKey());
            System.out.println("Value = " + entry.getValue());
        }

        // 2 判断审批状态值
        if (approvalVo.getStatus() == 1){
            // 2.1 状态值为2 审批通过
            // 如果有别的流程变量 可以继续设置 我们这里没有 就是定义一个结构
            Map<String, Object> variable = new HashMap<String, Object>();
            taskService.complete(taskId, variable);
        } else {
            // 2.2 状态值为-1 审批驳回  流程直接结束
            this.endTask(taskId);
        }

        // 3 记录审批过程相关信息 oa_prrocess_record
        // 这个方法已经写过了 传递三个参数
        processRecordService.record(
                approvalVo.getProcessId(),
                approvalVo.getStatus(),
                approvalVo.getDescription());

        // 4 查询下一个审批人(更新流程表记录) process表记录
        Process process = baseMapper.selectById(approvalVo.getProcessId());
        // 根据流程实例Id查询任务(前面写过)
        List<Task> currentTaskList = this.getCurrentTaskList(process.getProcessInstanceId());
        // 如果查询出来的任务为空 说明没有下一个审批人
        if (!CollectionUtils.isEmpty(currentTaskList)){

            // 一个任务可能有多人审批
            List<String> assignList = new ArrayList<>();
            for (Task task : currentTaskList) {

                // 这里的assignee对应的是sysuser的username
                String assignee = task.getAssignee();
                // 根据username查询用户对象
                SysUser sysUser = sysUserService.getUserByUsername(assignee);
                assignList.add(sysUser.getName());

                // TODO 微信公众号推送
            }

            // (更新流程表记录) process表记录
            process.setDescription("等待" + StringUtils.join(assignList.toArray(), ",") + "审批");
            process.setStatus(1);

        } else {
            // 没有审批任务了 审批完成
            if (approvalVo.getStatus().intValue()== 1){
                process.setStatus(2);
                process.setDescription("审批完成(通过)");
            } else {
                process.setStatus(-1);
                process.setDescription("审批完成(驳回)");
            }
        }

        // 做最后的更新
        baseMapper.updateById(process);


    }
  • com.atguigu.serviceoa.process.controller.ProcessController
@ApiOperation(value = "执行审批")
    @PostMapping("approve")
    public Result approve(@RequestBody ApprovalVo approvalVo) {
        processService.approve(approvalVo);
        return Result.ok();
    }
  • 状态值为-1 审批驳回 流程直接结束
  • com.atguigu.serviceoa.process.service.impl.ProcessServiceImpl
// 状态是-1 直接结束流程 根据任务ID直接结束流程
    // 这个代码 直接复制粘贴即可
    private void endTask(String taskId) {

        //  1 根据任务Id获取当前任务对象 Task
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();

        // 2 获取流程定义模型  BpmnModel
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());

        // 3 获取结束流向节点
        List endEventList = bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class);
        if(CollectionUtils.isEmpty(endEventList)) {
            return;
        }
        FlowNode endFlowNode = (FlowNode) endEventList.get(0);

        // 4 获取当前流向节点
        FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(task.getTaskDefinitionKey());

        // 5 清理当前流动方向
        //  临时保存当前活动的原始方向
        List originalSequenceFlowList = new ArrayList<>();
        originalSequenceFlowList.addAll(currentFlowNode.getOutgoingFlows());
        //  清理活动方向
        currentFlowNode.getOutgoingFlows().clear();

        // 6 创建新流向
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newSequenceFlowId");
        newSequenceFlow.setSourceFlowElement(currentFlowNode);
        newSequenceFlow.setTargetFlowElement(endFlowNode);
        List newSequenceFlowList = new ArrayList<>();
        newSequenceFlowList.add(newSequenceFlow);

        // 7 当前节点指向新方向
        currentFlowNode.setOutgoingFlows(newSequenceFlowList);

        // 8 完成当前任务
        taskService.complete(task.getId());

    }

1.7 查询已处理信息

  • 需求分析
  • 还是写一个分页查询(练习一下)
  • com.atguigu.serviceoa.process.controller.ProcessController
@ApiOperation(value = "查询已处理已处理")
    @GetMapping("/findProcessed/{page}/{limit}")
    public Result findProcessed(@PathVariable Long page, @PathVariable Long limit) {

        Page<Process> pageParam = new Page<>(page, limit);
        // 查询已处理
        IPage<ProcessVo> pageModel = processService.findProcessed(pageParam);
        return Result.ok(pageModel);
    }
  • com.atguigu.serviceoa.process.service.ProcessService
// 查询已处理
    IPage<ProcessVo> findProcessed(Page<Process> pageParam);
  • com.atguigu.serviceoa.process.service.impl.ProcessServiceImpl
// 查询已处理
    public IPage<ProcessVo> findProcessed(Page<Process> pageParam) {

        // 1 封装查询条件
        HistoricTaskInstanceQuery query = historyService
                .createHistoricTaskInstanceQuery()
                // 根据当前登录的用户名
                .taskAssignee(LoginUserInfoHelper.getUsername())
                .finished()
                .orderByTaskCreateTime()
                .desc();

        // 2 调用方法分页查询 返回List集合
        // query自带的方法listPage
        // listPage有两个参数:
        // 第一个参数:开始位置  (当前页面-1)*,每页记录数
        int begin = (int) ((pageParam.getCurrent() - 1) * pageParam.getSize());
        // 第二个参数:每页显示记录数
        int size = (int) pageParam.getSize();
        // 用的是listPage 返回List<HistoricTaskInstance>集合
        List<HistoricTaskInstance> list = query.listPage(begin, size);

        // 3 遍历返回的List集合 封装为IPage<ProcessVo>
        // 先定义一个List<ProcessVo>的空集合
        List<ProcessVo> processVoList = new ArrayList<>();
        for (HistoricTaskInstance item : list) {
            // 获取流程实例ID
            String processInstanceId = item.getProcessInstanceId();
            // 根据流程实例ID获取对应的process信息
            LambdaQueryWrapper<Process> lqw = new LambdaQueryWrapper<>();
            lqw.eq(Process::getProcessInstanceId,processInstanceId);
            Process process = baseMapper.selectOne(lqw);

            // 把process转化为processVo
            ProcessVo processVo = new ProcessVo();
            BeanUtils.copyProperties(process,processVo);

            // 放到List 中
            processVoList.add(processVo);
        }

        // 4 IPage封装分页查询所有数据,返回
        // 返回的数据总条数
        long count = query.count();
        IPage<ProcessVo> pageModel = new Page<ProcessVo>(pageParam.getCurrent(),pageParam.getSize(),count);
        pageModel.setRecords(processVoList);
        return pageModel;
    }

1.8 查询已发起

  • 根据当前用户ID查询oa_process表
  • 与之前的一个方法很像:
  • com.atguigu.serviceoa.process.mapper.ProcessMapper
// 获取审批管理分页列表
    // @Param("vo"):在xml文件中processQueryVo参数就叫做vo
    IPage<ProcessVo> selectPage(Page<ProcessVo> page, @Param("vo") ProcessQueryVo processQueryVo);
  • com.atguigu.serviceoa.process.controller.ProcessController
@ApiOperation(value = "查询已发起")
    @GetMapping("/findStarted/{page}/{limit}")
    public Result findStarted(
            @ApiParam(name = "page", value = "当前页码", required = true)
            @PathVariable Long page,

            @ApiParam(name = "limit", value = "每页记录数", required = true)
            @PathVariable Long limit) {
        Page<ProcessVo> pageParam = new Page<>(page, limit);
        IPage<ProcessVo> pageModel = processService.findStarted(pageParam);
        return Result.ok(pageModel);
    }
  • com.atguigu.serviceoa.process.service.ProcessService
// 查询已发起
    IPage<ProcessVo> findStarted(Page<ProcessVo> pageParam);
  • com.atguigu.serviceoa.process.service.impl.ProcessServiceImpl
@Override
    // 查询已发起
    // 与之前的一个方法很像
    public IPage<ProcessVo> findStarted(Page<ProcessVo> pageParam) {
        ProcessQueryVo processQueryVo = new ProcessQueryVo();
        // 一共有三个条件  这里只有一个条件userID
        processQueryVo.setUserId(LoginUserInfoHelper.getUserId());
        IPage<ProcessVo> pageModel = baseMapper.selectPage(pageParam, processQueryVo);
        return pageModel;
    }

1.9 用户基本信息

  • com.atguigu.serviceoa.process.controller.ProcessController
@ApiOperation(value = "获取当前用户基本信息")
    @GetMapping("getCurrentUser")
    public Result getCurrentUser() {
        Map<String,Object> map = sysUserService.getCurrentUser();
        return Result.ok(map);
    }
  • com.atguigu.serviceoa.auth.service.SysUserService
// 获取当前用户基本信息
    Map<String, Object> getCurrentUser();
  • com.atguigu.serviceoa.auth.service.impl.SysUserServiceImpl
@Override
    // 获取当前用户基本信息
    public Map<String, Object> getCurrentUser() {
        SysUser sysUser = baseMapper.selectById(LoginUserInfoHelper.getUserId());
        Map<String, Object> map = new HashMap<>();
        map.put("name", sysUser.getName());
        map.put("phone", sysUser.getPhone());
        return map;
    }

2 微信小程序

2.1 功能说明

  • 员工端使用微信公众号完成审批操作,涉及到的功能包含:自定义菜单、授权登录、消息
  • 微信公众号一级菜单为:审批列表、审批中心、我的
  • 员工关注公众号,员工第一次登录微信公众号,通过微信授权登录进行员工账号绑定
  • 员工通过公众号提交审批和审批信息,系统根据微信公众号推送审批信息,及时反馈审批过程
  • 公众号一级菜单,数据库默认初始化(审批列表、审批中心、我的)

2.2 公众号菜单CRUD

2.2.1 代码生成器细节知识——去掉表格前缀

// 5、策略配置
        StrategyConfig strategy = new StrategyConfig();

        // 指定表的名称
        strategy.setInclude("wechat_menu");

        // 去除数据库表格的的前缀
        strategy.setTablePrefix("wechat_");

2.2.2 MenuVo——树形结构

  • 多了一个属性,menu中没有
  • children中就是二级三级菜单
@ApiModelProperty(value = "下级")
    @TableField(exist = false)
    private List<MenuVo> children;

2.2.3 具体代码

  • com.atguigu.serviceoa.wechat.controller.MenuController
package com.atguigu.serviceoa.wechat.controller;
import com.atguigu.common.result.Result;
import com.atguigu.enity.model.wechat.Menu;
import com.atguigu.enity.vo.wechat.MenuVo;
import com.atguigu.serviceoa.wechat.service.MenuService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;

@RestController
@RequestMapping("/admin/wechat/menu")
@Slf4j
public class MenuController {

    @Autowired
    private MenuService menuService;

    //@PreAuthorize("hasAuthority('bnt.menu.list')")
    @ApiOperation(value = "获取全部菜单——树形结构")
    @GetMapping("findMenuInfo")
    public Result findMenuInfo() {
        List<MenuVo> menuVoList = menuService.findMenuInfo();
        return Result.ok(menuVoList);
    }

    //@PreAuthorize("hasAuthority('bnt.menu.list')")
    @ApiOperation(value = "根据ID获取菜单对象")
    @GetMapping("get/{id}")
    public Result get(@PathVariable Long id) {
        Menu menu = menuService.getById(id);
        return Result.ok(menu);
    }

    //@PreAuthorize("hasAuthority('bnt.menu.add')")
    @ApiOperation(value = "新增")
    @PostMapping("save")
    public Result save(@RequestBody Menu menu) {
        menuService.save(menu);
        return Result.ok();
    }

    //@PreAuthorize("hasAuthority('bnt.menu.update')")
    @ApiOperation(value = "修改")
    @PutMapping("update")
    public Result updateById(@RequestBody Menu menu) {
        menuService.updateById(menu);
        return Result.ok();
    }

    //@PreAuthorize("hasAuthority('bnt.menu.remove')")
    @ApiOperation(value = "删除")
    @DeleteMapping("remove/{id}")
    public Result remove(@PathVariable Long id) {
        menuService.removeById(id);
        return Result.ok();
    }

}
  • com.atguigu.serviceoa.wechat.service.MenuService
package com.atguigu.serviceoa.wechat.service;
import com.atguigu.enity.model.wechat.Menu;
import com.atguigu.enity.vo.wechat.MenuVo;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.stereotype.Service;
import java.util.List;

/**
 * 菜单 服务类
 */
@Service
public interface MenuService extends IService<Menu> {

    // 获取全部菜单——树形结构
    List<MenuVo> findMenuInfo();
}
  • com.atguigu.serviceoa.wechat.service.impl.MenuServiceImpl
package com.atguigu.serviceoa.wechat.service.impl;
import com.atguigu.enity.model.wechat.Menu;
import com.atguigu.enity.vo.wechat.MenuVo;
import com.atguigu.serviceoa.wechat.mapper.MenuMapper;
import com.atguigu.serviceoa.wechat.service.MenuService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单 服务实现类
 * </p>
 *\
 * @author atguigu
 * @since 2023-05-06
 */
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {

    @Override
    // 获取全部菜单——树形结构
    // 目前只有两个层级,不用搞树形结构那么麻烦
    public List<MenuVo> findMenuInfo() {

        // 1 查询所有菜单List<Menu>集合
        List<Menu> menuList = baseMapper.selectList(null);
        // 把List<Menu>复制到ListVo<Menu>
        // 只能复制对象 不能直接复制对象集合
        List<MenuVo> menuVoList = new ArrayList<>();
        menuList.stream().forEach( item ->{
            MenuVo menuVo = new MenuVo();
            BeanUtils.copyProperties(item,menuVo);
            menuVoList.add(menuVo);
        });

        // 2 查询所有一级菜单 parent_id = 0 ,返回一级菜单List<Menu>集合
        List<MenuVo> menuListVo1 = menuVoList.stream()
                .filter(item -> item.getParentId().longValue() == 0)
                .collect(Collectors.toList());

        // 3 一级菜单List集合遍历,得到每个一级菜单
        for (MenuVo menuVo : menuListVo1) {
            List<MenuVo> children = new ArrayList<>();
            menuVoList.stream().forEach( item ->{
                // 4 获取每个一级菜单里面的所有二级菜单  一级菜单id等于二级菜单parentId
                // 定义一个空集合 children,用来封装二级菜单
                if (item.getParentId().longValue() == menuVo.getId().longValue()){
                    // 5 把一级菜单里面的所有二级菜单找到,封装在一级菜单的children里面
                    children.add(item);
                }
            });
            menuVo.setChildren(children);
        }
        // 3 一级菜单List集合遍历,得到每个一级菜单
//        for (MenuVo menuVo : menuListVo1) {
//            List<MenuVo> children = menuVoList.stream().filter(item -> {
//                // 4 获取每个一级菜单里面的所有二级菜单  一级菜单id等于二级菜单parentId
//                if (item.getParentId().longValue() == menuVo.getId().longValue()) {
//                    return item;
//                }
//            }).collect(Collectors.toList());
//        }
        return menuListVo1;
    }
}

2.推送菜单

  • 需求分析
  • 后台员工账号与微信账号是没有关联的,在点击微信菜单时,要判断是否登录
  • 第一次访问则弹出关联层,建立微信账号与员工账号的绑定
  • 即:通过员工手机号码与微信openId建立绑定,后续进入就知道用户身份了。
  • 老师的免费域名:
  • http://ggkt2.vipgz1.91tunnel.com 8800 ID:075952342272
  • http://ggkt1.vipgz1.91tunnel.com 9090 ID:075735342272