fmea评分标准添加
This commit is contained in:
@@ -25,17 +25,19 @@ const currentModalTitle = ref<string>('');
|
||||
const currentModalType = ref<string>('');
|
||||
// 当前弹框对象
|
||||
const currentModalObj = ref<string>('');
|
||||
// 评分标准弹框
|
||||
const ruleModal = ref<boolean>(false);
|
||||
// 项目总体信息与过程设置弹窗
|
||||
const openSetModal = ref<boolean>(false);
|
||||
// 项目总体信息
|
||||
const description = ref<string>('');
|
||||
const nodeList = ref<any[]>([]);
|
||||
const name = ref<string>('');
|
||||
// 过程流程描述
|
||||
// 步骤流程描述
|
||||
const node_description = ref<string>('');
|
||||
// 过程操作方式
|
||||
// 步骤操作方式
|
||||
const node_way = ref<string>('');
|
||||
// 过程保护措施
|
||||
// 步骤保护措施
|
||||
const node_protection = ref<string>('');
|
||||
// 分析列表弹窗
|
||||
const openListModal = ref<boolean>(false);
|
||||
@@ -47,6 +49,8 @@ const currentNodeIndex = ref<number>(-1)
|
||||
|
||||
// 打开分析列表弹框
|
||||
const openList = () => {
|
||||
currentNodeList.value = JSON.parse(JSON.stringify(nodes.value[currentNodeIndex.value]?.deviations || []))
|
||||
currentNodeListSource.value = JSON.parse(JSON.stringify(currentNodeList.value))
|
||||
node_description.value = currentNode.value?.description || ''
|
||||
openListModal.value = true
|
||||
}
|
||||
@@ -236,33 +240,29 @@ const setSave = async () => {
|
||||
const handleSelect = (key: string) => {
|
||||
runAi(key);
|
||||
}
|
||||
|
||||
const selectOptions = computed(() => {
|
||||
const l = props.fmeaRiskMatrixConfig?.probability?.map((item:{key:string,label:string}, index:number) => ({
|
||||
label: 'L'+'_'+Number(index + 1),
|
||||
value: 'L'+'_'+Number(index + 1)
|
||||
}));
|
||||
const s = props.fmeaRiskMatrixConfig?.consequence?.map((item:{key:string,label:string}, index:number) => ({
|
||||
label: 'S'+'_'+Number(index + 1),
|
||||
value: 'S'+'_'+Number(index + 1)
|
||||
}));
|
||||
return [...l, ...s];
|
||||
});
|
||||
|
||||
const l_options = computed(() => {
|
||||
const newArr = props.fmeaRiskMatrixConfig?.probability?.map((item:{key:string,label:string}, index:number) => ({
|
||||
...item,
|
||||
key: Number(index + 1)
|
||||
}));
|
||||
return newArr;
|
||||
});
|
||||
console.log(props.fmeaRiskMatrixConfig)
|
||||
const s_options = computed(() => {
|
||||
const newArr = props.fmeaRiskMatrixConfig?.consequence?.map((item:{key:string,label:string}, index:number) => ({
|
||||
...item,
|
||||
key: Number(index + 1)
|
||||
const newArr = props.fmeaRiskMatrixConfig?.s_grades?.map((item:any) => ({
|
||||
label: item.label+'('+item.score+')',
|
||||
value: item.score
|
||||
}));
|
||||
return newArr;
|
||||
});
|
||||
const p_options = computed(() => {
|
||||
const newArr = props.fmeaRiskMatrixConfig?.p_grades?.map((item:any) => ({
|
||||
label: item.label+'('+item.score+')',
|
||||
value: item.score
|
||||
}));
|
||||
return newArr;
|
||||
});
|
||||
const d_options = computed(() => {
|
||||
const newArr = props.fmeaRiskMatrixConfig?.d_grades?.map((item:any) => ({
|
||||
label: item.label+'('+item.score+')',
|
||||
value: item.score
|
||||
}));
|
||||
return newArr;
|
||||
});
|
||||
|
||||
// 右键菜单状态
|
||||
const contextMenuShow = ref<boolean>(false)
|
||||
const contextMenuX = ref<number>(0)
|
||||
@@ -450,85 +450,22 @@ const runInference = async () => {
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 根据l和s计算RR风险等级
|
||||
const riskLevel = (l: number, s: number) => {
|
||||
const num = l * s;
|
||||
for (let i = 0; i < props.fmeaRiskMatrixConfig?.risk_grades.length; i++) {
|
||||
const item = props.fmeaRiskMatrixConfig?.risk_grades[i];
|
||||
if (num >= item.min && num <= item.max) {
|
||||
return item; // 返回整条数据
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// 计算RR1风险等级
|
||||
const countRiskLevel = (row: any) => {
|
||||
const l = row.l_value;
|
||||
const s = row.s_value;
|
||||
const newArr = [...row?.safeguards || [],...row?.suggestions || []];
|
||||
const result:any = { L: 0, S: 0 };
|
||||
newArr.forEach(item => {
|
||||
if (!item.value) return; // 跳过空值
|
||||
const parts = item.value.split('_');
|
||||
if (parts.length === 2) {
|
||||
const type = parts[0].toUpperCase(); // 统一大写
|
||||
const num = parseInt(parts[1], 10);
|
||||
if (!isNaN(num) && (type === 'L' || type === 'S')) {
|
||||
result[type] += num;
|
||||
}
|
||||
}
|
||||
});
|
||||
const newL = (l - result.L) > 0 ? l - result.L : 1;
|
||||
const newS = (s - result.S) > 0 ? s - result.S : 1;
|
||||
return riskLevel(newL, newS);
|
||||
}
|
||||
|
||||
// 新增安全措施
|
||||
const addSafeguard = (index: number) => {
|
||||
if(currentDev.value.rows[index].safeguards){
|
||||
currentDev.value.rows[index].safeguards.push({name:'',value:''});
|
||||
}else{
|
||||
currentDev.value.rows[index].safeguards = [{name:'',value:''}];
|
||||
}
|
||||
save()
|
||||
}
|
||||
// 删除安全措施
|
||||
const delSafeguard = (index: number, safeguardIndex: number) => {
|
||||
currentDev.value.rows[index].safeguards.splice(safeguardIndex, 1);
|
||||
save()
|
||||
}
|
||||
// 新增建议措施
|
||||
const addSuggestion = (index: number) => {
|
||||
if(currentDev.value.rows[index].suggestions){
|
||||
currentDev.value.rows[index].suggestions.push({name:'',value:''});
|
||||
}else{
|
||||
currentDev.value.rows[index].suggestions = [{name:'',value:''}];
|
||||
}
|
||||
save()
|
||||
}
|
||||
// 删除建议措施
|
||||
const delSuggestion = (index: number, suggestionIndex: number) => {
|
||||
currentDev.value.rows[index].suggestions.splice(suggestionIndex, 1);
|
||||
save()
|
||||
}
|
||||
|
||||
// 新增行
|
||||
const addRow = async () => {
|
||||
console.log(props.fmeaRiskMatrixConfig)
|
||||
if(!currentDev.value){
|
||||
return window.$message?.warning("请先在左侧选择失效模式")
|
||||
}
|
||||
currentDev.value.rows.push({
|
||||
id: 0,
|
||||
cause: "",
|
||||
effect: "",
|
||||
s_value: 0,
|
||||
p_value: 0,
|
||||
d_value: 0,
|
||||
residual_level: '',
|
||||
safeguards: '',
|
||||
suggestions: '',
|
||||
});
|
||||
if(!currentDev.value){
|
||||
return window.$message?.warning("请先在左侧选择失效模式")
|
||||
}
|
||||
currentDev.value.rows.push({
|
||||
id: 0,
|
||||
cause: "",
|
||||
effect: "",
|
||||
s_value: null,
|
||||
p_value: null,
|
||||
d_value: null,
|
||||
residual_level: '',
|
||||
safeguards: '',
|
||||
suggestions: '',
|
||||
});
|
||||
};
|
||||
// 删除行
|
||||
const delRow = async (index: number) => {
|
||||
@@ -859,8 +796,6 @@ onBeforeUnmount(() => {
|
||||
|
||||
<div class="flex items-center gap-2 text-xs text-slate-500">
|
||||
<span>当前位置:</span>
|
||||
<!-- <NTag size="small">工作步骤:{{ currentNode?.node_name ?? '未选择' }}</NTag>
|
||||
<span>›</span> -->
|
||||
<NTag size="small" type="success">工作步骤:{{ currentNode?.node_name ?? '未选择' }}</NTag>
|
||||
<span>›</span>
|
||||
<NTag size="small" type="warning">失效模式:{{ currentDev?.deviation ?? '未选择' }}</NTag>
|
||||
@@ -894,7 +829,7 @@ onBeforeUnmount(() => {
|
||||
<div v-for="(dev, devIndex) in node.deviations" :key="devIndex"
|
||||
@click="clickDev(dev,Number(nodeIndex))"
|
||||
@contextmenu.prevent="handleContextMenu($event, 'dev', node, dev, Number(nodeIndex), Number(devIndex))"
|
||||
class="cursor-pointer flex w-full items-center ml-2 gap-1.5 rounded-md px-3 py-1.5 text-left text-xs transition"
|
||||
class="cursor-pointer flex items-center ml-4 gap-1.5 rounded-md px-2 py-1.5 text-left text-xs transition"
|
||||
:class="currentDev?.id === dev.id ? 'bg-[var(--theme-color)] text-white' : 'text-slate-600 hover:bg-slate-100'"
|
||||
>
|
||||
<span class="flex-1">{{ dev.deviation }}</span>
|
||||
@@ -907,6 +842,9 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<NButton size="small" type="primary" ghost block class="mt-2 text-xs" @click="ruleModal = true">
|
||||
评分标准
|
||||
</NButton>
|
||||
</div>
|
||||
<!-- 右:HAZOP 记录表 -->
|
||||
<div class="min-w-0 flex-1 bg-white">
|
||||
@@ -924,20 +862,20 @@ onBeforeUnmount(() => {
|
||||
</NButton>
|
||||
<span class="text-[11px] text-slate-400">风险等级按风险矩阵RPN = S × P × D 取值实时重算;「入表」将本条选入风险分析记录表</span>
|
||||
</div>
|
||||
<div class="scroll">
|
||||
<div class="scroll2">
|
||||
<table class="w-full border-collapse text-xs">
|
||||
<thead>
|
||||
<tr>
|
||||
<th :class="TH" class="w-16">操作</th>
|
||||
<th :class="TH" class="w-60">失效后果</th>
|
||||
<th :class="TH" class="w-6">S</th>
|
||||
<th :class="TH" class="w-60">失效原因</th>
|
||||
<th :class="TH" class="w-6">P</th>
|
||||
<th :class="TH" class="w-60">现有措施</th>
|
||||
<th :class="TH" class="w-6">D</th>
|
||||
<th :class="TH">失效后果</th>
|
||||
<th :class="TH" class="w-22">S</th>
|
||||
<th :class="TH">失效原因</th>
|
||||
<th :class="TH" class="w-22">P</th>
|
||||
<th :class="TH">现有措施</th>
|
||||
<th :class="TH" class="w-22">D</th>
|
||||
<th :class="TH" class="w-20">RPN</th>
|
||||
<th :class="TH" class="w-20">风险等级</th>
|
||||
<th :class="TH" class="w-60">建议措施</th>
|
||||
<th :class="TH">建议措施</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -968,22 +906,22 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</td>
|
||||
<td :class="TD">
|
||||
<NInput type="textarea" size="small" v-model:value="row.effect" :autosize="{minRows:1}" class="text-xs" @blur="save()" />
|
||||
<NInput type="textarea" size="small" v-model:value="row.effect" :autosize="{minRows:1}" class="text-xs" />
|
||||
</td>
|
||||
<td :class="TD" class="text-center">
|
||||
<!-- <NInputNumber v-model:value="row.s_value" size="tiny" :min="s_options[0].key" :max="s_options[s_options.length-1].key" :show-button="false" placeholder="" class="text-center w-10" @blur="save()" /> -->
|
||||
<NSelect v-model:value="row.s_value" size="tiny" :options="s_options" placeholder="请选择" class="text-center w-full mt-2px" />
|
||||
</td>
|
||||
<td :class="TD">
|
||||
<NInput type="textarea" size="small" v-model:value="row.cause" :autosize="{minRows:1}" class="text-xs" @blur="save()" />
|
||||
<NInput type="textarea" size="small" v-model:value="row.cause" :autosize="{minRows:1}" class="text-xs" />
|
||||
</td>
|
||||
<td :class="TD" class="text-center">
|
||||
<!-- <NInputNumber v-model:value="row.l_value" size="tiny" :min="l_options[0].key" :max="l_options[l_options.length-1].key" :show-button="false" placeholder="" class="text-center w-10" @blur="save()" /> -->
|
||||
<NSelect v-model:value="row.p_value" size="tiny" :options="p_options" placeholder="请选择" class="text-center w-full mt-2px" />
|
||||
</td>
|
||||
<td :class="TD">
|
||||
<NInput type="textarea" size="small" v-model:value="row.safeguards" :autosize="{minRows:1}" class="text-xs" @blur="save()" />
|
||||
<NInput type="textarea" size="small" v-model:value="row.safeguards" :autosize="{minRows:1}" class="text-xs" />
|
||||
</td>
|
||||
<td :class="TD" class="text-center">
|
||||
<!-- <NInputNumber v-model:value="row.l_value" size="tiny" :min="l_options[0].key" :max="l_options[l_options.length-1].key" :show-button="false" placeholder="" class="text-center w-10" @blur="save()" /> -->
|
||||
<NSelect v-model:value="row.d_value" size="tiny" :options="d_options" placeholder="请选择" class="text-center w-full mt-2px" />
|
||||
</td>
|
||||
<td :class="TD" class="text-center">
|
||||
<!-- <NTag
|
||||
@@ -1233,11 +1171,107 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</template>
|
||||
</NModal>
|
||||
<!-- 评分标准弹窗 -->
|
||||
<NModal
|
||||
v-model:show="ruleModal"
|
||||
preset="card"
|
||||
title="FMEA 评分标准"
|
||||
:auto-focus="false"
|
||||
:style="{ width: '700px', height: 'auto' }"
|
||||
:segmented="{ content: true, footer: false }"
|
||||
>
|
||||
<div class="space-y-3 scroll3">
|
||||
<p class="bg-[#F7FAFF] px-3 py-1.5 rounded-4px" :style="{color: themeStore.themeColor}">风险优先系数(RPN)= 严重性(S)× 可能性(P)× 可测定性(D)</p>
|
||||
<div>
|
||||
<p class="mb-1 font-13px font-600">表 1:风险的严重程度(SEV)评分制</p>
|
||||
<NTable size="small" :single-line="false">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="!text-center w-100px">结果</th>
|
||||
<th>结果的严重性</th>
|
||||
<th class="!text-center w-50px">评分</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item,index) in fmeaRiskMatrixConfig?.s_grades" :key="index">
|
||||
<td class="text-center">{{item.label}}</td>
|
||||
<td>{{item.description}}</td>
|
||||
<td class="text-center">{{item.score}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</NTable>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1 font-13px font-600">表 2:风险的发生几率(OCC)评分制</p>
|
||||
<NTable size="small" :single-line="false">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>失败发生的可能性</th>
|
||||
<th class="!text-center w-50px">评分</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item,index) in fmeaRiskMatrixConfig?.p_grades" :key="index">
|
||||
<td>{{item.label}}:{{item.description}}</td>
|
||||
<td class="text-center">{{item.score}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</NTable>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1 font-13px font-600">表 3:风险被检测或发现的可能性(DET)评分制</p>
|
||||
<NTable size="small" :single-line="false">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="!text-center w-100px">发现的可能性</th>
|
||||
<th>在发生之前通过过程控制可以检测出缺陷的可能性大小</th>
|
||||
<th class="!text-center w-50px">评分</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(item,index) in fmeaRiskMatrixConfig?.d_grades" :key="index">
|
||||
<td class="text-center">{{item.label}}</td>
|
||||
<td>{{item.description}}</td>
|
||||
<td class="text-center">{{item.score}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</NTable>
|
||||
</div>
|
||||
<div>
|
||||
<p class="mb-1 font-13px font-600">评价结果</p>
|
||||
<p class="mb-2">风险评价结果首先遵循:<span class="font-600">风险严重程度为高风险的即为高风险。</span></p>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div v-for="(item,index) in fmeaRiskMatrixConfig?.risk_grades" :key="index" class="flex items-center">
|
||||
<NTag
|
||||
size="small"
|
||||
:color="{
|
||||
color: item.bg_color,
|
||||
textColor: item.font_color,
|
||||
borderColor: item.bg_color,
|
||||
}"
|
||||
>
|
||||
{{item.name}}
|
||||
</NTag>
|
||||
<span class="ml-2">{{item.min_rpn}}-{{item.max_rpn}}分:</span>
|
||||
<span>{{item.control_measure}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</NModal>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.scroll {
|
||||
height: calc(100vh - 196px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.scroll2 {
|
||||
height: calc(100vh - 160px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
.scroll3 {
|
||||
max-height: calc(100vh - 140px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1057,7 +1057,7 @@ onBeforeUnmount(() => {
|
||||
<div v-for="(dev, devIndex) in obj.deviations" :key="devIndex"
|
||||
@click="clickDev(dev,Number(nodeIndex))"
|
||||
@contextmenu.prevent="handleContextMenu($event, 'dev', node, obj, dev, Number(nodeIndex), Number(objIndex), Number(devIndex))"
|
||||
class="cursor-pointer flex w-full items-center ml-2 gap-1.5 rounded-md px-3 py-1.5 text-left text-xs transition"
|
||||
class="cursor-pointer flex items-center ml-4 gap-1.5 rounded-md px-2 py-1.5 text-left text-xs transition"
|
||||
:class="currentDev?.id === dev.id ? 'bg-[var(--theme-color)] text-white' : 'text-slate-600 hover:bg-slate-100'"
|
||||
>
|
||||
<span class="flex-1">{{ dev.deviation }}</span>
|
||||
|
||||
Reference in New Issue
Block a user