feat: 为多个页面添加操作帮助功能,替换旧版静态资源文件

1. 新增PageHelp通用帮助组件,实现页面左下角悬浮帮助按钮
2. 为WMS、MES、工位终端多个业务页面接入帮助系统
3. 替换项目中旧的打包静态资源文件,更新资源引用路径
4. 新增各模块的帮助文档配置数据
This commit is contained in:
SunYF
2026-08-28 17:23:44 +08:00
parent cbd55338f1
commit dd078038e2
93 changed files with 619 additions and 45 deletions
@@ -0,0 +1,54 @@
<template>
<!-- 页面左下角 "?" 帮助按钮点击弹出当前页面整体介绍 + 字段说明 -->
<div class="page-help">
<el-tooltip content="操作说明" placement="left">
<el-button class="help-fab" circle @click="open">?</el-button>
</el-tooltip>
<el-drawer v-model="show" :title="data.title || '操作说明'" size="480px" append-to-body>
<div class="ph-overview" v-if="data.overview">{{ data.overview }}</div>
<div v-if="data.sections && data.sections.length">
<div v-for="(sec, si) in data.sections" :key="si">
<h3 class="ph-sec-title">{{ sec.title }}</h3>
<p class="ph-sec-overview" v-if="sec.overview">{{ sec.overview }}</p>
<el-table :data="sec.fields" border size="small" class="ph-table">
<el-table-column prop="name" label="字段" width="96" />
<el-table-column prop="source" label="来源" width="80" />
<el-table-column prop="purpose" label="用途" min-width="120" show-overflow-tooltip />
<el-table-column prop="fill" label="怎么填" min-width="140" show-overflow-tooltip />
</el-table>
</div>
</div>
<el-table v-else :data="data.fields" border size="small" class="ph-table">
<el-table-column prop="name" label="字段" width="96" />
<el-table-column prop="source" label="来源" width="80" />
<el-table-column prop="purpose" label="用途" min-width="120" show-overflow-tooltip />
<el-table-column prop="fill" label="怎么填" min-width="140" show-overflow-tooltip />
</el-table>
</el-drawer>
</div>
</template>
<script setup>
import { ref } from 'vue'
defineProps({
data: { type: Object, default: () => ({ title: '操作说明', overview: '', fields: [] }) }
})
const show = ref(false)
function open() { show.value = true }
</script>
<style scoped>
.page-help { position: fixed; left: 16px; bottom: 16px; z-index: 2000; }
.help-fab { background: #409eff; color: #fff; font-weight: 700; font-size: 18px;
box-shadow: 0 2px 8px rgba(0,0,0,.25); }
.help-fab:hover { background: #66b1ff; }
.ph-overview { color: #555; line-height: 1.7; margin-bottom: 14px; white-space: pre-line; }
.ph-sec-title { margin: 12px 0 4px; font-size: 15px; }
.ph-sec-overview { color: #777; margin: 4px 0 8px; line-height: 1.6; font-size: 13px; }
.ph-table :deep(.el-table__cell), .ph-table :deep(td.el-table__cell) { padding: 4px 6px; font-size: 12px; }
</style>
+154
View File
@@ -0,0 +1,154 @@
// 页面级操作说明:每个页面/弹窗的整体介绍 + 各字段 来源/用途/怎么填
// 由 components/PageHelp.vue 在左下角 "?" 按钮弹出展示。
export const helpProductType = {
title: '产品类型',
overview: '产品类型是对“生产什么产品”的分类档案,好比“产品种类”。新建工单时必须先选择产品类型。\n只有先维护好产品类型,工单、BOM 才能正常建立。',
fields: [
{ name: '名称', source: '手动填写', purpose: '产品类型的中文名称,用于识别', fill: '如:智能电表、断路器、配电柜' },
{ name: '编码', source: '手动填写', purpose: '产品类型的唯一编码,BOM/工单按此关联', fill: '如:METER-01(尽量唯一,不重复)' },
{ name: '类别', source: '手动填写', purpose: '产品所属大类,方便分类统计', fill: '如:计量表 / 开关柜(可空)' },
{ name: '启用', source: '开关选择', purpose: '启用后才能在新建工单/备料时被选到', fill: '默认开启;暂不用的可关闭' },
{ name: '备注', source: '手动填写', purpose: '补充说明文字', fill: '可不填' }
]
}
export const helpWorkOrder = {
title: '工单管理(新建 / 编辑工单)',
overview: '工单是一个“合同/生产批次”的唯一载体,也是仓库出库挂靠的唯一对象。\n流程:建工单 → 配 BOM(单台用哪些料)→ 日排产(今天产多少台)→ 系统按排产备料 → AGV 配送到各工位。',
fields: [
{ name: '工单号', source: '系统自动生成,可改', purpose: '唯一标识一个工单,备料/出库/报工都挂在此号下', fill: '如 WO20260828,保证唯一' },
{ name: '产品类型', source: '先维护“产品类型”后选择', purpose: '说明这批生产的是什么产品', fill: '下拉选择已启用的产品类型' },
{ name: '产品编码', source: '手动填写', purpose: '产品的唯一编码(通常与产品类型编码一致)', fill: '如 METER-01' },
{ name: '产品名称', source: '手动填写', purpose: '产品的中文名称,用于展示与追溯', fill: '如 智能电表' },
{ name: '数量', source: '手动填写', purpose: '本工单的总数量(如一个合同 100 台)', fill: '填写整数 ≥1' },
{ name: '工序组合', source: '手动填写', purpose: '本工单在产线要执行的工序序列,PLC 按此下发', fill: '如 135=做第1/3/5序;全工序=123456789101112' },
{ name: '状态', source: '系统流程驱动', purpose: '工单生命周期:创建→发布→生产→完成', fill: '新建时选“已创建”,后续由流程推进' }
],
sections: [
{
title: '日排产(弹窗)',
overview: '只排“哪天生产多少台”,是仓库备料/配送的前瞻参考,不直接触发出库与下单。',
fields: [
{ name: '日期', source: '手动选择', purpose: '计划生产日期', fill: '选择一个日期,可排未来多天' },
{ name: '计划数量', source: '手动填写', purpose: '当天计划产量(≤ 工单总数量)', fill: '填写整数,如今天产 20 台' }
]
}
]
}
export const helpBom = {
title: 'BOM(添加 BOM 物料)',
overview: 'BOM 列出“生产 1 台该工单产品需要哪些物料、各用多少”。系统按它是算备料/出库的需求量,并强约束出库不能超需求。',
fields: [
{ name: '物料编码', source: '手动填写', purpose: '该物料在全库房的唯一编码(与 WMS 物料档案一致)', fill: '如螺丝=SCREW-M3,芯片=IC-001' },
{ name: '物料名称', source: '手动填写', purpose: '物料中文名,用于识别', fill: '如 十字螺丝、主控芯片' },
{ name: '规格', source: '手动填写', purpose: '物料的规格型号', fill: '如 M3×8 / SMT-48脚' },
{ name: '单位', source: '手动填写', purpose: '计量单位,用于算量', fill: '个 / 件 / 套 / kg' },
{ name: '管理方式', source: '单选,按物料类型', purpose: '精密件=逐件按SN管理;结构件=按批次管理', fill: '电子件选精密件(SN);螺丝等选结构件(批次)' },
{ name: '单台用量', source: '手动填写', purpose: '生产 1 台产品用多少个该物料', fill: '如每台用 8 颗螺丝 → 填 8' },
{ name: '损耗率%', source: '手动填写', purpose: '考虑报废/损耗的加放比例', fill: '如 2% 填 20 表示不计算' },
{ name: '需求量', source: '通常自动算出,可覆盖', purpose: '总需求 = 数量×单台用量×(1+损耗率)', fill: '自动算,也可手动修正' }
]
}
export const helpMaterial = {
title: '备料单',
overview: '备料单是按“日排产”自动算出的:该日生产所需物料清单。仓库看它备料,再用 AGV 配送到对应工位(DOCK01~20)。',
fields: [
{ name: '日期', source: '手动选择', purpose: '按哪一天的排产生成备料', fill: '选择某排产日期' },
{ name: '工单号', source: '筛选条件', purpose: '只查看指定工单的备料', fill: '可空,空=全部' },
{ name: '状态', source: '筛选条件', purpose: '按备料状态筛选', fill: '可空' }
]
}
export const helpPlc = {
title: 'PLC 工序下发',
overview: '把工序组合(如 135)写入西门子 S7-1214 的寄存器,产线传送带据此只做对应工序。\n系统遵循“未收到完成信号,绝不下发下一条”,保证产线不会串序。',
fields: [
{ name: '工单号', source: '手动填写', purpose: '当前生产的工单号,用于追溯', fill: '选择或输入工单号' },
{ name: '工件SN', source: '扫码枪扫入', purpose: '当前流经的工件唯一序列号', fill: '扫码枪扫描,可空(按工单整体下发)' },
{ name: '工位', source: '手动填写', purpose: '要下发到哪个工位(1~12', fill: '输入 1~12 的整数' },
{ name: '工序组合', source: '手动填写', purpose: '该工位要执行的工序,PLC 会组合执行', fill: '如 135(做第1/3/5序),全序=123456789101112' }
]
}
export const helpTorque = {
title: '拧紧数据(查询 / 扫码录入)',
overview: '接收丹尼科尔拧紧工具的采集结果(扭矩/角度/时间/结果/操作人),用于质量追溯。工位终端点“完成”后数据才会报到这里。',
fields: [
{ name: 'SN', source: '扫码枪 / 手工', purpose: '被拧紧的工件唯一序列号', fill: '扫码枪扫描' },
{ name: '工单号', source: '自动带出/选择', purpose: '该工件所属工单', fill: '选择工单号' },
{ name: '工位', source: '手动填写', purpose: '拧紧发生在哪道工位', fill: '如 3' },
{ name: '扭矩', source: '拧紧工具采集', purpose: '实际拧紧扭矩(N·m)', fill: '工具自动带出,可手工录' },
{ name: '角度', source: '拧紧工具采集', purpose: '实际旋转角度(°)', fill: '工具自动带出' },
{ name: '操作人', source: '登录账号', purpose: '执行拧紧操作的人,用于追溯', fill: '默认当前登录用户,可改' }
]
}
export const helpScan = {
title: '扫码报工',
overview: '产线扫码枪扫到工件,按类型记录该工件在各工序的流转:进线、工序完成、完工、暂存退回。这是工单进度与追溯的数据来源。',
fields: [
{ name: 'SN', source: '扫码枪横扫', purpose: '工件的唯一序列号', fill: '扫码枪扫描' },
{ name: '工单号', source: '自动带出/选择', purpose: '工件所属工单', fill: '输入或选择' },
{ name: '工位', source: '扫码枪绑定', purpose: '当前扫码的工位编号', fill: '如 5' },
{ name: '类型', source: '按操作选择', purpose: '本次扫码的业务含义', fill: '进线ONLINE / 工序PROCESS / 完工DONE / 暂存TEMP_STORE' },
{ name: '工序号', source: '手动填写', purpose: 'PROCESS 时填第几道工序', fill: '如 3' }
]
}
export const helpTrace = {
title: '工件追溯',
overview: '输入工件的 SN,即可查到它的完整履历:进线/完工时间、各工序时间线、步骤考核数据(扭矩/角度等)、拧紧记录、以及它用了哪些批次/精密件(成品关联)。',
fields: [
{ name: '工件SN', source: '扫码枪 / 手输', purpose: '要追溯的工件唯一序列号', fill: '扫SN条码或手动输入后点查询' }
]
}
export const helpRbac = {
title: '角色权限管理(用户 / 角色 / 权限)',
overview: '管控谁能登录、能看哪些菜单。建议:只给操作员分配其工序所需的菜单权限。登录 token 有效期短(1800 秒),超时自动失效。',
sections: [
{
title: '用户(新建 / 编辑)',
fields: [
{ name: '用户名', source: '手动填写', purpose: '登录账号,唯一', fill: '如 operator1' },
{ name: '密码', source: '手动填写', purpose: '登录密码,保存时加密', fill: '≥6 位;编辑时留空=不修改' },
{ name: '姓名', source: '手动填写', purpose: '真实姓名,用于操作日志追溯', fill: '如 张三' },
{ name: '角色', source: '下拉选择', purpose: '决定该用户有哪些菜单权限', fill: '选择已建角色' },
{ name: '状态', source: '选择', purpose: '禁用后无法登录', fill: '启用 / 禁用' }
]
},
{
title: '角色(新建 / 编辑)',
fields: [
{ name: '名称', source: '手动填写', purpose: '角色中文名', fill: '如 装配工、质检员' },
{ name: '编码', source: '手动填写', purpose: '角色唯一编码(SUPER_ADMIN 为超级管理员内置码,勿改)', fill: '如 OPERATOR' },
{ name: '备注', source: '手动填写', purpose: '说明文字', fill: '可空' },
{ name: '权限', source: '多选勾选', purpose: '勾选该角色可见的菜单/功能', fill: '勾选所需权限码' }
]
},
{
title: '权限(新增 / 编辑)',
overview: '通常由系统预置,一般无需手动新增。',
fields: [
{ name: '编码', source: '系统预置', purpose: '权限唯一码,如 produce.workorder', fill: '按系统预置填写' },
{ name: '名称', source: '手动填写', purpose: '权限名', fill: '如 工单管理' },
{ name: '类型', source: '手动填写', purpose: 'MENU=菜单权限 / API=接口权限', fill: '如 MENU' },
{ name: '路径', source: '手动填写', purpose: 'MESU 对应的前端路由路径', fill: '如 /work-order' },
{ name: '排序', source: '手动填写', purpose: '菜单显示顺序', fill: '数字,越小越靠前' }
]
}
]
}
export const helpEventLog = {
title: '操作日志',
overview: '记录所有关键业务操作(建工单、BOM维护、备料、PLC下发、拧紧、扫码报工等),按工单号、操作人、实体可追溯。',
fields: [
{ name: '工单号', source: '筛选条件', purpose: '按工单号过滤该工单的所有操作', fill: '输入工单号,可空=全部' },
{ name: '操作人', source: '筛选条件', purpose: '按操作人过滤', fill: '输入姓名/账号,可空=全部' },
{ name: '类型', source: '筛选条件', purpose: '按事件类型过滤', fill: '如 EVENT_WORK_ORDER / EVENT_TORQUE,可空' }
]
}
+3
View File
@@ -52,12 +52,15 @@
</template>
</el-dialog>
</el-card>
<PageHelp :data="helpBom" />
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import request from '../utils/request'
import PageHelp from '../components/PageHelp.vue'
import { helpBom } from '../help'
const orderNo = ref('')
const workOrders = ref([])
@@ -19,11 +19,14 @@
<el-pagination v-model:current-page="page" :page-size="pageSize" :total="total"
layout="total, prev, pager, next" background style="margin-top:10px" @current-change="load" />
</el-card>
<PageHelp :data="helpEventLog" />
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
import request from '../utils/request'
import PageHelp from '../components/PageHelp.vue'
import { helpEventLog } from '../help'
const query = reactive({ orderNo: '', operator: '', eventType: '' })
const list = ref([])
@@ -27,12 +27,15 @@
<el-table-column prop="operator" label="操作人" width="90" />
</el-table>
</el-card>
<PageHelp :data="helpMaterial" />
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '../utils/request'
import PageHelp from '../components/PageHelp.vue'
import { helpMaterial } from '../help'
const query = reactive({ planDate: '', orderNo: '', status: '' })
const list = ref([])
@@ -32,12 +32,15 @@
<el-table-column prop="operator" label="操作人" width="90" />
</el-table>
</el-card>
<PageHelp :data="helpPlc" />
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '../utils/request'
import PageHelp from '../components/PageHelp.vue'
import { helpPlc } from '../help'
const send = reactive({ orderNo: '', sn: '', stationNo: 1, processCombination: '' })
const query = reactive({ orderNo: '', status: '' })
@@ -34,12 +34,15 @@
</template>
</el-dialog>
</el-card>
<PageHelp :data="helpProductType" />
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import request from '../utils/request'
import PageHelp from '../components/PageHelp.vue'
import { helpProductType } from '../help'
const list = ref([])
const dialog = reactive({ show: false, id: 0, name: '', code: '', category: '', remark: '', isActive: true })
+3
View File
@@ -110,12 +110,15 @@
<template #footer><el-button @click="p.show=false">取消</el-button><el-button type="primary" @click="savePerm">保存</el-button></template>
</el-dialog>
</el-card>
<PageHelp :data="helpRbac" />
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import request from '../utils/request'
import PageHelp from '../components/PageHelp.vue'
import { helpRbac } from '../help'
const tab = ref('users')
const users = ref([]), roles = ref([]), perms = ref([])
+3
View File
@@ -32,12 +32,15 @@
<el-table-column prop="time" label="时间" min-width="170" />
</el-table>
</el-card>
<PageHelp :data="helpScan" />
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '../utils/request'
import PageHelp from '../components/PageHelp.vue'
import { helpScan } from '../help'
const scan = reactive({ sn: '', orderNo: '', station: '', type: 'PROCESS', processCode: 0 })
const query = reactive({ sn: '', orderNo: '' })
@@ -34,12 +34,15 @@
<el-table-column prop="time" label="时间" min-width="170" />
</el-table>
</el-card>
<PageHelp :data="helpTorque" />
</template>
<script setup>
import { reactive, ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '../utils/request'
import PageHelp from '../components/PageHelp.vue'
import { helpTorque } from '../help'
const query = reactive({ sn: '', workOrderNo: '' })
const torque = reactive({ sn: '', workOrderNo: '', stationNo: '', strain: 20, angle: 90, operator: '' })
@@ -57,11 +57,14 @@
</el-tabs>
</template>
</el-card>
<PageHelp :data="helpTrace" />
</template>
<script setup>
import { ref } from 'vue'
import request from '../utils/request'
import PageHelp from '../components/PageHelp.vue'
import { helpTrace } from '../help'
const sn = ref('')
const data = ref(null)
@@ -84,12 +84,15 @@
</el-table>
</el-dialog>
</div>
<PageHelp :data="helpWorkOrder" />
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import request from '../utils/request'
import PageHelp from '../components/PageHelp.vue'
import { helpWorkOrder } from '../help'
const statusOptions = [
{ v: 'CREATED', l: '已创建' }, { v: 'RELEASED', l: '已发布' },