Pārlūkot izejas kodu

feat: 更新作业类型名称匹配逻辑,优化查找函数以支持全等优先和包含兜底

xieyong 2 dienas atpakaļ
vecāks
revīzija
f39eaff48a

+ 9 - 9
src/views/DangerousWorkList/constants.js

@@ -1,7 +1,7 @@
 /**
  * 危险作业票(作业票)常量与审批流配置
  */
-import { isSameWorkTypeName, matchBuiltInWorkType } from './workTypes';
+import { findByWorkTypeName, matchBuiltInWorkType } from './workTypes';
 
 /**
  * 作业票状态
@@ -181,14 +181,14 @@ export function getProcessDefinitionKey(workType, workTypeName) {
     workTypeName === undefined || workTypeName === null
       ? ''
       : String(workTypeName).trim();
-  // 1) 作业类型名称(后端字典值)优先
-  if (name) {
-    const byName = WORK_TICKET_PROCESS_MAPPING.find((item) =>
-      isSameWorkTypeName(item.name, name)
-    );
-    if (byName) {
-      return byName.processDefinitionKey;
-    }
+  // 1) 作业类型名称(后端字典值)优先:全等优先 + 包含兜底
+  const byName = findByWorkTypeName(
+    WORK_TICKET_PROCESS_MAPPING,
+    name,
+    (item) => [item.name]
+  );
+  if (byName) {
+    return byName.processDefinitionKey;
   }
   // 2) 内置作业类型映射:按源系统编码 HO_PERMIT_* 定位审批流
   //    不再按字典码直接兜底:字典码由后端维护,与内置编码不一定对应,

+ 9 - 9
src/views/DangerousWorkList/templates.js

@@ -24,7 +24,7 @@
 
 import {
   BUILT_IN_WORK_TYPES,
-  isSameWorkTypeName,
+  findByWorkTypeName,
   matchBuiltInWorkType
 } from './workTypes';
 
@@ -848,14 +848,14 @@ export function getWorkTicketTemplate(workType, workTypeName) {
     workTypeName === undefined || workTypeName === null
       ? ''
       : String(workTypeName).trim();
-  // 1) 作业类型名称(后端字典值)优先
-  if (name) {
-    const byName = WORK_TICKET_TEMPLATES.find((item) =>
-      (item.workTypeNames || []).some((n) => isSameWorkTypeName(n, name))
-    );
-    if (byName) {
-      return byName;
-    }
+  // 1) 作业类型名称(后端字典值)优先:全等优先 + 包含兜底
+  const byName = findByWorkTypeName(
+    WORK_TICKET_TEMPLATES,
+    name,
+    (item) => item.workTypeNames || []
+  );
+  if (byName) {
+    return byName;
   }
   // 2) 内置作业类型映射:按源系统编码 HO_PERMIT_* 定位模板
   //    不再按字典码直接兜底:字典码由后端维护,与内置编码不一定对应,

+ 70 - 18
src/views/DangerousWorkList/workTypes.js

@@ -35,6 +35,15 @@ export const BUILT_IN_WORK_TYPES = [
 // 泛词不参与包含匹配,避免「作业」「其他」这类名称误命中
 const GENERIC_NAMES = ['作业', '类型', '其他', '其它', '作业票', '其它作业'];
 
+/**
+ * 归一化作业类型名称:去掉首尾空白,非字符串统一转成字符串
+ * @param {*} value 原始值
+ * @returns {string} 归一化后的名称
+ */
+function normalizeWorkTypeName(value) {
+  return value === undefined || value === null ? '' : String(value).trim();
+}
+
 /**
  * 两个作业类型名称是否指向同一种类型
  * 完全相同直接命中;否则按包含关系兜底(如字典「受限空间」vs 内置「受限空间作业」)
@@ -43,8 +52,8 @@ const GENERIC_NAMES = ['作业', '类型', '其他', '其它', '作业票', '其
  * @returns 是否为同一种作业类型
  */
 export function isSameWorkTypeName(a, b) {
-  const x = String(a === undefined || a === null ? '' : a).trim();
-  const y = String(b === undefined || b === null ? '' : b).trim();
+  const x = normalizeWorkTypeName(a);
+  const y = normalizeWorkTypeName(b);
   if (!x || !y) {
     return false;
   }
@@ -59,30 +68,73 @@ export function isSameWorkTypeName(a, b) {
   return long.indexOf(short) > -1;
 }
 
+/**
+ * 按作业类型名称在候选列表中查找
+ *
+ * 匹配分两轮:
+ *   第一轮:名称完全相等(含别名),命中即返回。
+ *     放在最前面是为了避免「更短更泛」的类型抢答:
+ *     内置表里若同时存在「高处作业」和「登高作业」,
+ *     字典值「高处作业」必须命中前者,而不是被包含关系先扫到后者。
+ *   第二轮:包含关系兜底(排除「作业」「其他」这类泛词),
+ *     命中多条时取匹配名称最长、也就是最具体的那一条。
+ *
+ * @param {Array} list 候选列表
+ * @param {string} name 作业类型名称(后端字典值)
+ * @param {Function} getNames 从候选项取出可参与匹配的名称数组
+ * @returns {object|null} 命中的候选项,未命中返回 null
+ */
+export function findByWorkTypeName(list, name, getNames) {
+  const target = normalizeWorkTypeName(name);
+  if (!target) {
+    return null;
+  }
+  const candidates = list || [];
+  // 第一轮:名称完全相等
+  for (const item of candidates) {
+    const names = (getNames && getNames(item)) || [];
+    if (names.some((n) => normalizeWorkTypeName(n) === target)) {
+      return item;
+    }
+  }
+  // 第二轮:包含关系兜底,命中最具体(名称最长)的一条
+  let hit = null;
+  let hitLength = -1;
+  for (const item of candidates) {
+    const names = (getNames && getNames(item)) || [];
+    for (const n of names) {
+      if (!isSameWorkTypeName(n, target)) {
+        continue;
+      }
+      const length = normalizeWorkTypeName(n).length;
+      if (length > hitLength) {
+        hit = item;
+        hitLength = length;
+      }
+    }
+  }
+  return hit;
+}
+
 /**
  * 匹配内置作业类型
- * 匹配顺序:作业类型名称 -> 源系统编码 HO_PERMIT_* -> 内置字典码
+ * 匹配顺序:作业类型名称(全等优先 + 包含兜底) -> 内置字典码 / 源系统 HO_PERMIT_* 编码
  * @param workType 作业类型编码(后端字典码或源系统 HO_PERMIT_* 编码)
  * @param workTypeName 作业类型名称
  * @returns 匹配到的内置作业类型,未匹配返回 null
  */
 export function matchBuiltInWorkType(workType, workTypeName) {
-  const name =
-    workTypeName === undefined || workTypeName === null
-      ? ''
-      : String(workTypeName).trim();
-  if (name) {
-    const byName = BUILT_IN_WORK_TYPES.find((item) =>
-      [item.name, ...(item.aliases || [])].some((n) =>
-        isSameWorkTypeName(n, name)
-      )
-    );
-    if (byName) {
-      return byName;
-    }
+  // 1) 作业类型名称(后端字典值)
+  const byName = findByWorkTypeName(
+    BUILT_IN_WORK_TYPES,
+    workTypeName,
+    (item) => [item.name, ...(item.aliases || [])]
+  );
+  if (byName) {
+    return byName;
   }
-  const code =
-    workType === undefined || workType === null ? '' : String(workType).trim();
+  // 2) 编码兜底:内置字典码,或源系统编码 HO_PERMIT_*
+  const code = normalizeWorkTypeName(workType);
   if (code) {
     const byCode = BUILT_IN_WORK_TYPES.find(
       (item) => item.code === code || item.sourceCode === code