从0到1搭建自己的OA系统(一)

虽然说是从0到1,但是程序员都知道,不可能重复造轮子。还是从ruoyi脚手架项目开始

一、ruoyi脚手架整体结构

1.1、原脚手架结构

  • ruoyi-admin 所有controller有关的接口全放在这里,也叫Web模块,特有逻辑1,必需的
  • ruoyi-system 除此之外的domain、mapper、service等CRUD相关逻辑,特有逻辑2
  • ruoyi-quartz 定时器,特有逻辑3
  • ruoyi-generator 代码生成器,特有逻辑4
  • ruoyi-common 公共组件,如工具类、公共用到的,公共逻辑1,必需的
  • ruoyi-framework 框架运行所需要的一些类,公共逻辑2,必需的

上述加黑字体的模块是主要模块,项目最终都会整合到 ruoyi-admin模块中,而ruoyi-admin是通过pom.xml把上述模块加入依赖进来的,各模块之间的依赖关系如下简图所示:

1.2、SQL表结构

重点的表主要是sys_ 开头的表:

  • sys_config :对应的系统中“系统管理/参数设置
  • sys_dept:对应系统中“系统管理/部门管理
  • sys_dict_data:字典明细表,对应系统中“系统管理/字典管理
  • sys_dict_type:字典类型表,对应系统中“系统管理/字典管理/字典类型
  • sys_job / sys_job_log:定时任务,对应系统中“系统监控/定时任务”
  • sys_logininfor:登录信息,对应于系统的“系统监控/在线用户”和“日志管理/登录日志
  • sys_menu:菜单管理表,对应于系统的所有菜单值,还对应于“系统管理/菜单管理
  • sys_notice:通知信息,对应于“系统管理/通知公告”
  • sys_oper_log:操作日志,对应于“日志管理/操作日志
  • sys_post:岗位管理表,对应“系统管理/岗位管理
  • sys_role:角色管理表,对应“系统管理/角色管理
  • sys_user:用户表,对应“系统管理/用户管理
  • sys_role_dept / sys_role_menu /sys_user_role : 角色与部门、菜单、用户的对应表
  • sys_user_post:用户与岗位的对应表

其中,用户相关的表的关系如下所示:

1.3 接口返回值

前后端分离的ruoyi框架共三个类型的返回值,分别是:

  • void:主要是导出或下载等不需要返回值的接口
  • TableDataInfo:所返回的数据结构如下,主要是页面的分页列表数据

  • AjaxResult:所返回的数据结构如下,主要是基本添加、编辑、单个查询或删除等操作的返回值,一般是json格式数据

二、改造“通知公告”

目的:通过改造“通知公告”能够对系统有个基本了解。

目标:前端将“通知公告”拆分为两个页面:

  • A页面主要是显示所有用户发布的所有公告,并可查看详情,查看完毕后标识已读状态
  • B页面主要是用户个人自己的公告编辑,发起流程并发布的编辑页面

2.1 调整字典数据

通过前端页面调整字典数据,增加记录是否已读的sys_notice_isread数据字典类型,同时修改通知的类型sys_notice_status为流程类型、修改sys_notice_type的通知类型:

  • sys_notice_type:

  • sys_notice_status:

  • sys_notice_isread(新增):

2.2 增加用户与通知的关联SQL表

针对每个用户的已读信息,在SQL中予以存储之用,表名命名为sys_user_notice:

2.3 生成新增SQL的后台操作代码

使用代码生成器生成新增的SQL后台操作代码,如下图,代码生成器生成的代码包括前端VUE文件和后端main文件以及针对前端菜单显示的SQL三部分。其中因前端是改造原通知公告页面,故不使用vue和SQL文件,仅导入后端操作的main文件,如图标识所示部分:

2.4 改造“全员信息”页面

复制备份前端的views/system/notice下的index.vue,命名为create.vue作为编辑公共页面备用。

首先改造index如下:

2.4.1 去掉编辑功能

注释掉本页面中所有的“新增、修改、删除”的前端代码

2.4.2 增加序号和公告编号

<el-table-column label="序号" align="center" prop="noId" width="100" />
<el-table-column label="公告编号" align="center" prop="noticeId" :show-overflow-tooltip="true"/>

2.4.3 操作中添加“查看”

<el-button size="mini" type="text" icon="el-icon-view" @click="openDetailDialog(scope.row.noticeId)">查看</el-button>

同时添加点击“查看”后的详情页面:

    <!--通知公告详情 -->
    <el-dialog :title="form.noticeTitle" :visible.sync="openDetail" width="800px" append-to-body @close="closeDetail(form.noticeId)">
      <div style="margin-top:-20px;margin-bottom:10px;">        
          <el-tag size="mini" effect="dark" 
          v-for="mytype in dict.type.sys_notice_type" :key="dict.value"
        :type="mytype.raw.listClass" v-if="form.noticeType==mytype.value">{{ mytype.label}}</el-tag>
        <span style="margin-left:20px;">{{form.createTime}}</span>
      </div>
      <div v-loading="loadingDetail" class="content">
        <div v-html="form.noticeContent" style="margin-left:0px;margin-right:76px" class="ql-editor"></div>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="closeDetail(form.noticeId)"> 关 闭 </el-button>
      </div>
    </el-dialog>

2.4.4 api和数据改造

api增加listPublishList路径,用以获取后端的所有发布的信息,index中改造如下:

import { listPublishNotice, getNotice,getNoticeAndRecord, delNotice, addNotice, updateNotice } from "@/api/system/notice";

api中改造如下:

// 查询所有发布的公告列表
export function listPublishNotice(query) {
  return request({
    url: '/system/notice/publishlist',
    method: 'get',
    params: query
  })
}

index.vue中发生变动的数据如下:

  dicts: ['sys_notice_status','sys_notice_isread', 'sys_notice_type'],
  queryParams: {
        pageNum: 1,
        pageSize: 10,
        noticeTitle: undefined,
        createBy: undefined,
        status: undefined,
        orderByColumn:"create_time",
        isAsc:"desc"
      },

获取数据的方法变动如下:

/** 查询公告列表 */
    getList() {
      this.loading = true;
      listPublishNotice(this.queryParams).then(response => {
        this.noticeList = response.rows;
        this.total = response.total;
        this.loading = false;
      });
    },

增加打开详情信息的处理方法如下:

 // 打开信息详情
    openDetailDialog(id) {
      this.openDetail = true;
      this.loadingDetail = true;
      getNoticeAndRecord(id).then(response => {
        this.form = response.data;
        this.openDetail = true;
        this.loadingDetail = false;
        
      });
    },
    // 取消按钮
    closeDetail(id) {
      this.titleDetail = "详情";
      this.openDetail = false;
      this.reset();
      this.noticeList.forEach(element => {
        if(element.noticeId == id) {
          element.isRead = 1;
        }
    });
   },

2.4.5 后端处理修改

SysNoticeCotroller中增加路由:

    /**
     * 获取发布类型通知公告列表
     */
    @SaCheckPermission("system:notice:list")
    @GetMapping("/publishlist")
    public TableDataInfo<SysNotice> publishlist(SysNotice notice, PageQuery pageQuery) {
        return noticeService.selectPageNoticePublishList(notice, pageQuery, getUserId());
    }

在SysNoticeServerImpl中增加相关处理方法并添加接口:

    /**
     * 查询所有发布状态的公告
     * @param notice
     * @param pageQuery
     * @return
     */
    @Override
    public TableDataInfo<SysNotice> selectPageNoticePublishList(SysNotice notice, PageQuery pageQuery, Long currentUserId) {
        LambdaQueryWrapper<SysNotice> lqw = new LambdaQueryWrapper<SysNotice>()
            .like(StringUtils.isNotBlank(notice.getNoticeTitle()), SysNotice::getNoticeTitle, notice.getNoticeTitle())
            .eq(StringUtils.isNotBlank(notice.getNoticeType()), SysNotice::getNoticeType, notice.getNoticeType())
            .like(StringUtils.isNotBlank(notice.getCreateBy()), SysNotice::getCreateBy, notice.getCreateBy())
            .eq(SysNotice::getStatus, dictDataService.selectDictValue("sys_notice_status", "发布"));
        Page<SysNotice> page = baseMapper.selectPage(pageQuery.build(), lqw);
        int i = PageQuery.DEFAULT_PAGE_NUM;
        for( SysNotice one : page.getRecords()) {
                one.setCreateBy(String.valueOf(sysUserService.selectUserByUserName(one.getCreateBy()).getNickName()));
                SysUserNoticeVo isReadResult = sysUserNoticeService.queryByIdAndNoticeId(currentUserId, one.getNoticeId());
                if(isReadResult != null){
                    one.setIsRead(Long.valueOf(dictDataService.selectDictValue("sys_notice_isread", "已读")));
                } else {
                    one.setIsRead(Long.valueOf(dictDataService.selectDictValue("sys_notice_isread", "未读")));
                }
                one.setNoId(Long.valueOf((pageQuery.getPageNum()-1)*pageQuery.getPageSize()+i));
            i++;
        }

        return TableDataInfo.build(page);
    }

所有修改完毕后效果如下

2.5 改造“编辑公告”页面

针对上述2.4步复制出来的create.vue页面改造如下:

2.5.1 添加序号和流程发起

<el-table-column label="序号" align="center" prop="noId" width="100" />
<el-table-column label="公告编号" align="center" prop="noticeId" :show-overflow-tooltip="true"/>
<el-button type="text" size="mini" icon="el-icon-video-play" @click="handleStart(scope.row)" v-hasPermi="['workflow:process:start']">发起</el-button>

2.5.2 修改数据和方法

如2.4.4中改造“全员公告”的方式类似,分别修改api及本create.vue页面如下

// 查询当前用户的所有公告列表
export function listCurrUserNotice(query) {
  return request({
    url: '/system/notice/curruserlist',
    method: 'get',
    params: query
  })
}
import { listCurrUserNotice,getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
// 查询参数
queryParams: {
        pageNum: 1,
        pageSize: 10,
        noticeTitle: undefined,
        createBy: undefined,
        status: undefined,
        orderByColumn:"create_time",
        isAsc:"desc"
      },
/** 查询公告列表 */
    getList() {
      this.loading = true;
      listCurrUserNotice(this.queryParams).then(response => {
        this.noticeList = response.rows;
        this.total = response.total;
        this.loading = false;
      });
    },

其中,流程操作中的“发起”按钮的操作方法暂未开发(20240304记录,待后续更新)

2.5.3 后端处理修改

分别修改后端对应的controller文件和service实现文件:

/**
     * 获取当前用户的所有状态通知公告列表
     */
    @SaCheckPermission("system:notice:list")
    @GetMapping("/curruserlist")
    public TableDataInfo<SysNotice> curruserlist(SysNotice notice, PageQuery pageQuery) {
        return noticeService.selectPageCurrUserList(notice, pageQuery, getUserId());
    }
/**
     * 查询当前用户的所有状态的公告
     * @param notice
     * @param pageQuery
     * @param  userId
     * @return
     */
    @Override
    public TableDataInfo<SysNotice> selectPageCurrUserList(SysNotice notice, PageQuery pageQuery, Long userId) {
        LambdaQueryWrapper<SysNotice> lqw = new LambdaQueryWrapper<SysNotice>()
            .like(StringUtils.isNotBlank(notice.getNoticeTitle()), SysNotice::getNoticeTitle, notice.getNoticeTitle())
            .eq(StringUtils.isNotBlank(notice.getNoticeType()), SysNotice::getNoticeType, notice.getNoticeType())
            .eq(SysNotice::getCreateBy, sysUserService.selectUserById(userId).getUserName());
        Page<SysNotice> page = baseMapper.selectPage(pageQuery.build(), lqw);
        int i = PageQuery.DEFAULT_PAGE_NUM;
        for( SysNotice one : page.getRecords()) {
            one.setNoId(Long.valueOf((pageQuery.getPageNum()-1)*pageQuery.getPageSize()+i));
            i++;
        }
        return  TableDataInfo.build(page);
    }

所有改造完毕后的效果如下:

2.6 过程遇到的问题

2.6.1 jdk17下cglib报错

修改后端的service时,报如下错误,经查是 jdk17下cglib未更新所致

Unable to make protected final java.lang.Class java.lang.ClassLoader

在项目运行的中增加项目VM运行前的参数解决 

--add-opens java.base/java.lang=ALL-UNNAMED

2.6.2  SQL update相关问题 

因本次修改仿照其他sql表建立的sys_user_notice关联表,在实际修改service过程中发生了以下几类错误,后期如遇到可快速避免:

  • 新增表无id,updateById或selectById时报错。此类问题可使用updateByBo之类解决,增加一个lamdaQueryWrapper的表达式,用Bo对象实现查询或更新
  • 默认的表都有create_by等系统默认字段,后端MybatisPlus的相关处理默认也是要操作这几个字段的,在尽量少更改代码的情况,在后期新建的SQL表中尽量考虑增加上这几个系统字段
  • 14
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值