diff --git a/fad-hrm/src/main/java/com/ruoyi/hrm/controller/HrmFlowTaskController.java b/fad-hrm/src/main/java/com/ruoyi/hrm/controller/HrmFlowTaskController.java index b7aaf50..07c299a 100644 --- a/fad-hrm/src/main/java/com/ruoyi/hrm/controller/HrmFlowTaskController.java +++ b/fad-hrm/src/main/java/com/ruoyi/hrm/controller/HrmFlowTaskController.java @@ -6,6 +6,7 @@ import com.ruoyi.common.core.domain.PageQuery; import com.ruoyi.common.core.domain.R; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.helper.LoginHelper; import com.ruoyi.hrm.domain.bo.HrmFlowTaskBo; import com.ruoyi.hrm.domain.bo.HrmFlowTaskApproveBo; import com.ruoyi.hrm.domain.bo.HrmSealStampBo; @@ -112,4 +113,14 @@ public class HrmFlowTaskController extends BaseController { @RequestParam(required = false) String remark) { return toAjax(service.transfer(taskId, newAssigneeUserId, actionUserId, remark)); } + /** + * 审批历史列表:查询当前用户的审批历史,包含分页 + */ + @GetMapping("/historyList") + public TableDataInfo historyList(PageQuery pageQuery) { + // 使用若依自带的 LoginHelper 获取当前登录用户的 ID (类型是 Long) + Long userId = LoginHelper.getUserId(); + // 调用 Service + return service.selectHistoryTaskList(userId, pageQuery); + } } diff --git a/fad-hrm/src/main/java/com/ruoyi/hrm/service/IHrmFlowTaskService.java b/fad-hrm/src/main/java/com/ruoyi/hrm/service/IHrmFlowTaskService.java index 514d360..d2c5f60 100644 --- a/fad-hrm/src/main/java/com/ruoyi/hrm/service/IHrmFlowTaskService.java +++ b/fad-hrm/src/main/java/com/ruoyi/hrm/service/IHrmFlowTaskService.java @@ -2,6 +2,7 @@ package com.ruoyi.hrm.service; import com.ruoyi.common.core.domain.PageQuery; import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.hrm.domain.HrmFlowTask; import com.ruoyi.hrm.domain.bo.HrmFlowTaskBo; import com.ruoyi.hrm.domain.vo.HrmFlowTaskVo; @@ -42,6 +43,10 @@ public interface IHrmFlowTaskService { */ Boolean transfer(Long taskId, Long newAssigneeUserId, Long actionUserId, String remark); + /** + * 查询当前用户的审批历史,并回填业务数据 + */ + TableDataInfo selectHistoryTaskList(Long userId, PageQuery pageQuery); /** * 根据业务类型 + 业务ID 查询当前待办任务(pending),用于详情页自动带出 currentTaskId */ diff --git a/fad-hrm/src/main/java/com/ruoyi/hrm/service/impl/HrmFlowTaskServiceImpl.java b/fad-hrm/src/main/java/com/ruoyi/hrm/service/impl/HrmFlowTaskServiceImpl.java index 3a09cd8..73a5ce4 100644 --- a/fad-hrm/src/main/java/com/ruoyi/hrm/service/impl/HrmFlowTaskServiceImpl.java +++ b/fad-hrm/src/main/java/com/ruoyi/hrm/service/impl/HrmFlowTaskServiceImpl.java @@ -38,6 +38,7 @@ public class HrmFlowTaskServiceImpl implements IHrmFlowTaskService { private final FlowAssigneeHelper assigneeHelper; private final BizStatusSyncHelper bizStatusSyncHelper; + private final HrmFlowTaskMapper hrmFlowTaskMapper; // 注入五个业务Mapper private final HrmLeaveReqMapper leaveReqMapper; private final HrmTravelReqMapper travelReqMapper; @@ -397,4 +398,27 @@ public class HrmFlowTaskServiceImpl implements IHrmFlowTaskService { lqw.orderByDesc(HrmFlowTask::getCreateTime); return lqw; } + /** + * 查询当前用户的审批历史,回填业务数据以便前端复用页面 + */ + @Override + public TableDataInfo selectHistoryTaskList(Long userId, PageQuery pageQuery) { + + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + + lqw.eq(HrmFlowTask::getAssigneeUserId, userId); + + lqw.ne(HrmFlowTask::getStatus, "pending"); + + lqw.orderByDesc(HrmFlowTask::getCreateTime); + + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + + if (result.getRecords() != null && !result.getRecords().isEmpty()) { + fillBizData(result.getRecords()); + } + + return TableDataInfo.build(result); + } + } diff --git a/ruoyi-oa/pom.xml b/ruoyi-oa/pom.xml index 96dd6cb..c50d8a3 100644 --- a/ruoyi-oa/pom.xml +++ b/ruoyi-oa/pom.xml @@ -68,6 +68,7 @@ 1.0.0 + com.xuxueli xxl-job-core diff --git a/ruoyi-oa/src/main/java/com/ruoyi/oa/utils/SfRouteQueryUtil.java b/ruoyi-oa/src/main/java/com/ruoyi/oa/utils/SfRouteQueryUtil.java index 2106df0..82bcd9d 100644 --- a/ruoyi-oa/src/main/java/com/ruoyi/oa/utils/SfRouteQueryUtil.java +++ b/ruoyi-oa/src/main/java/com/ruoyi/oa/utils/SfRouteQueryUtil.java @@ -5,7 +5,7 @@ import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.ruoyi.oa.domain.OaExpress; import com.ruoyi.oa.domain.vo.OaExpressVo; -import sun.misc.BASE64Encoder; +import java.util.Base64; import com.ruoyi.common.utils.DateUtils; import org.apache.commons.lang3.StringUtils; diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java index 78fbbe4..b94014a 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java @@ -1,9 +1,11 @@ package com.ruoyi.workflow.service; + import com.ruoyi.workflow.domain.FlowRecord; import com.ruoyi.workflow.domain.bo.WfTaskBo; import org.flowable.bpmn.model.FlowElement; import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.history.HistoricTaskInstance; import java.io.InputStream; import java.util.List; @@ -124,4 +126,5 @@ public interface IWfTaskService { * @return Map包含isStartNode和isEndNode信息 */ Map checkTaskNodeType(String taskId); + } diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java index 0f89c49..56083b0 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java @@ -4,6 +4,8 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.AbstractWrapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.ruoyi.common.core.service.UserService; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.helper.LoginHelper; @@ -63,6 +65,7 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ private final IWfCopyService copyService; + /** * 完成任务 * @@ -788,4 +791,7 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ return result; } + + + } diff --git a/ruoyi-ui/src/api/hrm/flow.js b/ruoyi-ui/src/api/hrm/flow.js index 9fda8de..a266cc3 100644 --- a/ruoyi-ui/src/api/hrm/flow.js +++ b/ruoyi-ui/src/api/hrm/flow.js @@ -238,6 +238,13 @@ export function delFlowInstance (instId) { method: 'delete' }) } +export function listHistoryFlowTask(query) { + return request({ + url: '/hrm/flow/task/historyList', + method: 'get', + params: query + }) +} /** * 查询实例对应的所有审批任务 @@ -247,4 +254,9 @@ export function listAssignTask (instId) { url: `/hrm/flow/instance/tasks/${instId}`, method: 'get' }) + +/** + * 查询当前用户的审批历史 + */ + } diff --git a/ruoyi-ui/src/permission.js b/ruoyi-ui/src/permission.js index 2584ad2..a89916b 100644 --- a/ruoyi-ui/src/permission.js +++ b/ruoyi-ui/src/permission.js @@ -1,12 +1,12 @@ import router from './router' import store from './store' -import {Message} from 'element-ui' +import { Message } from 'element-ui' import NProgress from 'nprogress' import 'nprogress/nprogress.css' -import {getToken} from '@/utils/auth' -import {isRelogin} from '@/utils/request' +import { getToken } from '@/utils/auth' +import { isRelogin } from '@/utils/request' -NProgress.configure({showSpinner: false}) +NProgress.configure({ showSpinner: false }) const whiteList = ['/login', '/register'] @@ -14,25 +14,32 @@ router.beforeEach((to, from, next) => { NProgress.start() if (getToken()) { to.meta.title && store.dispatch('settings/setTitle', to.meta.title) - /* has token*/ if (to.path === '/login') { - next({path: '/'}) + next({ path: '/' }) NProgress.done() } else { if (store.getters.roles.length === 0) { isRelogin.show = true - // 判断当前用户是否已拉取完user_info信息 store.dispatch('GetInfo').then(res => { isRelogin.show = false store.dispatch('GenerateRoutes').then(accessRoutes => { - // 根据roles权限生成可访问的路由表 - router.addRoutes(accessRoutes) // 动态添加可访问路由表 - next({...to, replace: true}) // hack方法 确保addRoutes已完成 + + const officeMenu = accessRoutes.find(m => m.path === '/oa') + if (officeMenu) { + const staticOa = router.options.routes.find(r => r.path === '/oa') + const historyMenu = staticOa?.children?.find(c => c.name === 'ApprovalHistory') + if (historyMenu) { + officeMenu.children.push(historyMenu) + } + } + + router.addRoutes(accessRoutes) + next({ ...to, replace: true }) }) }).catch(err => { store.dispatch('LogOut').then(() => { Message.error(err) - next({path: '/'}) + next({ path: '/' }) }) }) } else { @@ -40,12 +47,10 @@ router.beforeEach((to, from, next) => { } } } else { - // 没有token if (whiteList.indexOf(to.path) !== -1) { - // 在免登录白名单,直接进入 next() } else { - next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页 + next(`/login?redirect=${to.fullPath}`) NProgress.done() } } @@ -53,4 +58,4 @@ router.beforeEach((to, from, next) => { router.afterEach(() => { NProgress.done() -}) +}) \ No newline at end of file diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js index 1c37a86..c588125 100644 --- a/ruoyi-ui/src/router/index.js +++ b/ruoyi-ui/src/router/index.js @@ -7,28 +7,6 @@ Vue.use(Router); /* Layout */ import Layout from "@/layout"; -/** - * Note: 路由配置项 - * - * hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1 - * alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 - * // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面 - * // 若你想不管路由下面的 children 声明的个数都显示你的根路由 - * // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由 - * redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 - * name:'router-name' // 设定路由的名字,一定要填写不然使用时会出现各种问题 - * query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数 - * roles: ['admin', 'common'] // 访问路由的角色权限 - * permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限 - * meta : { - noCache: true // 如果设置为true,则不会被 缓存(默认 false) - title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字 - icon: 'svg-name' // 设置该路由的图标,对应路径src/assets/icons/svg - breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示 - activeMenu: '/system/user' // 当路由设置了该属性,则会高亮相对应的侧边栏。 - } - */ - // 公共路由 export const constantRoutes = [ { @@ -73,12 +51,10 @@ export const constantRoutes = [ name: "Index", meta: { title: "工作台", icon: "dashboard", affix: true }, beforeEnter: (to, from, next) => { - // 从本地存储获取角色信息 currentRole().then((res) => { - console.log(res) const role = res.data[0].roleKey; if (role === "temp") { - next("/temp"); // 重定向到临时页面 + next("/temp"); } else { next(); } @@ -91,16 +67,15 @@ export const constantRoutes = [ path: "/temp", component: () => import("@/views/temp"), name: "Temp", - hidden: true, // 隐藏路由 + hidden: true, meta: { title: "临时页面", icon: "dashboard" }, beforeEnter: (to, from, next) => { - // 从本地存储获取角色信息 currentRole().then((res) => { const role = res.data[0].roleKey; if (role === "temp") { next(); } else { - next("/index"); // 重定向到工作台 + next("/index"); } }); }, @@ -144,14 +119,12 @@ export const constantRoutes = [ name: "updateOnboarding", meta: { title: "更新入职数据", activeMenu: "/people/onboarding" }, }, - { path: "addOffboarding", component: () => import("@/views/oa/offboarding/add"), name: "addOffboarding", meta: { title: "新增离职申请", activeMenu: "/people/offboarding" }, }, - { path: "updateOffboarding/:offboardingId(\\d+)", component: () => import("@/views/oa/offboarding/update"), @@ -174,7 +147,6 @@ export const constantRoutes = [ }, ], }, - { path: "/money", component: Layout, @@ -188,7 +160,6 @@ export const constantRoutes = [ }, ], }, - { path: "/claim", component: Layout, @@ -210,7 +181,6 @@ export const constantRoutes = [ }, ]; -// 动态路由,基于用户权限动态去加载 export const dynamicRoutes = [ { path: "/system/user-auth", @@ -240,7 +210,6 @@ export const dynamicRoutes = [ }, ], }, - { path: "/system/dict-data", component: Layout, @@ -255,7 +224,6 @@ export const dynamicRoutes = [ }, ], }, - { path: "/oa/warehouse-data", component: Layout, @@ -348,23 +316,20 @@ export const dynamicRoutes = [ }, ]; -// 防止连续点击多次路由报错 let routerPush = Router.prototype.push; let routerReplace = Router.prototype.replace; -// push -Router.prototype.push = function push (location) { +Router.prototype.push = function push(location) { return routerPush.call(this, location).catch((err) => err); }; -// replace -Router.prototype.replace = function push (location) { +Router.prototype.replace = function replace(location) { return routerReplace.call(this, location).catch((err) => err); }; const router = new Router({ base: process.env.VUE_APP_CONTEXT_PATH, - mode: "history", // 去掉url中的# + mode: "history", scrollBehavior: () => ({ y: 0 }), routes: constantRoutes, }); -export default router; +export default router; \ No newline at end of file diff --git a/ruoyi-ui/src/store/modules/permission.js b/ruoyi-ui/src/store/modules/permission.js index 2287665..766d105 100644 --- a/ruoyi-ui/src/store/modules/permission.js +++ b/ruoyi-ui/src/store/modules/permission.js @@ -29,11 +29,36 @@ const permission = { }, }, actions: { - // 生成路由 - GenerateRoutes({ commit }) { + GenerateRoutes({ commit }) { return new Promise(resolve => { - // 向后端请求路由数据 + getRouters().then(res => { + + + const oaMenu = res.data.find(item => item.path === '/oa' || (item.meta && item.meta.title === '办公中心')); + + if (oaMenu) { + if (!oaMenu.children) oaMenu.children = []; + + + const hasHistory = oaMenu.children.some(child => child.path === 'flowHistory'); + + if (!hasHistory) { + oaMenu.children.push({ + name: 'HrmFlowHistory', + path: 'flowHistory', + hidden: false, + component: 'hrm/flow/taskHistory', + meta: { + title: '审批历史', + icon: 'date-range', + noCache: false + } + }); + } + } + // ================= 新增拦截代码:将页面注入到办公中心结束 ================= + const sdata = JSON.parse(JSON.stringify(res.data)) const rdata = JSON.parse(JSON.stringify(res.data)) const sidebarRoutes = filterAsyncRouter(sdata) @@ -130,4 +155,4 @@ export const loadView = (view) => { } } -export default permission +export default permission \ No newline at end of file diff --git a/ruoyi-ui/src/views/hrm/flow/taskHistory.vue b/ruoyi-ui/src/views/hrm/flow/taskHistory.vue new file mode 100644 index 0000000..05db498 --- /dev/null +++ b/ruoyi-ui/src/views/hrm/flow/taskHistory.vue @@ -0,0 +1,236 @@ + + + + + \ No newline at end of file diff --git a/ruoyi-ui/src/views/hrm/index.vue b/ruoyi-ui/src/views/hrm/index.vue index b896cf6..1825d9c 100644 --- a/ruoyi-ui/src/views/hrm/index.vue +++ b/ruoyi-ui/src/views/hrm/index.vue @@ -17,6 +17,9 @@ 薪酬与指标 + + 审批历史 +
diff --git a/ruoyi-ui/src/views/hrm/js/History b/ruoyi-ui/src/views/hrm/js/History new file mode 100644 index 0000000..3028a36 --- /dev/null +++ b/ruoyi-ui/src/views/hrm/js/History @@ -0,0 +1,36 @@ +import request from '@/utils/request' + +// 获取审批历史(已完成) +export function listHistoryFlowTask(query) { + return request({ + url: '/workflow/task/historyList', + method: 'get', + params: query + }) +} + +// 任务详情 +export function getTodoTaskByBiz(taskId) { + return request({ + url: '/workflow/task/getByTaskId/' + taskId, + method: 'get' + }) +} + +// 审批记录 +export function listFlowAction(query) { + return request({ + url: '/workflow/instance/action/list', + method: 'get', + params: query + }) +} + +// 表单数据 +export function listFlowFormData(query) { + return request({ + url: '/workflow/instance/form/data', + method: 'get', + params: query + }) +} \ No newline at end of file