const fs = require('fs') const path = require('path') const { modules } = require('./capture-full-manual-pages') const root = path.resolve(__dirname, '..', '..') const outputPath = path.join(__dirname, 'full-page-catalog.json') const purposes = { '设备信息维护': '维护设备名称、公司编码、生产用名、规格型号、设备类型、使用部门、数量、状态及维修记录,为工艺能力、工位绑定和设备数据查询提供设备主数据。', '设备数据': '按工位查看设备运行数据及当前采集状态,用于现场设备状态监控和生产运行判断。', '设备历史数据': '按设备、工位和时间范围追溯历史采集值,用于故障分析、运行复盘和数据导出。', '实时数据': '查看设备最新实时采集值和更新时间,快速判断设备连接及当前运行状态。', '设计任务': '建立、分派和维护设计任务,记录项目、物料、设计要求、计划时间、可见人员、批示、附件及完成状态。', '设计报工': '由设计人员对被授权的设计任务执行开始、结束和说明登记,形成设计工时与进度记录。', '设计工时校验': '由授权人员复核设计报工的开始时间、结束时间、计算工时和备注,形成已校验状态。', '设计工时报表': '按作业者或任务汇总设计工时,支持条件查询、树形展开和结果导出。', '工序管理': '维护工艺分类、工序名称、简称及工艺要求,为标准工艺和生产工艺编制提供基础工序字典。', '制定标准工艺': '按物料建立可复用的标准工艺路线,维护工序顺序、设备、工时和工艺要求。', '生产工艺': '根据生产订单和物料生成、编辑、复制并启用本次生产工艺,可将工艺任务下发到计划排产。', '工艺查询': '按物料、订单等条件查看已维护的工艺路线及工序明细,供生产、计划和质量人员核对。', '工艺任务': '查询待编制或待下发工艺的生产订单任务,进入对应工艺处理流程。', '图纸维护': '维护物料对应的零件图纸及版本,支持上传、查看、替换、下载和删除记录查询。', '工艺维护': '维护工艺相关图纸及名称,使工序和工艺路线能够关联正确的技术文件。', '查看图纸': '以只读方式按物料、图号等条件查找和预览零件图纸。', '采购图纸查询': '供采购场景按物料或图号查询所需图纸,支持只读预览和下载。', '机加件排产': '对待排产机加工序选择工位、指派数量并维护计划开始、完成和最晚开始时间,批量形成机加计划。', '装配件排产': '对装配任务选择工位、人员和计划时间,形成装配执行任务。', '机加件已排产': '查询已形成计划的机加任务,并按订单、物料、工序、工位和日期核对排产结果。', '机加件未排产': '汇总尚未完成排产的机加工序,定位缺少工位、数量或计划时间的任务。', '优先装配': '维护需要优先处理的装配订单或任务,为装配排产和现场执行提供优先级依据。', '计划用表': '以计划人员使用的综合表格查看订单、物料、工艺、计划时间和任务状态。', '装配未排产': '查询尚未形成装配计划的任务,支持按订单、物料和日期范围筛选。', '生产订单关闭': '查询可关闭或已关闭的生产订单,并执行订单关闭状态维护。', '工位任务汇总': '按工位汇总计划任务、数量、时间和状态,用于检查工位负荷及任务分布。', '装配已排产': '查询已排产装配任务及其工位、人员、数量和计划时间。', '系统类装配任务': '维护和查看系统类产品的装配任务、工位分配及计划执行状态。', '阀类装配任务': '维护和查看阀类产品的装配任务、工位分配及计划执行状态。', '及时齐套跟踪结果': '汇总物料齐套跟踪结果,展示任务是否按计划具备投产或装配条件。', '生产计划跟踪': '综合查看生产订单从计划、工艺、排产到执行的进度与状态。', '加工中心': '供机加现场查询本人或工位任务,并执行开工、暂停、报工、收料、自检、异常和图纸查看等生产操作。', '过程异常管控': '集中查询和处理生产过程中登记的异常,跟踪异常类型、责任、状态和处理结果。', '工时校验': '对生产报工形成的工时记录进行核对和校验,修正异常时长并保留校验状态。', '外协管理': '管理生产外协任务的发料、收料、数量和状态,连接内部生产订单与外协执行。', '人员绑定': '将人员与工位、设备或生产资源建立绑定关系,决定现场任务和报工的人员范围。', '装配中心': '供装配现场执行开始、结束、送检、收验、领料、自检、异常和图纸查看等操作。', '班次管理': '维护班次名称、班次类型及工作时间,为人员、设备和工时计算提供班次基础数据。', '工时报表': '按项目、人员、任务或设备汇总生产工时,并支持日期过滤和 Excel 导出。', '加急件管理': '登记和跟踪加急生产任务,维护加急数量、状态及相关订单信息。', '拣配任务': '查看和处理生产物料拣配任务,跟踪拣配数量和完成状态。', '采购外协管理': '跟踪采购外协任务的订单、发料、到货、收料和完成情况。', '工时查询': '按人员、订单、物料、工序和日期查询生产工时明细。', '机加正在进行中': '实时查看正在机加执行的人员、设备、任务及开始时间。', '装配状态': '实时查看装配任务的当前执行、送检、收验和完成状态。', '外协报表': '按订单、供应商、物料和日期汇总外协发料、收料及完成数据。', '工时修正': '对满足权限和状态条件的生产工时记录进行修正,并保留修改依据。', '物料机器人': '查询 AGV 物料搬运任务的起点、终点、状态和时间,并在授权情况下处理任务状态。', '手续确认报表': '汇总订单或任务相关手续的确认状态,供生产和发货前核查。', '发货通知列表': '查询发货通知及其订单、物料、数量、状态和关联文件,供生产与销售协同。', '结算工时': '按任务和人员结算可计入的生产工时,形成结算口径的工时结果。', '机加及时开工': '对比机加计划开始时间与实际开工状态,识别未按时开工任务。', '外协及时开工': '对比外协计划与实际执行状态,识别未按时开始的外协任务。', '加急任务列表': '集中展示加急任务、当前环节和完成状态,提示相关人员优先处理。', '装配及时送检': '对比装配计划和实际送检时间,识别未按时送检任务。', '终检': '处理产品最终检验任务,登记检验数量、合格数量、不合格数量和检验结果。', '采购入库检': '处理采购物料入库前检验,关联采购到货、物料和质量标准。', '销售退货检': '处理销售退货物料的质量检验并记录判定结果。', '原材料退库检': '处理原材料退库前检验,记录质量状态和处置依据。', '序检收检': '处理工序间送检和收检任务,连接生产报工与后续工序放行。', '质量检验标准': '查询和维护物料、工序对应的检验项目、标准和判定要求。', '其他入库检': '处理非采购等其他来源的入库检验任务。', '质检明细': '按订单、物料、检验类型和日期查询质量检验记录明细。', '不合格品处置': '登记不合格品的评审、返工、让步、报废等处置结论并跟踪状态。', '质检报工': '由检验人员执行开始、结束、送检和收验等质量任务操作并形成质检工时。', '测试装配任务': '处理测试类装配和检验任务,记录执行数量、状态及结果。', '及时检验报表': '统计检验任务是否按计划及时完成,支持责任和日期维度分析。', '产品合格率(工位)': '按工位汇总检验数量、合格数量和合格率,用于质量绩效分析。', '销售订单状态': '综合展示销售订单对应生产订单的计划、齐套、拣配、发料、装配、入库和发货状态。' } const moduleRelations = { '设备管理': '上游使用系统工位、部门和设备主数据;设备能力和采集数据向工艺编制、计划排产、生产监控、异常分析提供设备依据。', '研发管理': '上游使用人员、角色、项目、物料和附件;设计任务依次形成设计报工、工时校验和工时报表,并可为工艺、生产和项目跟踪提供设计进度。', '工艺管理': '上游接收 SAP/MES 生产订单、物料、图纸和设备信息;输出标准工艺、生产工艺和工艺任务,供计划排产、生产执行与质量检验使用。', '计划排产': '上游接收生产订单、物料、工艺路线、工位和人员;输出机加及装配任务、计划时间和优先级,供生产中心、异常提醒和齐套跟踪使用。', '生产管理': '上游接收已排产任务、工艺、人员、工位和物料;执行结果形成报工、工时、异常、外协、送检和发货协同数据,向质量、报表和销售状态反馈。', '异常提醒': '读取计划时间、实际开工、外协执行、加急标识和送检时间进行差异判断;结果供计划与生产人员跟进,不单独改变原业务单据。', '质量管理': '上游接收采购到货、生产送检、退货、物料和质量标准;检验及处置结果反馈生产状态、库存入库、不合格品处理和质量统计。', '销售订单管理': '汇总 SAP/MES 销售订单、生产订单、计划、齐套、拣配、发料、装配、入库和发货数据,形成面向订单的全流程状态视图。' } function normalizeText(value) { return String(value || '') .replace(//g, '') .replace(/<[^>]+>/g, '') .replace(/\{\{[^}]+\}\}/g, '') .replace(/ /g, ' ') .replace(/\s+/g, ' ') .trim() } function unique(values, limit = 60) { return [...new Set(values.map(normalizeText).filter(value => value && value.length <= 40))].slice(0, limit) } function extractSearchFields(template) { const firstTable = template.search(/= 0 ? template.slice(0, firstTable) : template.slice(0, 12000) const labels = [] const labelPatterns = [ /]*\blabel=["']([^"']+)["'][^>]*>/gi, /]*>([^<]{1,40})<\/span>/gi, /]*>([^<]{1,40})<\/label>/gi ] for (const pattern of labelPatterns) { let match while ((match = pattern.exec(prefix))) { const label = normalizeText(match[1]).replace(/[::]$/, '') if (label && !/^(至|表单|日程|首页)$/.test(label)) labels.push(label) } } const placeholders = [] const placeholderPattern = /\bplaceholder=["']([^"']+)["']/gi let match while ((match = placeholderPattern.exec(prefix))) { const value = normalizeText(match[1]).replace(/^(请输入|请选择|输入|选择)/, '') if (value && value.length <= 30) placeholders.push(value) } return unique([...labels, ...placeholders], 30) } function extractButtons(template) { const values = [] const pattern = /<(?:el-button|button)\b[^>]*>([\s\S]*?)<\/(?:el-button|button)>/gi let match while ((match = pattern.exec(template))) { const value = normalizeText(match[1]) if (value && value.length <= 24) values.push(value) } return unique(values, 30) } function extractAttributes(template, tag, attribute, limit) { const values = [] const pattern = new RegExp(`<${tag}\\b[^>]*\\b${attribute}=["']([^"']+)["'][^>]*>`, 'gi') let match while ((match = pattern.exec(template))) values.push(match[1]) return unique(values, limit) } function extractProcedures(source, importedSources) { const read = [] const write = [] const directPattern = /CreateData\s*\(\s*["'](11|12)["']\s*,\s*["'`]([^"'`$]+)["'`]/g let match while ((match = directPattern.exec(source))) { (match[1] === '11' ? read : write).push(match[2]) } const apiPattern = /\bname\s*:\s*["'`]([^"'`$]+)["'`]/g for (const apiSource of importedSources) { while ((match = apiPattern.exec(apiSource))) { if (/查询|获取|列表|状态|select/i.test(match[1])) read.push(match[1]) else write.push(match[1]) } } return { read: unique(read, 20), write: unique(write, 20) } } function readImportedApiSources(source) { const sources = [] const pattern = /from\s+["']@\/api\/([^"']+)["']/g let match while ((match = pattern.exec(source))) { const apiPath = path.join(root, 'src', 'api', `${match[1]}.js`) if (fs.existsSync(apiPath)) sources.push(fs.readFileSync(apiPath, 'utf8')) } return sources } const catalog = [] let sequence = 0 for (let moduleIndex = 0; moduleIndex < modules.length; moduleIndex++) { const module = modules[moduleIndex] for (let pageIndex = 0; pageIndex < module.pages.length; pageIndex++) { sequence++ const [title, route, relativeSource] = module.pages[pageIndex] const sourcePath = path.join(root, 'src', 'views', relativeSource) const source = fs.readFileSync(sourcePath, 'utf8') const templateStart = source.indexOf('') const template = templateStart >= 0 && templateEnd > templateStart ? source.slice(templateStart + '