MES审批复用钉钉审批设置
This commit is contained in:
@@ -944,6 +944,11 @@ jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules
|
||||
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java
|
||||
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
|
||||
|
||||
-- author:GHT---date:20260610--for: 【IM审批通用化】MES发起审批按钮按ding_tpl_bind路由匹配(与钉钉按钮一致) -----
|
||||
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/controller/MesXslApprovalLaunchController.java
|
||||
jeecgboot-vue3/src/components/ApprovalLaunch/index.vue
|
||||
jeecgboot-vue3/src/views/approval/flow/launch.api.ts
|
||||
|
||||
-- author:GHT---date:20260610--for: 【IM审批通用化】IM工作通知公众号(同事列表置顶+审批消息统一推送) -----
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_147__sys_im_work_notify_user.sql
|
||||
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/im/service/impl/SysImChatServiceImpl.java
|
||||
|
||||
@@ -16,11 +16,13 @@ import org.jeecg.modules.xslmes.approval.service.IMesXslApprovalHandleService;
|
||||
import org.jeecg.modules.xslmes.approval.service.IMesXslApprovalInstanceService;
|
||||
import org.jeecg.modules.xslmes.approval.vo.ApprovalGateVo;
|
||||
import org.jeecg.modules.xslmes.common.MesXslTenantUtils;
|
||||
import org.jeecg.modules.xslmes.dingtalk.service.IMesXslDingTplBindService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -61,19 +63,37 @@ public class MesXslApprovalLaunchController {
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
|
||||
//update-begin---author:GHT ---date:20260610 for:【IM审批通用化】MES发起按钮与钉钉绑定同路由匹配-----------
|
||||
@Autowired
|
||||
private IMesXslDingTplBindService dingTplBindService;
|
||||
//update-end---author:GHT ---date:20260610 for:【IM审批通用化】MES发起按钮与钉钉绑定同路由匹配-----------
|
||||
|
||||
/**
|
||||
* 已发布审批流列表(按租户隔离),即"可发起的单据类型"。
|
||||
* 同时按"功能模块(单据表)"自动反查其菜单路由填入 routePath,供前端控制悬浮按钮仅在该功能页显示,无需手工配置。
|
||||
* routePath 有值时:与钉钉审批按钮一致,先按 mes_xsl_ding_tpl_bind 解析当前页绑定,再返回该页业务表下已发布审批流。
|
||||
*/
|
||||
@Operation(summary = "发起审批-已发布审批流列表")
|
||||
@GetMapping("/publishedList")
|
||||
public Result<List<MesXslApprovalFlow>> publishedList() {
|
||||
public Result<List<MesXslApprovalFlow>> publishedList(
|
||||
@RequestParam(name = "routePath", required = false) String routePath) {
|
||||
QueryWrapper<MesXslApprovalFlow> qw = new QueryWrapper<>();
|
||||
qw.eq("status", "1");
|
||||
Integer tenantId = MesXslTenantUtils.resolveTenantId(null);
|
||||
if (tenantId != null) {
|
||||
qw.eq("tenant_id", tenantId);
|
||||
}
|
||||
//update-begin---author:GHT ---date:20260610 for:【IM审批通用化】MES发起按钮与钉钉绑定同路由匹配-----------
|
||||
if (oConvertUtils.isNotEmpty(routePath)) {
|
||||
if (dingTplBindService.resolveActiveByRoutePath(routePath.trim()) == null) {
|
||||
return Result.OK(Collections.emptyList());
|
||||
}
|
||||
String bizTable = resolveTableByRoutePath(routePath);
|
||||
if (oConvertUtils.isEmpty(bizTable) || !IDENTIFIER.matcher(bizTable).matches()) {
|
||||
return Result.OK(Collections.emptyList());
|
||||
}
|
||||
qw.eq("biz_table", bizTable);
|
||||
}
|
||||
//update-end---author:GHT ---date:20260610 for:【IM审批通用化】MES发起按钮与钉钉绑定同路由匹配-----------
|
||||
qw.orderByDesc("create_time");
|
||||
List<MesXslApprovalFlow> list = approvalFlowService.list(qw);
|
||||
// 未手工指定 route_path 时,按单据表名自动反查菜单路由
|
||||
@@ -90,6 +110,59 @@ public class MesXslApprovalLaunchController {
|
||||
* 约定:jeecg 代码生成的列表组件名为 表名驼峰 + List(如 mes_xsl_formula_spec -> MesXslFormulaSpecList),
|
||||
* 对应 sys_permission.component 形如 xslmes/mesXslFormulaSpec/MesXslFormulaSpecList,取其 url 即路由。
|
||||
*/
|
||||
//update-begin---author:GHT ---date:20260610 for:【IM审批通用化】按前端路由反查业务表(与钉钉绑定路由解析一致)-----------
|
||||
private String resolveTableByRoutePath(String routePath) {
|
||||
if (oConvertUtils.isEmpty(routePath)) {
|
||||
return null;
|
||||
}
|
||||
String component = resolveComponentByRoutePath(routePath);
|
||||
if (oConvertUtils.isEmpty(component)) {
|
||||
return null;
|
||||
}
|
||||
String comp = component.contains("/") ? component.substring(component.lastIndexOf('/') + 1) : component;
|
||||
if (comp.endsWith("List")) {
|
||||
comp = comp.substring(0, comp.length() - "List".length());
|
||||
}
|
||||
return camelToUnderline(comp);
|
||||
}
|
||||
|
||||
private String resolveComponentByRoutePath(String routePath) {
|
||||
if (oConvertUtils.isEmpty(routePath)) {
|
||||
return null;
|
||||
}
|
||||
String path = routePath.trim().replaceAll("/+$", "");
|
||||
String sql = "SELECT component FROM sys_permission WHERE menu_type IN (0,1) "
|
||||
+ "AND (del_flag = 0 OR del_flag IS NULL) AND url = ? "
|
||||
+ "ORDER BY menu_type DESC LIMIT 1";
|
||||
try {
|
||||
List<String> list = jdbcTemplate.queryForList(sql, String.class, path);
|
||||
return list.isEmpty() ? null : list.get(0);
|
||||
} catch (Exception e) {
|
||||
log.warn("反查菜单组件失败 routePath={}", routePath, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String camelToUnderline(String camel) {
|
||||
if (oConvertUtils.isEmpty(camel)) {
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < camel.length(); i++) {
|
||||
char c = camel.charAt(i);
|
||||
if (Character.isUpperCase(c)) {
|
||||
if (i > 0) {
|
||||
sb.append('_');
|
||||
}
|
||||
sb.append(Character.toLowerCase(c));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
//update-end---author:GHT ---date:20260610 for:【IM审批通用化】按前端路由反查业务表(与钉钉绑定路由解析一致)-----------
|
||||
|
||||
private String resolveRoutePathByTable(String table) {
|
||||
if (oConvertUtils.isEmpty(table) || !IDENTIFIER.matcher(table).matches()) {
|
||||
return null;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<!--
|
||||
全局「发起审批」悬浮按钮
|
||||
仅在「设计并发布了审批流、且能匹配到对应功能页路由」的页面显示。
|
||||
与「钉钉审批」按钮一致:当前页存在 mes_xsl_ding_tpl_bind 绑定且钉钉模板启用时显示;
|
||||
弹窗内可选该页业务表下已发布的 MES 审批流。
|
||||
支持两种发起方式:
|
||||
1)列表多选联动:在列表勾选数据后点击,弹窗自动带入选中单据并可批量发起;
|
||||
2)手动选择:未勾选时,在弹窗内搜索选择单条单据发起。
|
||||
@@ -57,11 +58,12 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import { computed, reactive, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { getPublishedFlows, getBizRecords, launchApproval, launchApprovalBatch } from '/@/views/approval/flow/launch.api';
|
||||
import { getBindingByRoute } from '/@/views/xslmes/dingtalk/dingTplBind/dingTplBind.api';
|
||||
import { useApprovalSelection } from './useApprovalSelection';
|
||||
|
||||
defineOptions({ name: 'ApprovalLaunchFloat' });
|
||||
@@ -78,6 +80,7 @@
|
||||
const bizDataId = ref<string>();
|
||||
const bizTitle = ref<string>('');
|
||||
|
||||
const binding = ref<any>(null);
|
||||
const flowList = ref<any[]>([]);
|
||||
const recordList = ref<any[]>([]);
|
||||
// 打开弹窗时快照的列表勾选行(批量模式数据源)
|
||||
@@ -86,18 +89,10 @@
|
||||
// 悬浮位置(右下角)
|
||||
const floatStyle = reactive({ right: '24px', bottom: '120px' });
|
||||
|
||||
function normalizePath(p?: string) {
|
||||
return (p || '').trim().replace(/\/+$/, '');
|
||||
}
|
||||
// 与钉钉审批按钮一致:按 mes_xsl_ding_tpl_bind + 路由解析是否显示
|
||||
const show = computed(() => !!binding.value);
|
||||
|
||||
// 当前路由匹配到的已发布审批流
|
||||
const matchedFlows = computed(() => {
|
||||
const cur = normalizePath(currentRoute.value?.path);
|
||||
if (!cur) return [];
|
||||
return flowList.value.filter((f) => f.routePath && normalizePath(f.routePath) === cur);
|
||||
});
|
||||
|
||||
const show = computed(() => matchedFlows.value.length > 0);
|
||||
const matchedFlows = computed(() => flowList.value);
|
||||
|
||||
const flowOptions = computed(() =>
|
||||
matchedFlows.value.map((f) => ({
|
||||
@@ -130,15 +125,27 @@
|
||||
}))
|
||||
);
|
||||
|
||||
onMounted(loadFlows);
|
||||
|
||||
async function loadFlows() {
|
||||
watch(
|
||||
() => currentRoute.value?.path,
|
||||
async (path) => {
|
||||
binding.value = null;
|
||||
flowList.value = [];
|
||||
if (!path || path === '/' || path.startsWith('/login')) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
flowList.value = (await getPublishedFlows()) || [];
|
||||
const bind = await getBindingByRoute(path);
|
||||
binding.value = bind || null;
|
||||
if (binding.value) {
|
||||
flowList.value = (await getPublishedFlows(path)) || [];
|
||||
}
|
||||
} catch {
|
||||
binding.value = null;
|
||||
flowList.value = [];
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
function resetSelection() {
|
||||
flowId.value = undefined;
|
||||
@@ -149,6 +156,10 @@
|
||||
}
|
||||
|
||||
async function openModal() {
|
||||
if (!matchedFlows.value.length) {
|
||||
createMessage.warning('当前页面暂无已发布的 MES 审批流,请先在审批流设计中发布');
|
||||
return;
|
||||
}
|
||||
visible.value = true;
|
||||
resetSelection();
|
||||
// 读取当前列表页的勾选行
|
||||
|
||||
@@ -14,8 +14,10 @@ enum Api {
|
||||
|
||||
/**
|
||||
* 已发布审批流列表(可发起的单据类型)
|
||||
* @param routePath 当前功能页路由;传入时与钉钉审批按钮一致,按 mes_xsl_ding_tpl_bind 绑定页过滤
|
||||
*/
|
||||
export const getPublishedFlows = () => defHttp.get({ url: Api.publishedList });
|
||||
export const getPublishedFlows = (routePath?: string) =>
|
||||
defHttp.get({ url: Api.publishedList, params: routePath ? { routePath } : undefined });
|
||||
|
||||
/**
|
||||
* 根据审批流查询其绑定单据的记录列表
|
||||
|
||||
Reference in New Issue
Block a user