Browse Source

用户输入RFID前道+绑定+Converting可以批量新增工序

master
han\hanst 3 weeks ago
parent
commit
bb9eba36e5
  1. 207
      src/views/modules/erf/components/expTriConfirm.vue

207
src/views/modules/erf/components/expTriConfirm.vue

@ -359,12 +359,13 @@
<el-form-item>
<template slot="label">
<span style="color: #909399; font-size: 12px; ">
支持多种输入RFID前道+绑定+Converting RFID前道绑定Converting
支持多种输入RFID前道+绑定+Converting 1.RFID前道 2.绑定 RFID前道绑定
</span>
</template>
<el-input
v-model="batchProcessInput"
@blur="handleBatchInput"
ref="batchInput"
@keyup.enter.native="handleBatchInput"
placeholder="输入工序名称后按回车或失去焦点自动识别">
</el-input>
@ -423,10 +424,10 @@
</el-table>
<div slot="footer">
<el-button @click="batchAddDialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirmBatchCreate" :disabled="validBatchCount === 0" :loading="batchCreating">
批量创建{{ validBatchCount }}
</el-button>
<el-button @click="batchAddDialogVisible = false">取消</el-button>
</div>
</el-dialog>
@ -744,10 +745,15 @@ export default {
this.batchProcessList = []
this.batchAddDialogVisible = true
this.loadTemplateList()
//
this.$nextTick(() => {
this.$refs.batchInput.focus();
});
},
/**
* 处理批量输入失去焦点或回车时触发
* 智能解析多种输入格式支持模糊匹配模板
*/
handleBatchInput() {
if (!this.batchProcessInput || !this.batchProcessInput.trim()) {
@ -755,45 +761,62 @@ export default {
return
}
//
let text = this.batchProcessInput
text = text.replace(/\+/g, '\n')
.replace(/、/g, '\n')
.replace(/,/g, '\n')
.replace(/,/g, '\n')
.replace(/;/g, '\n')
.replace(/;/g, '\n')
.replace(/\|/g, '\n')
const names = text.split('\n')
let text = this.batchProcessInput.trim()
//
const hasExplicitSeparator = /[\+、,,;;\|]/.test(text) ||
/\d+[\.\)]/.test(text) ||
/然后|接着|再做|再进行|之后/.test(text)
//
text = text
// 1. 2. 1) 2) 1 2
.replace(/\d+[\.\)、]\s*/g, '\n')
//
.replace(/[一二三四五六七八九十]+[、\.\)]\s*/g, '\n')
.replace(/第[一二三四五六七八九十]+[步道序个]\s*/g, '\n')
//
.replace(/[\+、,,;;\|]/g, '\n')
//
.replace(/然后|接着|再做|再进行|之后/g, '\n')
//
if (!hasExplicitSeparator) {
text = text.replace(/\s+/g, '\n')
} else {
//
text = text.replace(/\s{2,}/g, '\n')
}
//
let names = text.split('\n')
.map(n => n.trim())
.filter(n => n.length > 0)
.filter(n => n.length > 1 && !/^[\d\s]+$/.test(n)) //
if (names.length === 0) {
this.batchProcessList = []
this.$message.warning('未识别到有效的工序名称')
return
}
//
const uniqueNames = [...new Set(names)]
//
const uniqueNames = this.smartDeduplication(names)
//
//
this.batchProcessList = uniqueNames.map(name => {
const template = this.templateList.find(t =>
t.templateName === name || t.templateName.includes(name) || name.includes(t.templateName)
)
const matchResult = this.smartMatchTemplate(name)
if (template) {
if (matchResult.template) {
return {
processStep: name,
processStep: matchResult.useName, // 使
matched: true,
prodApproverName: template.prodApproverName,
prodApproverUserId: template.prodApproverUserId,
qaApproverName: template.qaApproverName,
qaApproverUserId: template.qaApproverUserId,
techApproverName: template.techApproverName,
techApproverUserId: template.techApproverUserId,
remark: template.remark || ''
prodApproverName: matchResult.template.prodApproverName,
prodApproverUserId: matchResult.template.prodApproverUserId,
qaApproverName: matchResult.template.qaApproverName,
qaApproverUserId: matchResult.template.qaApproverUserId,
techApproverName: matchResult.template.techApproverName,
techApproverUserId: matchResult.template.techApproverUserId,
remark: matchResult.template.remark || ''
}
}
@ -809,6 +832,132 @@ export default {
remark: ''
}
})
//
const matchedCount = this.batchProcessList.filter(p => p.matched).length
if (matchedCount > 0) {
this.$message.success(`识别${uniqueNames.length}个工序,自动匹配${matchedCount}个模板`)
}
},
/**
* 智能去重 - 识别相似工序名
* 例如: "RFID前道" "RFID 前道" 会被识别为同一个
*/
smartDeduplication(names) {
const normalized = names.map(name => ({
original: name,
normalized: name.replace(/\s+/g, '').toLowerCase()
}))
const unique = []
const seen = new Set()
for (const item of normalized) {
if (!seen.has(item.normalized)) {
seen.add(item.normalized)
unique.push(item.original)
}
}
return unique
},
/**
* 智能模板匹配算法
* @param {string} inputName - 用户输入的工序名称
* @return {Object} { template, useName }
*/
smartMatchTemplate(inputName) {
if (!this.templateList || this.templateList.length === 0) {
return { template: null, useName: inputName }
}
let bestMatch = null
let bestScore = 0
let bestUseName = inputName
for (const template of this.templateList) {
const templateName = template.templateName
const score = this.calculateMatchScore(inputName, templateName)
if (score > bestScore) {
bestScore = score
bestMatch = template
// 使
bestUseName = score >= 80 ? templateName : inputName
}
}
// 60
if (bestScore >= 60) {
return { template: bestMatch, useName: bestUseName }
}
return { template: null, useName: inputName }
},
/**
* 计算两个字符串的匹配得分0-100
* 综合考虑完全匹配包含关系相似度
*/
calculateMatchScore(input, template) {
const inputNorm = input.replace(/\s+/g, '').toLowerCase()
const templateNorm = template.replace(/\s+/g, '').toLowerCase()
// 1. - 100
if (inputNorm === templateNorm) return 100
// 2. - 90
if (templateNorm.includes(inputNorm) || inputNorm.includes(templateNorm)) {
return 90
}
// 3. -
let commonChars = 0
for (const char of inputNorm) {
if (templateNorm.includes(char)) commonChars++
}
const containScore = (commonChars / Math.max(inputNorm.length, templateNorm.length)) * 70
// 4.
const distance = this.levenshteinDistance(inputNorm, templateNorm)
const maxLen = Math.max(inputNorm.length, templateNorm.length)
const similarityScore = (1 - distance / maxLen) * 80
//
return Math.max(containScore, similarityScore)
},
/**
* 计算 Levenshtein 编辑距离
* 用于衡量两个字符串的相似程度
*/
levenshteinDistance(str1, str2) {
const len1 = str1.length
const len2 = str2.length
const matrix = []
//
for (let i = 0; i <= len1; i++) matrix[i] = [i]
for (let j = 0; j <= len2; j++) matrix[0][j] = j
//
for (let i = 1; i <= len1; i++) {
for (let j = 1; j <= len2; j++) {
if (str1[i - 1] === str2[j - 1]) {
matrix[i][j] = matrix[i - 1][j - 1]
} else {
matrix[i][j] = Math.min(
matrix[i - 1][j] + 1, //
matrix[i][j - 1] + 1, //
matrix[i - 1][j - 1] + 1 //
)
}
}
}
return matrix[len1][len2]
},
/**

Loading…
Cancel
Save