docs: update MES workflow and user manual
This commit is contained in:
@@ -175,6 +175,7 @@
|
||||
style="width: 100%; margin-top: 20px"
|
||||
tooltip-effect="dark"
|
||||
@row-click="handleRowClick"
|
||||
:row-class-name="tableRowClassName"
|
||||
>
|
||||
<el-table-column
|
||||
align="center"
|
||||
@@ -743,6 +744,14 @@ export default {
|
||||
this.loading = false;
|
||||
if (response.data.rows && response.data.rows.length !== 0) {
|
||||
this.tableData = response.data.rows;
|
||||
this.tableData.sort((a, b) => {
|
||||
const aIsUrgent = a.加急状态 === '1';
|
||||
const bIsUrgent = b.加急状态 === '1';
|
||||
|
||||
if (aIsUrgent && !bIsUrgent) return -1;
|
||||
if (!aIsUrgent && bIsUrgent) return 1;
|
||||
return 0;
|
||||
});
|
||||
this.total = response.data.total
|
||||
} else {
|
||||
this.tableData = [];
|
||||
@@ -1122,10 +1131,27 @@ export default {
|
||||
const seconds = String(date.getSeconds()).padStart(2, "0");
|
||||
return `${year}${month}${day}_${hours}${minutes}${seconds}`;
|
||||
},
|
||||
tableRowClassName({ row, rowIndex }) {
|
||||
const isUrgent = row.加急状态 == "1";
|
||||
if (isUrgent) {
|
||||
return "priority-row";
|
||||
}
|
||||
return "";
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
::v-deep .priority-row {
|
||||
background-color: #f56c6c !important;
|
||||
color: #000000 !important;
|
||||
}
|
||||
::v-deep .priority-row td {
|
||||
background-color: #f56c6c !important;
|
||||
color: #000000 !important;
|
||||
border: #f56c6c;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.search-container {
|
||||
margin-bottom: 20px;
|
||||
@@ -1343,4 +1369,4 @@ button {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
143
MES_Manage_View_V20/今日工作汇报_2026-05-26.md
Normal file
143
MES_Manage_View_V20/今日工作汇报_2026-05-26.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# 元利 MES 项目 — 今日工作汇报
|
||||
|
||||
日期:2026-05-26
|
||||
项目:MES_Manage_View_V20
|
||||
|
||||
## 一、今日主要工作
|
||||
|
||||
### 1. 丰富并修改元利项目详细流程图
|
||||
|
||||
今日继续完善 `元利项目详细流程图.md`,在原有系统级流程基础上,进一步补充页面级、业务级流程说明。
|
||||
|
||||
重点补充内容:
|
||||
- 登录、菜单权限、动态路由生成流程。
|
||||
- 工艺、图纸、生产订单、排产、生产执行、质检、外协、工时校验、生产订单关闭等模块之间的衔接关系。
|
||||
- 机加排产、装配排产、机加中心、装配中心、质量中心、工时校验等关键页面的详细业务流。
|
||||
- SAP 回写、SAP 查询、WMS/库存任务、MES 存储过程之间的数据流转关系。
|
||||
- 将流程图尽量调整为“框 + 箭头 + 文字”的形式,减少字母节点指引,便于培训和现场讲解。
|
||||
|
||||
本次调整后,流程图更适合用于:
|
||||
- 给客户讲解整体 MES 业务闭环。
|
||||
- 给实施人员定位页面与数据流关系。
|
||||
- 给开发人员判断新增需求影响范围。
|
||||
|
||||
### 2. 工时校验数据对接梳理
|
||||
|
||||
今日继续梳理工时校验页面与 MES/SAP 数据之间的对接关系,重点围绕 `ProductionManagement/WorkHoursCheck`。
|
||||
|
||||
已梳理内容:
|
||||
- 对接数据时发现装配人员工时数据错误,经检查由于用户重复提交导致的问题
|
||||
- 在排查过程中发现装配人员报工加班时,同时生成了正常报工的工时
|
||||
|
||||
|
||||
### 3. 生产订单关闭培训与相关数据处理
|
||||
|
||||
今日进行了生产订单关闭相关培训和数据处理,重点说明生产订单关闭页面的使用边界。
|
||||
|
||||
培训内容:
|
||||
- 生产订单关闭前需要先确认订单在 MES 中的任务完成情况。
|
||||
- 关闭前需要核对生产订单状态、入库情况、报工情况和 SAP 状态。
|
||||
- 批量关闭时要区分已成功关闭、关闭失败、不能关闭三类结果。
|
||||
- SAP 关闭失败时不应重复点击,应先确认 SAP 返回原因。
|
||||
|
||||
数据处理内容:
|
||||
- 协助检查生产订单关闭相关数据。
|
||||
- 梳理关闭条件与当前订单状态之间的关系。
|
||||
- 对异常数据进行核对,避免误关或重复关闭。
|
||||
|
||||
### 4. 沟通报工结果数据上传到 SAP 的影响
|
||||
|
||||
今日围绕报工结果上传 SAP 的影响进行了沟通和确认。
|
||||
|
||||
沟通重点:
|
||||
- 超过班次工作时间部分的工时 如果不选择加班,系统自动记录这段工时
|
||||
- 这段工时如果上次到SAP会导致其他生成订单工时不准确的问题,因为计算方法核算的是当日总报工时间记为8小时
|
||||
- 这段时间如果上传,就会导致其他工时减少
|
||||
- 休息日/法定时选择不加班工时记录的问题,讨论结果是MES正常记录 但是不传输给SAP
|
||||
|
||||
|
||||
### 5. 修改装配报工数据重复问题
|
||||
|
||||
今日处理装配报工数据重复问题。
|
||||
|
||||
处理重点:
|
||||
- 排查装配报工过程中可能重复写入的数据链路。
|
||||
- 核对装配任务、报工记录、质检/送检记录之间的关联关系。
|
||||
- 调整重复数据产生场景,避免同一任务重复形成报工结果。
|
||||
- 修改后重点关注装配中心报工、送检、任务完成状态的回显是否一致。
|
||||
|
||||
处理结果:
|
||||
- 已针对装配报工重复问题进行修正。
|
||||
- 后续需要继续观察现场报工数据,确认是否仍存在重复写入或重复统计。
|
||||
|
||||
### 6. 丰富并修改用户使用说明书
|
||||
|
||||
今日重点丰富 `元利项目详细用户使用说明书.md`。
|
||||
|
||||
主要修改内容:
|
||||
- 将第 21 章逐页说明整体扩展,不再只写笼统功能说明。
|
||||
- 对 78 个页面按源码逐页补充:
|
||||
- 页面用途
|
||||
- 具体操作步骤
|
||||
- 查询条件/输入项
|
||||
- 结果表重点列
|
||||
- 页面按钮/状态/页签
|
||||
- 弹窗/表单重点项
|
||||
- 后台处理/外部接口
|
||||
- 操作注意事项
|
||||
- 将第 21 章页面标题从英文页面名改为中文页面名,例如:
|
||||
- `WorkHoursCheck` 改为 `工时校验`
|
||||
- `SelfMakePlandone` 改为 `机加已排产`
|
||||
- `MachiningCenter` 改为 `机加中心`
|
||||
- `QualityCenter` 改为 `质量中心`
|
||||
- 对 `机加已排产` 章节进行了重点细化,补充日程拖拽、指派数量、拆分派工、二次派工、原料状态、图纸、外协分组、最晚开始、红色加急排序、SAP 日期同步等操作。
|
||||
|
||||
说明书修改后更适合:
|
||||
- 现场用户培训。
|
||||
- 新员工快速熟悉页面。
|
||||
- 实施人员按页面排查问题。
|
||||
- 后续新增需求评审时对照现有功能。
|
||||
|
||||
### 7. 修改原料退库检,增加加急显示
|
||||
|
||||
今日处理原料退库检页面加急显示需求。
|
||||
|
||||
涉及页面:
|
||||
- `QualityManagement/CheckTask/materialReturn.vue`
|
||||
|
||||
处理内容:
|
||||
- 在原料退库检任务中增加加急状态/加急信息显示。
|
||||
- 方便质检人员优先识别加急退库检任务。
|
||||
- 便于后续按加急任务排序、提醒或优先处理。
|
||||
|
||||
业务影响:
|
||||
- 质检人员在原料退库检页面可以更直观看到加急任务。
|
||||
- 加急退库检任务可优先处理,减少对生产或后续流程的影响。
|
||||
|
||||
## 二、今日产出与修改文件
|
||||
|
||||
| 文件 | 今日处理内容 |
|
||||
|---|---|
|
||||
| `元利项目详细流程图.md` | 丰富业务流程图,补充多页面、多模块数据流 |
|
||||
| `元利项目详细用户使用说明书.md` | 扩展第 21 章逐页操作说明,标题改为中文页面名 |
|
||||
| `ProductionManagement/WorkHoursCheck` | 梳理工时校验与 SAP 上传关系 |
|
||||
| `PlanManagement/PlannOrderClose` | 生产订单关闭培训与数据处理 |
|
||||
| 装配报工相关页面/数据 | 修正装配报工重复数据问题 |
|
||||
| `QualityManagement/CheckTask/materialReturn.vue` | 原料退库检增加加急显示 |
|
||||
|
||||
## 三、今日沟通事项
|
||||
|
||||
1. 与相关人员沟通工时校验数据上传 SAP 的影响,明确报工结果、工时、SAP 工序资源之间的关系。
|
||||
2. 对生产订单关闭进行培训,说明关闭前校验、关闭失败处理和数据风险。
|
||||
3. 结合装配报工重复问题,沟通现场报工操作和后台数据写入逻辑。
|
||||
4. 结合用户说明书和流程图,明确后续培训资料需要按页面逐步讲解,不能只写功能概述。
|
||||
|
||||
## 四、当前风险与注意事项
|
||||
|
||||
| 风险点 | 影响 | 处理建议 |
|
||||
|---|---|---|
|
||||
| 工时上传 SAP 重复提交 | 可能造成 SAP 工时或库存单据重复 | 上传失败时先查失败原因,不要连续重复提交 |
|
||||
| 生产订单关闭条件不一致 | 可能误关订单或关闭失败 | 关闭前核对 MES 任务、入库、报工和 SAP 状态 |
|
||||
| 装配报工重复 | 影响工时、任务进度、质检/送检统计 | 修复后继续观察现场数据 |
|
||||
| 加急任务未突出显示 | 质检处理优先级不明确 | 原料退库检已增加加急显示,后续可扩展排序 |
|
||||
| 用户手册仍需继续细化 | 培训时可能仍有页面操作细节不足 | 后续按重点业务页面继续逐页补强 |
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
101
tools/rename_manual_chapter21_titles.js
Normal file
101
tools/rename_manual_chapter21_titles.js
Normal file
@@ -0,0 +1,101 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const file = path.join(process.cwd(), 'MES_Manage_View_V20', '元利项目详细用户使用说明书.md');
|
||||
const text = fs.readFileSync(file, 'utf8');
|
||||
|
||||
const names = {
|
||||
'404.vue': '404 页面',
|
||||
PunctualWork: '及时开工异常',
|
||||
CraftMaintain: '产品结构维护',
|
||||
Devicedata: '设备采集数据',
|
||||
DeviceDataHistory: '设备历史数据',
|
||||
DeviceInformation: '设备信息维护',
|
||||
DeviceRealData: '设备实时数据',
|
||||
InstallMakePlan: '装配排产',
|
||||
InstallMakePlanDo: '装配已排产',
|
||||
PlannOrderClose: '生产订单关闭',
|
||||
PlanShell: '计划外壳跟踪',
|
||||
priorityinstall: '装配优先级调整',
|
||||
SelfMakePlan: '机加排产',
|
||||
SelfMakePlando: '机加待排产',
|
||||
SelfMakePlandone: '机加已排产',
|
||||
PartDrawing: '零件图纸维护',
|
||||
PartDrawlook: '零件图纸查看',
|
||||
ProcedureManagement: '工序维护',
|
||||
ProcessDrawing: '工艺图纸维护',
|
||||
ProcessesDevelop: '工艺开发',
|
||||
ProcessInquiry: '工艺查询',
|
||||
ProcessProduct: '生产工艺维护',
|
||||
ProcurementDrawlook: '采购图纸查看',
|
||||
ProductionOrder: '生产订单',
|
||||
AbnormalControl: '异常管控',
|
||||
AssemblePlanTrack: '装配计划跟踪',
|
||||
AssembleStatus: '装配状态',
|
||||
AssembleTaskManage: '装配任务管理',
|
||||
AssembleTasksSum: '装配任务汇总',
|
||||
AssemblyCenter: '装配中心',
|
||||
DeviceStatus: '设备状态',
|
||||
MachiningCenter: '机加中心',
|
||||
OutsourceMange: '外协管理',
|
||||
OutsourceSheet: '外协报表',
|
||||
PersonnelBinding: '人员绑定',
|
||||
PickingTask: '拣配任务',
|
||||
ProductionPlanTrack: '生产计划跟踪',
|
||||
ProductionTaskManage: '生产任务管理',
|
||||
ProductionTasksSum: '生产任务汇总',
|
||||
SaleOutsourceMange: '销售外协管理',
|
||||
ShiftManagement: '班次管理',
|
||||
Timesheet: '工时报表',
|
||||
Urgent: '加急任务',
|
||||
Workhours: '工时查询',
|
||||
'index - 副本.vue': '工时校验(副本)',
|
||||
WorkHoursCheck: '工时校验',
|
||||
WorkhoursEdit: '工时编辑',
|
||||
'final.vue': '终检',
|
||||
'firstSpecial.vue': '首检',
|
||||
'materialReturn.vue': '原材料退库检',
|
||||
'OtherInbound.vue': '其他入库检',
|
||||
'processReceive.vue': '序检收检',
|
||||
'processSpecial.vue': '过程特殊检验',
|
||||
'purchaseIncoming.vue': '采购入库检',
|
||||
'salesReturn.vue': '销售退货检',
|
||||
QualityCenter: '质量中心',
|
||||
QualityDetails: '质检明细',
|
||||
'index copy.vue': '质量标准查询(副本)',
|
||||
QualityStandardQuery: '质量标准查询',
|
||||
Unqualified: '不合格品处理',
|
||||
saleorderstatus: '销售订单状态',
|
||||
MenuManagement: '菜单管理',
|
||||
OperationLog: '操作日志',
|
||||
OrgManagement: '组织管理',
|
||||
PersonnelManagement: '人员管理',
|
||||
SystemRrolemaintenance: '系统角色维护',
|
||||
WorkstationManagement: '工位管理',
|
||||
dashboard: '首页看板',
|
||||
'AppMain.vue': '内容区域',
|
||||
'index.js': '布局组件索引',
|
||||
'Navbar.vue': '顶部导航',
|
||||
Sidebar: '侧边栏',
|
||||
'Item.vue': '侧边栏菜单项',
|
||||
'SidebarItem.vue': '侧边栏菜单节点',
|
||||
'TagsView.vue': '标签页导航',
|
||||
'Layout.vue': '系统布局',
|
||||
'ResizeHandler.js': '窗口自适应',
|
||||
login: '系统登录'
|
||||
};
|
||||
|
||||
const updated = text.replace(/^### (21\.\d+) (.+)$/gm, (match, num, oldName) => {
|
||||
const nextName = names[oldName.trim()];
|
||||
return nextName ? `### ${num} ${nextName}` : match;
|
||||
});
|
||||
|
||||
fs.writeFileSync(file, updated, 'utf8');
|
||||
|
||||
const missing = [...text.matchAll(/^### (21\.\d+) (.+)$/gm)]
|
||||
.map(m => m[2].trim())
|
||||
.filter(name => !names[name]);
|
||||
if (missing.length) {
|
||||
console.log(`missing mappings: ${[...new Set(missing)].join(', ')}`);
|
||||
}
|
||||
console.log('chapter 21 titles renamed');
|
||||
573
tools/rewrite_user_manual_pages.js
Normal file
573
tools/rewrite_user_manual_pages.js
Normal file
@@ -0,0 +1,573 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
const projectRoot = path.join(repoRoot, 'MES_Manage_View_V20');
|
||||
const viewsRoot = path.join(projectRoot, 'src', 'views');
|
||||
const manualPath = path.join(projectRoot, '元利项目详细用户使用说明书.md');
|
||||
|
||||
function readText(file) {
|
||||
const buf = fs.readFileSync(file);
|
||||
if (buf.length >= 3 && buf[0] === 0xef && buf[1] === 0xbb && buf[2] === 0xbf) {
|
||||
return buf.slice(3).toString('utf8');
|
||||
}
|
||||
if (buf.length >= 2 && buf[0] === 0xff && buf[1] === 0xfe) {
|
||||
return buf.slice(2).toString('utf16le');
|
||||
}
|
||||
return buf.toString('utf8');
|
||||
}
|
||||
|
||||
function writeText(file, text) {
|
||||
fs.writeFileSync(file, text, 'utf8');
|
||||
}
|
||||
|
||||
function walk(dir, out = []) {
|
||||
if (!fs.existsSync(dir)) return out;
|
||||
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
||||
const full = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) walk(full, out);
|
||||
else if (/\.(vue|js)$/i.test(entry.name)) out.push(full);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function rel(file) {
|
||||
return path.relative(projectRoot, file).replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
function clean(value) {
|
||||
return (value || '')
|
||||
.replace(/<!--[\s\S]*?-->/g, ' ')
|
||||
.replace(/<[^>]+>/g, ' ')
|
||||
.replace(/\{\{[\s\S]*?\}\}/g, ' ')
|
||||
.replace(/ /g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
function uniq(values) {
|
||||
const seen = new Set();
|
||||
const out = [];
|
||||
for (const value of values) {
|
||||
const v = String(value || '').trim();
|
||||
if (!v || seen.has(v)) continue;
|
||||
seen.add(v);
|
||||
out.push(v);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
function stripNoise(values) {
|
||||
return uniq(values)
|
||||
.filter(x => x.length <= 42)
|
||||
.filter(x => !/[{};]/.test(x))
|
||||
.filter(x => !/^(scope|row|item|index|true|false|null|undefined)$/i.test(x))
|
||||
.filter(x => !/^\d+$/.test(x));
|
||||
}
|
||||
|
||||
function extractAll(re, text, map) {
|
||||
const out = [];
|
||||
let match;
|
||||
while ((match = re.exec(text))) out.push(map(match));
|
||||
return out;
|
||||
}
|
||||
|
||||
function attr(attrs, name) {
|
||||
const m = new RegExp(`${name}="([^"]*)"`).exec(attrs);
|
||||
return m ? clean(m[1]) : '';
|
||||
}
|
||||
|
||||
function extractTemplate(text) {
|
||||
const start = text.search(/<template\b[^>]*>/i);
|
||||
if (start < 0) return text;
|
||||
const open = /<template\b[^>]*>/i.exec(text.slice(start));
|
||||
if (!open) return text;
|
||||
const contentStart = start + open.index + open[0].length;
|
||||
const scriptStart = text.search(/<script\b/i);
|
||||
const searchEnd = scriptStart >= 0 ? scriptStart : text.length;
|
||||
const close = text.lastIndexOf('</template>', searchEnd);
|
||||
if (close > contentStart) return text.slice(contentStart, close);
|
||||
return text.slice(contentStart, searchEnd);
|
||||
}
|
||||
|
||||
function extractScript(text) {
|
||||
const m = /<script\b[^>]*>([\s\S]*?)<\/script>/i.exec(text);
|
||||
return m ? m[1] : text;
|
||||
}
|
||||
|
||||
function extractPage(file) {
|
||||
const text = readText(file);
|
||||
const template = extractTemplate(text);
|
||||
const script = extractScript(text);
|
||||
const relative = rel(file);
|
||||
const parts = relative.split('/');
|
||||
const module = parts[2] || '根页面';
|
||||
const name = path.basename(file) === 'index.vue'
|
||||
? parts[parts.length - 2]
|
||||
: path.basename(file);
|
||||
|
||||
const labels = extractAll(/\blabel="([^"]+)"/g, template, m => clean(m[1]));
|
||||
const placeholders = extractAll(/\bplaceholder="([^"]+)"/g, template, m => clean(m[1]));
|
||||
const titles = extractAll(/\btitle="([^"]+)"/g, template, m => clean(m[1]));
|
||||
const formLabels = extractAll(/<el-form-item\b([^>]*)>/g, template, m => attr(m[1], 'label'));
|
||||
const tabLabels = extractAll(/<el-tab-pane\b([^>]*)>/g, template, m => attr(m[1], 'label'));
|
||||
const options = extractAll(/<el-option\b([^>]*)>/g, template, m => attr(m[1], 'label'));
|
||||
const buttons = extractAll(/<el-button\b([^>]*)>([\s\S]*?)<\/el-button>/g, template, m => {
|
||||
const textValue = clean(m[2]) || attr(m[1], 'title') || attr(m[1], 'aria-label');
|
||||
const click = attr(m[1], '@click') || attr(m[1], 'v-on:click');
|
||||
return textValue ? { text: textValue, click } : null;
|
||||
})
|
||||
.filter(Boolean)
|
||||
.filter(b => b.text.length <= 42)
|
||||
.filter(b => !/[{};]/.test(b.text));
|
||||
const tableColumns = extractAll(/<el-table-column\b([^>]*)>/g, template, m => {
|
||||
const label = attr(m[1], 'label');
|
||||
const prop = attr(m[1], 'prop');
|
||||
const type = attr(m[1], 'type');
|
||||
return label || prop || type ? { label, prop, type } : null;
|
||||
}).filter(Boolean);
|
||||
const vModels = extractAll(/\bv-model(?:\.[\w-]+)?="([^"]+)"/g, template, m => clean(m[1]));
|
||||
const params = extractAll(/\.(?:push|unshift)\s*\(\s*\[\s*['"]([^'"]+)['"]\s*,\s*([^\]\n]+)\]/g, script, m => ({
|
||||
name: clean(m[1]),
|
||||
expr: clean(m[2])
|
||||
}));
|
||||
const procs = extractAll(/CreateData\s*\(\s*['"]([^'"]+)['"]\s*,\s*['"]([^'"]+)['"]/g, script, m => ({
|
||||
type: m[1],
|
||||
name: clean(m[2])
|
||||
}));
|
||||
const sapCalls = extractAll(/\b(getB1|postB1|patchB1|posttm)\s*\(\s*([`'"])([\s\S]*?)\2/g, script, m => ({
|
||||
method: m[1],
|
||||
url: clean(m[3]).slice(0, 90)
|
||||
}));
|
||||
const dialogs = extractAll(/<el-dialog\b([\s\S]*?)>/g, template, m => {
|
||||
const title = attr(m[1], 'title') || clean((/:title="([^"]+)"/.exec(m[1]) || [])[1]);
|
||||
return title;
|
||||
});
|
||||
const methods = extractAll(/^\s*([A-Za-z_$\u4e00-\u9fa5][\w$\u4e00-\u9fa5]*)\s*\([^)]*\)\s*\{/gm, script, m => m[1]);
|
||||
const hasCalendar = /FullCalendar|@fullcalendar|eventDrop|eventResize/.test(text);
|
||||
const hasPagination = /el-pagination|pageSize|pageCurrent/.test(text);
|
||||
const hasUpload = /el-upload|上传|upload/i.test(text);
|
||||
const hasTree = /el-tree|treeData|Tree/.test(text);
|
||||
|
||||
return {
|
||||
file,
|
||||
relative,
|
||||
module,
|
||||
name,
|
||||
text,
|
||||
labels: stripNoise(labels),
|
||||
placeholders: stripNoise(placeholders),
|
||||
titles: stripNoise(titles),
|
||||
formLabels: stripNoise(formLabels),
|
||||
tabLabels: stripNoise(tabLabels),
|
||||
options: stripNoise(options),
|
||||
buttons,
|
||||
tableColumns,
|
||||
vModels: stripNoise(vModels),
|
||||
params,
|
||||
procs,
|
||||
sapCalls,
|
||||
dialogs: stripNoise(dialogs),
|
||||
methods: stripNoise(methods),
|
||||
hasCalendar,
|
||||
hasPagination,
|
||||
hasUpload,
|
||||
hasTree
|
||||
};
|
||||
}
|
||||
|
||||
function roleFor(page) {
|
||||
if (/SystemMaintenance|layout|login|dashboard|404/.test(page.relative)) return '系统管理员/相关用户';
|
||||
if (/QualityManagement/.test(page.relative)) return '质检员/质量主管';
|
||||
if (/PlanManagement/.test(page.relative)) return '计划员/生产主管';
|
||||
if (/ProductionManagement/.test(page.relative)) return '操作工/班组长/生产主管';
|
||||
if (/ProcessManagement|CraftManagement/.test(page.relative)) return '工艺员/技术人员';
|
||||
if (/DeviceManagement/.test(page.relative)) return '设备管理员/生产主管';
|
||||
if (/SaleManagement/.test(page.relative)) return '销售/计划/生产跟单人员';
|
||||
if (/AnomalousManagement/.test(page.relative)) return '班组长/生产主管/计划员';
|
||||
return '相关业务人员';
|
||||
}
|
||||
|
||||
function moduleName(page) {
|
||||
const map = {
|
||||
AnomalousManagement: '异常管理',
|
||||
CraftManagement: '产品结构维护',
|
||||
DeviceManagement: '设备管理',
|
||||
PlanManagement: '计划排产',
|
||||
ProcessManagement: '工艺与图纸管理',
|
||||
ProductionManagement: '生产执行管理',
|
||||
QualityManagement: '质量管理',
|
||||
SaleManagement: '销售与交付查询',
|
||||
SystemMaintenance: '系统维护',
|
||||
dashboard: '首页与看板',
|
||||
layout: '布局与导航',
|
||||
login: '登录',
|
||||
};
|
||||
if (page.relative === 'src/views/404.vue') return '错误页';
|
||||
return map[page.module] || page.module;
|
||||
}
|
||||
|
||||
function purpose(page) {
|
||||
const p = page.relative;
|
||||
const rules = [
|
||||
[/404\.vue$/, '该页面用于路由不存在或无效地址访问时展示 404 提示,帮助用户返回首页或重新选择菜单。'],
|
||||
[/login/, '该页面是系统登录入口,用户输入工号、密码并选择角色后进入 MES;同时提供修改密码功能。'],
|
||||
[/dashboard/, '该页面是系统首页/看板入口,用户登录后查看系统概览或进入各业务模块。'],
|
||||
[/PunctualWork/, '该页面用于查看未及时开工、待执行、可执行、已开工和已完成任务,帮助班组长或计划员催办生产开工。'],
|
||||
[/CraftMaintain/, '该页面用于维护产品结构树,支持新增、编辑、删除产品结构节点,为工艺、BOM 和生产任务提供层级基础资料。'],
|
||||
[/DeviceDataHistory/, '该页面用于查询设备历史采集数据,按工位、设备、参数和时间追溯设备运行记录。'],
|
||||
[/DeviceInformation/, '该页面用于维护设备台账、设备属性、维修/工时/点检相关信息。'],
|
||||
[/DeviceRealData|Devicedata/, '该页面用于查看设备实时数据或采集缓存数据,判断设备当前运行、报警和参数状态。'],
|
||||
[/SelfMakePlandone[\\/]/, '该页面用于机加/自制件已排产任务查看和调整,支持计划时间、指派对象、指派数量、最晚开始、二次派工和备注维护。'],
|
||||
[/SelfMakePlando[\\/]/, '该页面用于机加/自制件待排产任务处理,支持表单排产、日程拖拽调整、部分派工、批量排产、二次派工、原料状态和图纸查看。'],
|
||||
[/SelfMakePlan[\\/]/, '该页面用于机加/自制件排产前准备,查询生产订单工序任务并维护计划、工位、数量和说明后确认排产。'],
|
||||
[/InstallMakePlanDo|InstallMakePlan/, '该页面用于装配件排产,维护装配工位、人员、计划开始/完成、优先级、说明,并在排产完成时同步 SAP 或生成相关请求。'],
|
||||
[/PlanShell/, '该页面用于计划外壳和计划跟踪,集中查看订单计划、齐套、缺料、发货或关闭相关信息。'],
|
||||
[/PlannOrderClose/, '该页面用于关闭生产订单,用户查询待关闭订单后执行 MES/SAP 关闭动作。'],
|
||||
[/priorityinstall/, '该页面用于装配计划优先级和日程调整,支持表单和日程方式查看重点任务。'],
|
||||
[/ProductionOrder/, '该页面用于查询和同步生产订单,把 SAP/ERP 生产订单转成 MES 生产计划与工序任务。'],
|
||||
[/PartDrawing/, '该页面用于维护零件图纸,支持按物料查询、查看、上传/验证和删除图纸。'],
|
||||
[/PartDrawlook|ProcurementDrawlook/, '该页面用于按物料查看零件图纸,供生产、采购、外协或质检快速查阅技术文件。'],
|
||||
[/ProcessDrawing/, '该页面用于维护工艺图纸,支持查询、查看、上传/验证和删除工艺图纸。'],
|
||||
[/ProcedureManagement/, '该页面用于维护工序/路线阶段主数据,并与 SAP B1 RouteStages 保持一致。'],
|
||||
[/ProcessInquiry/, '该页面用于查询标准工艺或生产工艺,供排产、生产、质检核对工序路线。'],
|
||||
[/ProcessProduct|ProcessesDevelop/, '该页面用于维护产品工艺资料、工序路线、参数和图纸关系。'],
|
||||
[/MachiningCenter/, '该页面是机加生产执行主界面,操作工按工位执行收料、开工、暂停、报工、检验、退库、发料和图纸查看。'],
|
||||
[/AssemblyCenter/, '该页面是装配生产执行主界面,装配人员按工位执行开工、报工、送检、退库、缺料查询和图纸查看。'],
|
||||
[/ProductionTaskManage|AssembleTaskManage/, '该页面用于生产/装配任务管理,查询任务、查看工时、维护派工和任务说明。'],
|
||||
[/ProductionTasksSum|AssembleTasksSum/, '该页面用于生产/装配任务汇总,按订单、人员、工位、状态和时间统计任务执行情况。'],
|
||||
[/ProductionPlanTrack|AssemblePlanTrack/, '该页面用于跟踪生产/装配计划执行进度,查看计划、完成、延期和异常情况。'],
|
||||
[/AssembleStatus|DeviceStatus/, '该页面用于查看现场状态,关注工位、设备、任务是否开工、进行中或完成。'],
|
||||
[/OutsourceMange|SaleOutsourceMange/, '该页面用于外协任务管理,处理外协派工、供应商、发料、收料、质检记录和 SAP 采购请求。'],
|
||||
[/OutsourceSheet/, '该页面用于外协报表查询和导出,跟踪外协订单、供应商、数量、质检和结算状态。'],
|
||||
[/PickingTask/, '该页面用于生产领料/拣配任务查询与处理,核对订单物料和库存任务。'],
|
||||
[/PersonnelBinding/, '该页面用于维护人员与工位绑定关系,控制或提示人员可操作的工位。'],
|
||||
[/ShiftManagement/, '该页面用于维护班次、班次人员和排班基础数据。'],
|
||||
[/Timesheet|Workhours$/, '该页面用于查询工时记录,按人员、设备、任务、订单和日期统计工时。'],
|
||||
[/WorkhoursEdit/, '该页面用于修正或补录工时/报工记录,处理异常工时。'],
|
||||
[/WorkHoursCheck/, '该页面用于工时校验和 SAP 提交,用户核对报工记录后批量或单条校验并上传相关单据。'],
|
||||
[/Urgent/, '该页面用于维护加急任务,跟踪加急订单、加急数量和完成情况。'],
|
||||
[/AbnormalControl/, '该页面用于生产异常管理,查询异常、处理异常、转办、查看进度和关闭异常。'],
|
||||
[/QualityCenter/, '该页面是质量综合处理中心,集中处理待检、收检、检测明细、不合格和 SAP/WMS 联动。'],
|
||||
[/QualityDetails/, '该页面用于查询质检明细,按订单、物料、检验类型和时间追溯检测记录。'],
|
||||
[/QualityStandardQuery/, '该页面用于查询或维护质量检验标准、检测项目、上下限和启用状态。'],
|
||||
[/Unqualified/, '该页面用于不合格品处理,记录处置方式、责任、原因和处理结果。'],
|
||||
[/CheckTask[\\/].*purchaseIncoming/, '该页面用于采购/来料检验,质检人员录入来料检验数量、合格数、不合格数和检测明细。'],
|
||||
[/CheckTask[\\/].*processReceive/, '该页面用于工序收检/序检收检,质检人员接收工序检验任务并录入检验结果。'],
|
||||
[/CheckTask[\\/].*firstSpecial/, '该页面用于首检或特殊首件检验,录入首件检测结果。'],
|
||||
[/CheckTask[\\/].*final/, '该页面用于终检任务处理,录入最终检验结果。'],
|
||||
[/CheckTask[\\/].*materialReturn/, '该页面用于材料退库检验,核对退库物料并录入检验结论。'],
|
||||
[/CheckTask[\\/].*salesReturn/, '该页面用于销售退货检验,录入退货质检结果。'],
|
||||
[/CheckTask[\\/].*OtherInbound/, '该页面用于其他入库检验,录入其他入库质检结果。'],
|
||||
[/CheckTask[\\/].*processSpecial/, '该页面用于过程特殊检验,录入特殊检验项目和结果。'],
|
||||
[/saleorderstatus/, '该页面用于查询销售订单状态,跟踪销售订单在生产、交付和关闭过程中的状态。'],
|
||||
[/MenuManagement/, '该页面用于维护系统菜单、按钮权限和路由配置。'],
|
||||
[/OperationLog/, '该页面用于查询操作日志,追溯用户操作、报工或业务变更记录。'],
|
||||
[/OrgManagement/, '该页面用于维护组织、部门或组织树基础资料。'],
|
||||
[/PersonnelManagement/, '该页面用于维护人员账号、部门、角色和启用状态。'],
|
||||
[/SystemRrolemaintenance/, '该页面用于维护系统角色和角色权限。'],
|
||||
[/WorkstationManagement/, '该页面用于维护工位/资源主数据,并同步 SAP B1 Resources。'],
|
||||
[/layout|Sidebar|Navbar|TagsView|AppMain|ResizeHandler/, '该文件属于系统布局和导航组件,用户通过它切换菜单、标签页、折叠菜单或退出登录,不维护具体业务单据。'],
|
||||
];
|
||||
const found = rules.find(([re]) => re.test(p));
|
||||
if (found) return found[1];
|
||||
return '该页面为业务页面,用户按查询条件筛选数据,在列表或弹窗中查看明细,并按页面按钮完成维护、提交或状态更新。';
|
||||
}
|
||||
|
||||
function actionVerb(button) {
|
||||
const text = button.text;
|
||||
if (/查询|搜索|全部|待执行|可执行|已开工|已完成|未完成/.test(text)) return '查询/筛选';
|
||||
if (/新增|添加|新建|创建/.test(text)) return '新增';
|
||||
if (/编辑|修改|保存|确定|确 定/.test(text)) return '编辑/保存';
|
||||
if (/删除|移除/.test(text)) return '删除';
|
||||
if (/导出|打印/.test(text)) return '导出/打印';
|
||||
if (/查看|详情|图纸|明细|进度/.test(text)) return '查看';
|
||||
if (/排产|派工|开工|报工|送检|收料|发料|退库|关闭|提交|处理|转办|完结|校验|上传/.test(text)) return '业务提交';
|
||||
if (/取消|关闭|返回/.test(text)) return '取消/关闭';
|
||||
return '操作';
|
||||
}
|
||||
|
||||
function fieldName(value) {
|
||||
return value
|
||||
.replace(/^.*\./, '')
|
||||
.replace(/\[[^\]]+\]/g, '')
|
||||
.replace(/Form$/, '')
|
||||
.replace(/Time$/, '时间')
|
||||
.replace(/No$/, '编号');
|
||||
}
|
||||
|
||||
function queryItems(page) {
|
||||
const fromParams = page.params
|
||||
.filter(p => !/任务列表|操作人|最后编辑人|editstr|personnel|TaskAID/.test(p.name))
|
||||
.map(p => p.name);
|
||||
const fromModels = page.vModels
|
||||
.filter(v => !/^scope\.row|^item\.|^row\.|multipleSelection|loading|dialog|Visible|activeTab/.test(v))
|
||||
.map(fieldName);
|
||||
const fromPlaceholders = page.placeholders
|
||||
.map(x => x.replace(/^请输入/, '').replace(/^请选择/, '').replace(/起始|结束/g, '').trim())
|
||||
.filter(Boolean);
|
||||
return stripNoise([...fromParams, ...fromModels, ...fromPlaceholders]).slice(0, 22);
|
||||
}
|
||||
|
||||
function tableItems(page) {
|
||||
return stripNoise(page.tableColumns.map(c => c.label || c.prop || c.type)).slice(0, 34);
|
||||
}
|
||||
|
||||
function buttonItems(page) {
|
||||
return stripNoise(page.buttons.map(b => b.text)).slice(0, 30);
|
||||
}
|
||||
|
||||
function procItems(page) {
|
||||
return uniq(page.procs.map(p => p.name)).slice(0, 20);
|
||||
}
|
||||
|
||||
function sapItems(page) {
|
||||
return uniq(page.sapCalls.map(s => `${s.method} ${s.url}`)).slice(0, 12);
|
||||
}
|
||||
|
||||
function lineList(values, fallback) {
|
||||
if (!values.length) return `- ${fallback}`;
|
||||
return values.map(v => `- \`${v}\``).join('\n');
|
||||
}
|
||||
|
||||
function detailedSteps(page) {
|
||||
const steps = [];
|
||||
const queries = queryItems(page);
|
||||
const tabs = page.tabLabels;
|
||||
const columns = tableItems(page);
|
||||
const buttons = page.buttons.slice(0, 24);
|
||||
const dialogs = page.dialogs;
|
||||
const forms = page.formLabels;
|
||||
const procs = procItems(page);
|
||||
const pathText = page.relative;
|
||||
|
||||
steps.push(`从左侧菜单进入该页,确认页面标题、当前账号和业务角色正确。`);
|
||||
if (tabs.length) {
|
||||
steps.push(`先查看页签:${tabs.map(x => `\`${x}\``).join('、')};需要表格处理时进入表单/列表页签,需要看时间排布时进入日程/看板页签。`);
|
||||
}
|
||||
if (queries.length) {
|
||||
steps.push(`在查询区按需要填写筛选条件:${queries.slice(0, 12).map(x => `\`${x}\``).join('、')}。`);
|
||||
if (queries.length > 12) steps.push(`如果仍查不到数据,继续补充条件:${queries.slice(12, 22).map(x => `\`${x}\``).join('、')},或清空过窄条件后重新查询。`);
|
||||
} else {
|
||||
steps.push(`该页没有识别到固定查询区,按页面提示直接查看信息或使用菜单/按钮进入下一步。`);
|
||||
}
|
||||
const queryButtons = buttons.filter(b => actionVerb(b) === '查询/筛选');
|
||||
if (queryButtons.length) {
|
||||
steps.push(`点击 ${stripNoise(queryButtons.map(b => b.text)).slice(0, 8).map(x => `\`${x}\``).join('、')} 刷新列表;状态按钮会切换任务范围。`);
|
||||
} else if (buttons.length) {
|
||||
steps.push(`点击页面上的查询或刷新类按钮获取最新数据;如果页面自动加载,则先核对默认列表是否符合当前业务范围。`);
|
||||
}
|
||||
if (page.hasPagination) {
|
||||
steps.push(`列表较多时使用分页区切换页码或调整每页条数,避免只检查第一页。`);
|
||||
}
|
||||
if (columns.length) {
|
||||
steps.push(`查询后先核对关键列:${columns.slice(0, 12).map(x => `\`${x}\``).join('、')}。`);
|
||||
if (columns.length > 12) steps.push(`继续横向滚动或展开表格,核对:${columns.slice(12, 26).map(x => `\`${x}\``).join('、')}。`);
|
||||
}
|
||||
if (page.hasTree) {
|
||||
steps.push(`如果页面左侧或上方有树形结构,先选中组织、物料、菜单或产品节点,再查看右侧列表;新增子节点前确认父节点选中正确。`);
|
||||
}
|
||||
const nonQueryButtons = buttons.filter(b => !['查询/筛选', '取消/关闭'].includes(actionVerb(b)));
|
||||
for (const button of nonQueryButtons.slice(0, 10)) {
|
||||
const verb = actionVerb(button);
|
||||
if (verb === '新增') steps.push(`需要新增时点击 \`${button.text}\`,在弹窗中逐项填写必填字段,确认编码、名称、状态等基础信息后保存。`);
|
||||
else if (verb === '编辑/保存') steps.push(`需要维护已有记录时先选中目标行,再点击或触发表格内 \`${button.text}\`,修改字段后保存并等待成功提示。`);
|
||||
else if (verb === '删除') steps.push(`需要删除时先确认该记录没有正在使用的业务数据,再点击 \`${button.text}\`,按确认提示执行。`);
|
||||
else if (verb === '导出/打印') steps.push(`需要留存或流转时点击 \`${button.text}\`,导出/打印前确认当前查询条件和选中记录正确。`);
|
||||
else if (verb === '查看') steps.push(`需要查看明细时点击 \`${button.text}\`,在弹窗或新区域核对图纸、明细、进度、记录或关联单据。`);
|
||||
else if (verb === '业务提交') steps.push(`需要推进业务时先选中目标行并核对数量、时间、人员、工位、物料和备注,再点击 \`${button.text}\` 提交。`);
|
||||
else steps.push(`按业务需要点击 \`${button.text}\`,操作前先确认选中行和输入内容。`);
|
||||
}
|
||||
if (dialogs.length) {
|
||||
steps.push(`出现弹窗时按弹窗标题处理:${dialogs.slice(0, 8).map(x => `\`${x}\``).join('、')};弹窗关闭前确认必填项已保存。`);
|
||||
}
|
||||
if (forms.length) {
|
||||
steps.push(`弹窗或表单内重点填写:${forms.slice(0, 14).map(x => `\`${x}\``).join('、')},提交前逐项核对。`);
|
||||
}
|
||||
if (page.hasUpload) {
|
||||
steps.push(`涉及上传时先选择正确文件,再点击上传/保存;上传后重新查询,确认文件名、版本、上传时间或预览内容已显示。`);
|
||||
}
|
||||
if (page.hasCalendar) {
|
||||
steps.push(`进入日程页后,单击任务查看详情;拖拽任务可调整计划开始时间,拉伸任务可调整计划完成时间,系统提示确认后才会保存。`);
|
||||
steps.push(`日程保存失败或取消时任务会恢复原日期;保存成功后回到表单页重新查询,核对计划开始和计划完成是否同步。`);
|
||||
}
|
||||
if (procs.length) {
|
||||
steps.push(`保存或提交成功后重新点击查询,确认页面数据已通过 ${procs.slice(0, 5).map(x => `\`${x}\``).join('、')} 等后台过程更新。`);
|
||||
}
|
||||
if (page.sapCalls.length) {
|
||||
steps.push(`涉及 SAP/WMS 接口时,必须查看页面成功或失败提示;失败时先记录错误信息,不要连续重复提交同一单据。`);
|
||||
}
|
||||
|
||||
if (/SelfMakePlando[\\/]/.test(pathText)) {
|
||||
steps.push(`在 \`指派数量\` 中输入小于计划数的数量时,表示本次只派出部分数量,剩余数量需要继续跟踪和后续派工。`);
|
||||
steps.push(`点击 \`批量排产\` 前应选择同一生产订单的多道工序,系统会按订单行号排序并继承上一道工序的部分计划信息。`);
|
||||
steps.push(`点击 \`排产完成\` 后,系统校验指派对象、指派数量、计划开始、计划完成,并同步生产订单最早开始和最晚完成。`);
|
||||
}
|
||||
if (/SelfMakePlandone[\\/]/.test(pathText)) {
|
||||
steps.push(`已排产列表中仍可调整指派对象、指派数量、计划开始、计划完成、外协分组、最晚开始和二次派工;调整后要重新查询确认。`);
|
||||
}
|
||||
if (/MachiningCenter|AssemblyCenter/.test(pathText)) {
|
||||
steps.push(`现场执行类操作必须按实际顺序处理:先确认任务和工位,再收料/开工,完成加工或装配后再报工/送检。`);
|
||||
}
|
||||
if (/QualityManagement/.test(pathText)) {
|
||||
steps.push(`录入检验结果时先核对检验类型、订单、物料、批次/工序,再填写合格数、不合格数和检测明细,避免检验记录挂错任务。`);
|
||||
}
|
||||
if (/WorkHoursCheck/.test(pathText)) {
|
||||
steps.push(`工时校验前先比对 MES 报工、设备工时和 SAP 工序资源;只对核对无误的记录执行提交。`);
|
||||
}
|
||||
if (/WorkstationManagement/.test(pathText)) {
|
||||
steps.push(`工位新增或修改会影响 SAP 资源、派工、报工和看板,保存后要用排产或生产执行页面验证工位是否可选。`);
|
||||
}
|
||||
if (/MenuManagement|SystemRrolemaintenance|PersonnelManagement/.test(pathText)) {
|
||||
steps.push(`权限类修改保存后,需要让相关用户重新登录或刷新权限,再验证菜单、按钮和数据范围是否生效。`);
|
||||
}
|
||||
|
||||
return steps.map((s, i) => `${i + 1}. ${s}`).join('\n');
|
||||
}
|
||||
|
||||
function notes(page) {
|
||||
const values = [];
|
||||
if (/PlanManagement/.test(page.relative)) values.push('排产、派工和计划时间会影响生产看板、及时开工统计和 SAP 生产订单日期,提交前必须核对。');
|
||||
if (/ProductionManagement/.test(page.relative)) values.push('生产执行页面的数据会直接影响报工、工时、质检和库存任务,现场操作必须与实际加工进度一致。');
|
||||
if (/QualityManagement/.test(page.relative)) values.push('质检结果保存后会影响合格入库、不合格处理和后续工序,提交前必须核对数量。');
|
||||
if (/ProcessManagement|CraftManagement/.test(page.relative)) values.push('工艺、图纸和结构资料会被排产、生产、质检引用,版本错误会直接影响现场执行。');
|
||||
if (/DeviceManagement/.test(page.relative)) values.push('设备和采集数据用于看板、OEE 和报工分析,发现异常时应先确认设备编码和采集点位。');
|
||||
if (/SystemMaintenance/.test(page.relative)) values.push('系统维护类数据会影响登录、权限、菜单和业务可选项,修改后需要验证。');
|
||||
if (page.sapCalls.length) values.push('该页存在 SAP/WMS 调用,失败时应记录返回提示并确认是否已经生成外部单据。');
|
||||
if (page.hasCalendar) values.push('日程拖拽属于直接改计划时间的操作,拖拽前应确认任务未被现场执行锁定。');
|
||||
if (!values.length) values.push('操作后建议重新查询页面,确认列表、状态和明细已经刷新。');
|
||||
return values.map(v => `- ${v}`).join('\n');
|
||||
}
|
||||
|
||||
function section(page, index) {
|
||||
const query = queryItems(page);
|
||||
const columns = tableItems(page);
|
||||
const buttons = buttonItems(page);
|
||||
const procs = procItems(page);
|
||||
const sap = sapItems(page);
|
||||
|
||||
return `### 21.${index} ${page.name}
|
||||
|
||||
页面路径:\`${page.relative}\`
|
||||
所属模块:${moduleName(page)}
|
||||
建议使用人员:${roleFor(page)}
|
||||
|
||||
页面用途:${purpose(page)}
|
||||
|
||||
**具体操作步骤**
|
||||
${detailedSteps(page)}
|
||||
|
||||
**查询条件/输入项**
|
||||
${lineList(query, '未识别到固定输入项,按现场页面提示操作。')}
|
||||
|
||||
**结果表重点列**
|
||||
${lineList(columns, '未识别到固定表格列,以页面实际显示为准。')}
|
||||
|
||||
**页面按钮/状态/页签**
|
||||
${lineList([...buttons, ...page.tabLabels].slice(0, 36), '未识别到明确按钮,以页面实际显示为准。')}
|
||||
|
||||
**弹窗/表单重点项**
|
||||
${lineList([...page.dialogs, ...page.formLabels].slice(0, 30), '未识别到固定弹窗或表单项。')}
|
||||
|
||||
**后台处理/外部接口**
|
||||
${lineList([...procs.map(x => `存储过程:${x}`), ...sap.map(x => `接口:${x}`)].slice(0, 30), '未发现页面级后台提交动作。')}
|
||||
|
||||
**操作注意事项**
|
||||
${notes(page)}
|
||||
`;
|
||||
}
|
||||
|
||||
function moduleOrder(page) {
|
||||
const order = [
|
||||
'404.vue',
|
||||
'AnomalousManagement',
|
||||
'CraftManagement',
|
||||
'DeviceManagement',
|
||||
'PlanManagement',
|
||||
'ProcessManagement',
|
||||
'ProductionManagement',
|
||||
'QualityManagement',
|
||||
'SaleManagement',
|
||||
'SystemMaintenance',
|
||||
'dashboard',
|
||||
'layout',
|
||||
'login'
|
||||
];
|
||||
const key = page.relative === 'src/views/404.vue' ? '404.vue' : page.module;
|
||||
const idx = order.indexOf(key);
|
||||
return idx >= 0 ? idx : 99;
|
||||
}
|
||||
|
||||
function moduleHeading(page) {
|
||||
const key = page.relative === 'src/views/404.vue' ? '404.vue' : page.module;
|
||||
const headings = {
|
||||
'404.vue': '错误页',
|
||||
AnomalousManagement: '异常管理',
|
||||
CraftManagement: '产品结构维护',
|
||||
DeviceManagement: '设备管理',
|
||||
PlanManagement: '计划排产',
|
||||
ProcessManagement: '工艺与图纸管理',
|
||||
ProductionManagement: '生产执行管理',
|
||||
QualityManagement: '质量管理',
|
||||
SaleManagement: '销售与交付查询',
|
||||
SystemMaintenance: '系统维护',
|
||||
dashboard: '首页与看板',
|
||||
layout: '布局与导航',
|
||||
login: '登录'
|
||||
};
|
||||
return headings[key] || key;
|
||||
}
|
||||
|
||||
function buildChapter(pages) {
|
||||
const sorted = pages.sort((a, b) => {
|
||||
const m = moduleOrder(a) - moduleOrder(b);
|
||||
if (m !== 0) return m;
|
||||
return a.relative.localeCompare(b.relative, 'zh-Hans-CN');
|
||||
});
|
||||
|
||||
const lines = [];
|
||||
lines.push('## 二十一、逐页详细操作说明(按 src/views 页面)');
|
||||
lines.push('');
|
||||
lines.push('本章按源码页面逐页编写。每个页面都从实际 `v-model`、表格列、按钮、弹窗、页签、存储过程和 SAP/WMS 调用中提取操作线索,转换成用户可执行的步骤。');
|
||||
lines.push('');
|
||||
lines.push('通用阅读方法:');
|
||||
lines.push('- `查询条件/输入项` 是用户进入页面后可以填写、选择或用于筛选的字段。');
|
||||
lines.push('- `结果表重点列` 是查询后需要核对的表格列,表格可横向滚动时应继续向右查看。');
|
||||
lines.push('- `页面按钮/状态/页签` 是页面上能触发查询、查看、编辑、提交、导出、状态切换或页面切换的入口。');
|
||||
lines.push('- `后台处理/外部接口` 用于说明保存后可能调用的存储过程、SAP 或 WMS 接口,业务人员主要关注成功/失败提示。');
|
||||
lines.push('- 涉及排产、报工、质检、外协、SAP/WMS 的操作,提交前必须核对订单、物料、数量、人员、工位和日期。');
|
||||
lines.push('');
|
||||
|
||||
let current = '';
|
||||
let moduleIndex = 0;
|
||||
sorted.forEach((page, i) => {
|
||||
const heading = moduleHeading(page);
|
||||
if (heading !== current) {
|
||||
moduleIndex += 1;
|
||||
current = heading;
|
||||
lines.push(`## 21-${moduleIndex} ${heading}`);
|
||||
lines.push('');
|
||||
}
|
||||
lines.push(section(page, i + 1).trimEnd());
|
||||
lines.push('');
|
||||
});
|
||||
return lines.join('\n').trimEnd() + '\n';
|
||||
}
|
||||
|
||||
function main() {
|
||||
const pages = walk(viewsRoot)
|
||||
.filter(file => !/node_modules/.test(file))
|
||||
.map(extractPage);
|
||||
const chapter = buildChapter(pages);
|
||||
const manual = readText(manualPath);
|
||||
const marker = '## 二十一、逐页详细操作说明(按 src/views 页面)';
|
||||
const idx = manual.indexOf(marker);
|
||||
if (idx < 0) throw new Error(`找不到章节标记:${marker}`);
|
||||
const nextChapter = manual.slice(idx + marker.length).search(/\n## 二十二、/);
|
||||
const head = manual.slice(0, idx).trimEnd() + '\n\n';
|
||||
const tail = nextChapter >= 0 ? manual.slice(idx + marker.length + nextChapter) : '';
|
||||
writeText(manualPath, head + chapter + (tail ? '\n' + tail.trimStart() : ''));
|
||||
console.log(`rewrote chapter 21 for ${pages.length} pages`);
|
||||
}
|
||||
|
||||
main();
|
||||
BIN
生产任务看板/dist.zip
BIN
生产任务看板/dist.zip
Binary file not shown.
Reference in New Issue
Block a user