Commit b909fba1 by qlintonger xeno

feat: 新增双向对比基本算法逻辑

parent 09a08709
......@@ -69,6 +69,10 @@
<PARA>Ref. EM TASK 71-00-02-000-026-B00 (A5-PPBU) - Remove The EBU Fan Case Brackets, Removal-026.</PARA>
</L2ITEM>
<L2ITEM>
<PARAC>拆卸EBU风扇机匣支架,按EM TASK 71-00-02-000-026-B00--EDC。</PARAC>
<PARA>Ref. EM TASK 71-00-02-000-026-B00 (A5-PPBU) - Remove The EBU Fan Case Brackets, Removal-026--EDC.</PARA>
</L2ITEM>
<L2ITEM>
<PARAC>拆卸低压中压机匣支架,按EM TASK 71-00-02-000-027-B00。</PARAC>
<PARA>Ref. EM TASK 71-00-02-000-027-B00 (A5-PPBU) - Remove The LP Compressor/Intermediate Case Brackets, Removal-027.</PARA>
</L2ITEM>
......
......@@ -9,17 +9,17 @@
<CEP>
<EFFECT EFFRG="001999"></EFFECT>
<TITLEC>发动机QEC拆卸(V2500-A5系列)</TITLEC>
<TITLE>Remove the Engine's QEC(V2500-A5 series)</TITLE>
<TITLE>Remove the Engine's QEC(V2500-A5 series)123</TITLE>
<TOPIC CK-LEVEL="C">
<TITLEC>飞机/发动机基本信息123</TITLEC>
<TITLEC>飞机/发动机基本信息</TITLEC>
<TITLE>AIRCRAFT/ENGINE INFORMATION</TITLE>
<STEP CK-LEVEL="C">
<EFFECT EFFRG="001999"></EFFECT>
<RECORD-LINE>
<PARAC>发动机序号</PARAC>
<PARA>Engine SN</PARA>
<RECORD></RECORD>
</RECORD-LINE>
<!-- <RECORD-LINE>-->
<!-- <PARAC>发动机序号</PARAC>-->
<!-- <PARA>Engine SN</PARA>-->
<!-- <RECORD></RECORD>-->
<!-- </RECORD-LINE>-->
<NOTE>
<PARAC>开始工作前请记录。</PARAC>
<PARA>Please record before starting work.</PARA>
......@@ -49,7 +49,7 @@
</STEP>
<STEP CK-LEVEL="C">
<EFFECT EFFRG="001999"></EFFECT>
<PARAC>按照EB-2020-V250-70-201最新版,完成发动机的出库检查---修改1</PARAC>
<PARAC>按照EB-2020-V250-70-201最新版,完成发动机的出库检查。</PARAC>
<PARA>Finish the engine outgoing check ref thelatest version of EB-2020-V250-70-201.</PARA>
<SIGNOFF/>
</STEP>
......@@ -69,6 +69,10 @@
<PARA>Ref. EM TASK 71-00-02-000-026-B00 (A5-PPBU) - Remove The EBU Fan Case Brackets, Removal-026.</PARA>
</L2ITEM>
<L2ITEM>
<PARAC>拆卸EBU风扇机匣支架,按EM TASK 71-00-02-000-026-B00--EDC。</PARAC>
<PARA>Ref. EM TASK 71-00-02-000-026-B00 (A5-PPBU) - Remove The EBU Fan Case Brackets, Removal-026--EDC.</PARA>
</L2ITEM>
<L2ITEM>
<PARAC>拆卸低压中压机匣支架,按EM TASK 71-00-02-000-027-B00。</PARAC>
<PARA>Ref. EM TASK 71-00-02-000-027-B00 (A5-PPBU) - Remove The LP Compressor/Intermediate Case Brackets, Removal-027.</PARA>
</L2ITEM>
......@@ -286,10 +290,10 @@
<PARAC>发动机QEC零件故检,清洗,集件和导线修理</PARAC>
<PARA>Remove the Engine's QEC</PARA>
<LIST1>
<!-- <L1ITEM>-->
<!-- <PARAC>使用清洗剂清洗拆下QEC件</PARAC>-->
<!-- <PARA>Clean all QEC parts with cleanser.</PARA>-->
<!-- </L1ITEM>-->
<L1ITEM>
<PARAC>使用清洗剂清洗拆下QEC件</PARAC>
<PARA>Clean all QEC parts with cleanser.</PARA>
</L1ITEM>
<L1ITEM>
<PARAC>检查右侧空气系统管路,对开口处堵上堵盖。参考EM 71-00-02。</PARAC>
<PARA>Inspect the air system tubes which installed on the engine&rsquo;s right side, Ref EM manual 71-00-02.</PARA>
......@@ -314,10 +318,10 @@
<PARAC>目视检查IDG。对开口处堵上堵盖。</PARAC>
<PARA>Visual inspect IDG.</PARA>
</L1ITEM>
<!-- <L1ITEM>-->
<!-- <PARAC>目视检查液压泵。</PARAC>-->
<!-- <PARA>Visual inspect hydraulic pump.</PARA>-->
<!-- </L1ITEM>-->
<L1ITEM>
<PARAC>目视检查液压泵。</PARAC>
<PARA>Visual inspect hydraulic pump.</PARA>
</L1ITEM>
<L1ITEM>
<PARAC>目视检查高压活门。对开口处堵上堵盖。</PARAC>
<PARA>Visual inspect high pressure bleed valve.</PARA>
......
// 引入 TreeRenderResult 类型,该类型定义在 @/lib/XMLProcessor/src/typing 模块中
import { TreeRenderResult } from '@/lib/XMLProcessor/src/typing';
import { NewTreeModification, OldTreeModification, TreeRenderResult, TreeRenderResultFlatted } from '@/lib/XMLProcessor/src/typing'
// 引入 UUID 类用于生成唯一标识符
import { UUID } from 'uuidjs';
import { UUID } from 'uuidjs'
import { md5 } from 'js-md5'
// 定义 Processing 类,用于处理 XML 数据
export class Processing {
// 私有属性,用于解析 XML 字符串为 DOM 对象
private domParser: DOMParser;
private domParser: DOMParser
private xmlSerializer: XMLSerializer
// 构造函数,初始化 DOMParser 实例
constructor() {
this.domParser = new DOMParser();
this.xmlSerializer = new XMLSerializer();
this.domParser = new DOMParser()
this.xmlSerializer = new XMLSerializer()
}
serializeXML(xmlDOM: Document): string {
return this.xmlSerializer.serializeToString(xmlDOM);
return this.xmlSerializer.serializeToString(xmlDOM)
}
dualCompareFromString(xmlStringA: string, xmlStringB: string, bothHandledNode: string[]) {
const treeA = this.domParser.parseFromString(xmlStringA, 'text/xml');
const treeB = this.domParser.parseFromString(xmlStringB, 'text/xml');
const resultA = this.innerHandle(treeA.documentElement, bothHandledNode);
private flattenTree(renderResult: TreeRenderResult[]): TreeRenderResultFlatted[] {
const resp: TreeRenderResultFlatted[] = []
for (const item of renderResult) {
resp.push({
key: item.key,
label: item.label,
hash: item.hash,
index: item.index,
chained: item.chained
})
if (item.children) {
resp.push(...this.flattenTree(item.children))
}
}
return resp
}
dualCompareFromString(
xmlStringOld: string,
xmlStringNew: string,
bothHandledNode: string[]
): {
dataForNew: NewTreeModification
dataForOld: OldTreeModification
domOld: Document
domNew: Document
treeOld: TreeRenderResult[]
treeNew: TreeRenderResult[]
} {
const treeA = this.domParser.parseFromString(xmlStringOld, 'text/xml')
const treeB = this.domParser.parseFromString(xmlStringNew, 'text/xml')
const resultA = this.innerHandle(treeA.documentElement, bothHandledNode)
const resultB = this.innerHandle(treeB.documentElement, bothHandledNode)
treeA.documentElement.querySelectorAll(':not([data-key])').forEach((node) => node.remove())
treeB.documentElement.querySelectorAll(':not([data-key])').forEach((node) => node.remove())
console.log('both -res', {resultA, resultB})
// 扁平化所有节点
const resultAFlatted = this.flattenTree(resultA)
const resultBFlatted = this.flattenTree(resultB)
const dataForOld: OldTreeModification = {
Changed: [],
Deleted: []
}
const dataForNew: NewTreeModification = {
Changed: [],
Added: []
}
// 获取老节点中hash不存在的节点
let nonExistedHashNodeForOld: TreeRenderResultFlatted[] = resultAFlatted.filter((item) => {
return !resultBFlatted.find((itemB) => itemB.hash === item.hash && itemB.chained.join('$') === item.chained.join('$'))
})
let nonExistedHashNodeForNew: TreeRenderResultFlatted[] = resultBFlatted.filter((item) => {
return !resultAFlatted.find((itemA) => itemA.hash === item.hash && itemA.chained.join('$') === item.chained.join('$'))
})
const hashDiffInOld: TreeRenderResultFlatted[] = nonExistedHashNodeForOld.filter(
(a) => !nonExistedHashNodeForNew.find((v) => v.hash === a.hash)
)
const hashDiffInNew: TreeRenderResultFlatted[] = nonExistedHashNodeForNew.filter(
(a) => !nonExistedHashNodeForOld.find((v) => v.hash === a.hash)
)
let nodeUpdatedForOld: TreeRenderResultFlatted[] = []
let nodeUpdatedForNew: TreeRenderResultFlatted[] = []
for (const item of hashDiffInOld) {
const sameIndexFound = hashDiffInNew.find((a) => a.chained.join('$') === item.chained.join('$'))
if (sameIndexFound) {
nodeUpdatedForOld.push(item)
nodeUpdatedForNew.push(sameIndexFound)
}
}
let newNodeInserted: TreeRenderResultFlatted[] = []
for (const item of hashDiffInNew) {
if (!nodeUpdatedForOld.find(a=>a.hash === item.hash) && !nodeUpdatedForNew.find(a=>a.hash ===item.hash)) {
newNodeInserted.push(item)
}
}
let oldNodeDeleted: TreeRenderResultFlatted[] = []
for (const item of hashDiffInOld) {
if (!nodeUpdatedForNew.find(a=>a.hash === item.hash) && !nodeUpdatedForOld.find(a=>a.hash ===item.hash)) {
oldNodeDeleted.push(item)
}
}
dataForOld.Changed = nodeUpdatedForOld
dataForOld.Deleted = oldNodeDeleted
dataForNew.Changed = nodeUpdatedForNew
dataForNew.Added = newNodeInserted
return {
dataForNew,
dataForOld,
domOld: treeA,
domNew: treeB,
treeOld: resultA,
treeNew: resultB
}
}
// 处理 XML 字符串的方法,返回树形数据和 XML DOM 对象
processXML(xmlContent: string, handledNode: string[]): {
treeData: TreeRenderResult[];
xmlDOM: Document;
processXML(
xmlContent: string,
handledNode: string[]
): {
treeData: TreeRenderResult[]
xmlDOM: Document
xmlContent: string
} {
// 使用 DOMParser 解析 XML 字符串
const parsedTree = this.domParser.parseFromString(xmlContent, 'text/xml');
const parsedTree = this.domParser.parseFromString(xmlContent, 'text/xml')
// 获取 XML 文档的根元素
const rootElement = parsedTree.documentElement;
const rootElement = parsedTree.documentElement
const result = {
// 调用 innerHandle 方法处理根元素,生成树形数据
treeData: this.innerHandle(rootElement, handledNode),
......@@ -54,41 +142,48 @@ export class Processing {
}
// 异步处理 XML 文件的方法,返回包含树形数据和 XML DOM 对象的 Promise
async processFile(xmlFile: File, handledNode: string[]): Promise<{ treeData: TreeRenderResult[]; xmlDOM: Document;xmlContent: string }> {
async processFile(
xmlFile: File,
handledNode: string[]
): Promise<{
treeData: TreeRenderResult[]
xmlDOM: Document
xmlContent: string
}> {
// 检查文件是否为有效的 XML 文件
if (!(xmlFile instanceof File) || !xmlFile.type.includes('xml')) {
return Promise.reject('The file is not a valid XML file.');
return Promise.reject('The file is not a valid XML file.')
}
return new Promise((resolve, reject) => {
const fr = new FileReader();
const fr = new FileReader()
// 当文件读取完成时触发的事件处理函数
fr.onload = () => {
const content = fr.result as string;
const content = fr.result as string
try {
// 调用 processXML 方法处理读取的文件内容
const { treeData, xmlDOM, xmlContent } = this.processXML(content, handledNode);
const { treeData, xmlDOM, xmlContent } = this.processXML(content, handledNode)
// 解析成功,返回树形数据和 XML DOM 对象
resolve({ treeData, xmlDOM, xmlContent });
resolve({ treeData, xmlDOM, xmlContent })
} catch (error) {
// 解析失败,拒绝 Promise 并返回错误信息
reject(error);
reject(error)
}
};
}
// 当文件读取出错时触发的事件处理函数
fr.onerror = () => {
reject('Error reading file.');
};
reject('Error reading file.')
}
// 以文本形式读取文件
fr.readAsText(xmlFile);
});
fr.readAsText(xmlFile)
})
}
// 私有方法,用于递归处理单个 DOM 节点,生成树形数据
private innerHandle(domNode: Element, handledNode: string[]): TreeRenderResult[] {
let treeData: TreeRenderResult[] = [];
let treeData: TreeRenderResult[] = []
// 生成唯一的 key
let targetKey = domNode.getAttribute('data-key');
let targetKey = domNode.getAttribute('data-key')
if (!targetKey) {
targetKey = 'g-' + UUID.generate()
}
......@@ -100,37 +195,37 @@ export class Processing {
index: 0,
chained: [0],
hash: md5.hex(domNode.textContent! || '')
};
}
// 为 DOM 节点设置 data-key 属性
domNode.setAttribute('data-key', targetKey);
domNode.setAttribute('data-key', targetKey)
domNode.setAttribute('data-w-e-type', domNode.nodeName)
domNode.setAttribute('data-indent-level', '0')
// 递归处理子节点
treeItem.children = this.innerGroupHandle(domNode.children, handledNode, [0]);
treeItem.children = this.innerGroupHandle(domNode.children, handledNode, [0])
// 将树形数据项添加到结果数组中
treeData.push(treeItem);
treeData.push(treeItem)
return treeData;
return treeData
}
// 私有方法,用于递归处理一组 DOM 节点,生成树形数据
private innerGroupHandle(nodeSet: HTMLCollection, handledNode: string[], startChained: number[]): TreeRenderResult[] {
let targetResult: TreeRenderResult[] = [];
let realIndex = -1;
let targetResult: TreeRenderResult[] = []
let realIndex = -1
// 遍历节点集合
for (let i = 0; i < nodeSet.length; i++) {
const node = nodeSet[i] as Element;
const node = nodeSet[i] as Element
// 检查节点是否在处理列表中
if (!handledNode.includes(node.nodeName)) {
// 如果节点有子节点,递归处理子节点
if (node.children.length) {
targetResult.push(...this.innerGroupHandle(node.children, handledNode, startChained));
targetResult.push(...this.innerGroupHandle(node.children, handledNode, startChained))
}
continue;
continue
}
realIndex++;
realIndex++
// 生成唯一的 key
let targetKey = node.getAttribute('data-key');
let targetKey = node.getAttribute('data-key')
if (!targetKey) {
targetKey = 'g-' + UUID.generate()
}
......@@ -141,18 +236,18 @@ export class Processing {
index: realIndex,
chained: [...startChained, realIndex],
hash: md5.hex(node.textContent! || '')
};
}
// 为 DOM 节点设置 data-key 属性
node.setAttribute('data-key', targetKey);
node.setAttribute('data-key', targetKey)
node.setAttribute('data-w-e-type', node.nodeName)
node.setAttribute('data-indent-level', startChained.length.toString())
// 如果节点有子节点,递归处理子节点
if (node.children.length > 0) {
treeItem.children = this.innerGroupHandle(node.children, handledNode, [...startChained, realIndex]);
treeItem.children = this.innerGroupHandle(node.children, handledNode, [...startChained, realIndex])
}
// 将树形数据项添加到结果数组中
targetResult.push(treeItem);
targetResult.push(treeItem)
}
return targetResult;
return targetResult
}
}
\ No newline at end of file
}
......@@ -7,11 +7,12 @@ import {nodeSet} from '@/views/editor/constants/nodeParsed.ts'
const p = new Processing()
// @ts-ignore
window.$p = function() {
p.dualCompareFromString(
let nodeV = p.dualCompareFromString(
TextA,
TextB,
nodeSet
)
console.log('v-h', nodeV)
}
export const XMLProcessing: Plugin = function(app) {
app.provide('xmlProcessing', p);
......
......@@ -5,4 +5,22 @@ export type TreeRenderResult = {
hash: string,
index: number,
chained: number[]
}
export type TreeRenderResultFlatted = {
key: string,
label: string,
hash: string,
index: number,
chained: number[]
}
export type OldTreeModification = {
Changed: TreeRenderResultFlatted[],
Deleted: TreeRenderResultFlatted[]
}
export type NewTreeModification = {
Added: TreeRenderResultFlatted[],
Changed: TreeRenderResultFlatted[],
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment