feat(safety): 安全生产二期 - 安全风险分级管控前端
配套后端风险单元 / 风险清单接口。
新增:
- api/safety/risk/unit、api/safety/risk/list
- views/safety/risk/unit:风险单元管理(列表 + 表单)
- views/safety/risk/list:风险清单管理(列表 + 表单)
* L/E/C 选择采用标准 LEC 取值(含每个取值的含义说明),选项变化后实时算出 D 与等级
* 弹窗顶部用 Alert 直接给出「D = xxx,判定为xx风险」
* 列表用四色标签区分重大/较大/一般/低风险
- dict-enum.ts 补 4 个字典常量(不加则下拉框全空)
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '#/packages/effects/request/src'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace MesSafetyRiskApi { |
| | | /** é£é©æ¸
å */ |
| | | export interface Risk { |
| | | id?: number; |
| | | unitId?: number; |
| | | unitName?: string; |
| | | workshopName?: string; |
| | | code?: string; |
| | | name?: string; |
| | | accidentType?: number; |
| | | possibleConsequence?: string; |
| | | likelihood?: number; |
| | | exposure?: number; |
| | | consequence?: number; |
| | | riskValue?: number; |
| | | riskLevel?: number; |
| | | riskLevelName?: string; |
| | | controlEngineering?: string; |
| | | controlManagement?: string; |
| | | controlTraining?: string; |
| | | controlPpe?: string; |
| | | controlEmergency?: string; |
| | | evaluateDate?: string; |
| | | nextEvaluateDate?: string; |
| | | chargeUserId?: number; |
| | | chargeUserName?: string; |
| | | status?: number; |
| | | remark?: string; |
| | | createTime?: string; |
| | | } |
| | | |
| | | /** å页忰 */ |
| | | export interface RiskPageParam extends PageParam { |
| | | code?: string; |
| | | name?: string; |
| | | unitId?: number; |
| | | accidentType?: number; |
| | | riskLevel?: number; |
| | | status?: number; |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢é£é©æ¸
åå页 */ |
| | | export function getRiskPage(params: MesSafetyRiskApi.RiskPageParam) { |
| | | return requestClient.get<PageResult<MesSafetyRiskApi.Risk>>( |
| | | '/mes/safety/risk/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢é£é©æ¸
å详æ
*/ |
| | | export function getRisk(id: number) { |
| | | return requestClient.get<MesSafetyRiskApi.Risk>( |
| | | `/mes/safety/risk/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢æå®é£é©åå
ä¸çé£é©æ¸
å */ |
| | | export function getRiskListByUnit(unitId: number) { |
| | | return requestClient.get<MesSafetyRiskApi.Risk[]>( |
| | | `/mes/safety/risk/list-by-unit?unitId=${unitId}`, |
| | | ); |
| | | } |
| | | |
| | | /** å建é£é©æ¸
å */ |
| | | export function createRisk(data: MesSafetyRiskApi.Risk) { |
| | | return requestClient.post<number>('/mes/safety/risk/create', data); |
| | | } |
| | | |
| | | /** æ´æ°é£é©æ¸
å */ |
| | | export function updateRisk(data: MesSafetyRiskApi.Risk) { |
| | | return requestClient.put<boolean>('/mes/safety/risk/update', data); |
| | | } |
| | | |
| | | /** å é¤é£é©æ¸
å */ |
| | | export function deleteRisk(id: number) { |
| | | return requestClient.delete<boolean>(`/mes/safety/risk/delete?id=${id}`); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { PageParam, PageResult } from '#/packages/effects/request/src'; |
| | | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | export namespace MesSafetyRiskUnitApi { |
| | | /** é£é©åå
*/ |
| | | export interface RiskUnit { |
| | | id?: number; |
| | | code?: string; |
| | | name?: string; |
| | | workshopId?: number; |
| | | workshopName?: string; |
| | | location?: string; |
| | | riskCategory?: number; |
| | | chargeUserId?: number; |
| | | chargeUserName?: string; |
| | | status?: number; |
| | | riskCount?: number; |
| | | remark?: string; |
| | | createTime?: string; |
| | | } |
| | | |
| | | /** å页忰 */ |
| | | export interface RiskUnitPageParam extends PageParam { |
| | | code?: string; |
| | | name?: string; |
| | | workshopId?: number; |
| | | riskCategory?: number; |
| | | status?: number; |
| | | } |
| | | } |
| | | |
| | | /** æ¥è¯¢é£é©åå
å页 */ |
| | | export function getRiskUnitPage(params: MesSafetyRiskUnitApi.RiskUnitPageParam) { |
| | | return requestClient.get<PageResult<MesSafetyRiskUnitApi.RiskUnit>>( |
| | | '/mes/safety/risk-unit/page', |
| | | { params }, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢é£é©åå
详æ
*/ |
| | | export function getRiskUnit(id: number) { |
| | | return requestClient.get<MesSafetyRiskUnitApi.RiskUnit>( |
| | | `/mes/safety/risk-unit/get?id=${id}`, |
| | | ); |
| | | } |
| | | |
| | | /** æ¥è¯¢é£é©åå
ç²¾ç®å表ï¼ä¸æç¨ï¼ */ |
| | | export function getRiskUnitSimpleList() { |
| | | return requestClient.get<MesSafetyRiskUnitApi.RiskUnit[]>( |
| | | '/mes/safety/risk-unit/simple-list', |
| | | ); |
| | | } |
| | | |
| | | /** å建é£é©åå
*/ |
| | | export function createRiskUnit(data: MesSafetyRiskUnitApi.RiskUnit) { |
| | | return requestClient.post<number>('/mes/safety/risk-unit/create', data); |
| | | } |
| | | |
| | | /** æ´æ°é£é©åå
*/ |
| | | export function updateRiskUnit(data: MesSafetyRiskUnitApi.RiskUnit) { |
| | | return requestClient.put<boolean>('/mes/safety/risk-unit/update', data); |
| | | } |
| | | |
| | | /** å é¤é£é©åå
*/ |
| | | export function deleteRiskUnit(id: number) { |
| | | return requestClient.delete<boolean>(`/mes/safety/risk-unit/delete?id=${id}`); |
| | | } |
| | |
| | | MES_EM_ALERT_LEVEL: 'mes_em_alert_level', // MES è½èé¢è¦çº§å« |
| | | MES_EM_ALERT_STATUS: 'mes_em_alert_status', // MES è½èé¢è¦å¤çç¶æ |
| | | MES_PRO_EMERGENCY_PLAN_TYPE: 'mes_pro_emergency_plan_type', // MES åºæ¥å¤ç½®é¢æ¡ç±»å |
| | | MES_SAFETY_RISK_LEVEL: 'mes_safety_risk_level', // å®å
¨ç产-é£é©ç级 |
| | | MES_SAFETY_RISK_CATEGORY: 'mes_safety_risk_category', // å®å
¨ç产-é£é©ç±»å« |
| | | MES_SAFETY_ACCIDENT_TYPE: 'mes_safety_accident_type', // å®å
¨ç产-äºæ
ç±»å |
| | | MES_SAFETY_UNIT_STATUS: 'mes_safety_unit_status', // å®å
¨ç产-é£é©åå
ç¶æ |
| | | } as const; |
| | | |
| | | /** ========== WMS - ä»å¨ç®¡ç模å ========== */ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesSafetyRiskApi } from '#/api/safety/risk/list'; |
| | | |
| | | import { DICT_TYPE } from '#/packages/constants/src'; |
| | | import { getDictOptions } from '#/packages/effects/hooks/src'; |
| | | |
| | | import { z } from '#/adapter/form'; |
| | | import { getRiskUnitSimpleList } from '#/api/safety/risk/unit'; |
| | | import { getSimpleUserList } from '../shared'; |
| | | |
| | | /** L / E / C æ ååå¼ï¼LEC æ ¼é·åå§-éå°¼æ³ï¼ */ |
| | | export const LIKELIHOOD_OPTIONS = [ |
| | | { label: '10 - å®å
¨å¯ä»¥é¢æ', value: 10 }, |
| | | { label: '6 - ç¸å½å¯è½', value: 6 }, |
| | | { label: '3 - å¯è½ï¼ä½ä¸ç»å¸¸', value: 3 }, |
| | | { label: '1 - å¯è½æ§å°ï¼å®å
¨æå¤', value: 1 }, |
| | | ]; |
| | | |
| | | export const EXPOSURE_OPTIONS = [ |
| | | { label: '10 - è¿ç»æ´é²', value: 10 }, |
| | | { label: '6 - æ¯å¤©å·¥ä½æ¶é´å
æ´é²', value: 6 }, |
| | | { label: '3 - æ¯å¨ä¸æ¬¡æå¶ç¶æ´é²', value: 3 }, |
| | | { label: '2 - æ¯æä¸æ¬¡æ´é²', value: 2 }, |
| | | { label: '1 - æ¯å¹´å 次æ´é²', value: 1 }, |
| | | { label: '0.5 - é常ç½è§å°æ´é²', value: 0.5 }, |
| | | ]; |
| | | |
| | | export const CONSEQUENCE_OPTIONS = [ |
| | | { label: '100 - 大ç¾é¾ï¼è®¸å¤äººæ»äº¡', value: 100 }, |
| | | { label: '40 - ç¾é¾ï¼æ°äººæ»äº¡', value: 40 }, |
| | | { label: '15 - é常严éï¼ä¸äººæ»äº¡', value: 15 }, |
| | | { label: '7 - 严éï¼é伤', value: 7 }, |
| | | { label: '5 - é大ï¼è´æ®', value: 5 }, |
| | | { label: '3 - è¾å¤§ï¼è½»ä¼¤', value: 3 }, |
| | | { label: '1 - å¼äººæ³¨ç®ï¼éè¦ææ¤', value: 1 }, |
| | | ]; |
| | | |
| | | /** æé£é©å¼ D 计ç®é£é©ç级ï¼â¥320 é大(1)ï¼â¥160 è¾å¤§(2)ï¼â¥70 ä¸è¬(3)ï¼å
¶ä½ä½(4) */ |
| | | export function calcRiskLevel(riskValue?: number): number | undefined { |
| | | if (riskValue === undefined || riskValue === null) { |
| | | return undefined; |
| | | } |
| | | if (riskValue >= 320) return 1; |
| | | if (riskValue >= 160) return 2; |
| | | if (riskValue >= 70) return 3; |
| | | return 4; |
| | | } |
| | | |
| | | /** é£é©ç级åç§° */ |
| | | export function riskLevelName(level?: number): string { |
| | | switch (level) { |
| | | case 1: return 'é大é£é©'; |
| | | case 2: return 'è¾å¤§é£é©'; |
| | | case 3: return 'ä¸è¬é£é©'; |
| | | case 4: return 'ä½é£é©'; |
| | | default: return ''; |
| | | } |
| | | } |
| | | |
| | | /** é£é©ç级对åºçæ ç¾é¢è² */ |
| | | export function riskLevelColor(level?: number): string { |
| | | switch (level) { |
| | | case 1: return 'error'; |
| | | case 2: return 'warning'; |
| | | case 3: return 'processing'; |
| | | case 4: return 'success'; |
| | | default: return 'default'; |
| | | } |
| | | } |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'code', |
| | | label: 'é£é©ç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { allowClear: true, placeholder: '请è¾å
¥é£é©ç¼ç ' }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: 'é£é©åç§°', |
| | | component: 'Input', |
| | | componentProps: { allowClear: true, placeholder: '请è¾å
¥é£é©åç§°' }, |
| | | }, |
| | | { |
| | | fieldName: 'unitId', |
| | | label: 'é£é©åå
', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | allowClear: true, |
| | | api: getRiskUnitSimpleList, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | placeholder: 'è¯·éæ©é£é©åå
', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'riskLevel', |
| | | label: 'é£é©ç级', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.MES_SAFETY_RISK_LEVEL, 'number'), |
| | | placeholder: 'è¯·éæ©é£é©ç级', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** æ°å¢/ä¿®æ¹ç表å */ |
| | | export function useFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { triggerFields: [''], show: () => false }, |
| | | }, |
| | | { |
| | | fieldName: 'unitId', |
| | | label: 'é£é©åå
', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | api: getRiskUnitSimpleList, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | placeholder: 'è¯·éæ©é£é©åå
', |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'code', |
| | | label: 'é£é©ç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { placeholder: 'å¦ FX-001-01' }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: 'é£é©åç§°', |
| | | component: 'Input', |
| | | componentProps: { placeholder: 'å¦ ç缸è¶
åçç¸' }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'accidentType', |
| | | label: 'äºæ
ç±»å', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.MES_SAFETY_ACCIDENT_TYPE, 'number'), |
| | | placeholder: 'è¯·éæ©å¯è½å¯¼è´çäºæ
ç±»å', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'possibleConsequence', |
| | | label: 'å¯è½åæ', |
| | | component: 'Textarea', |
| | | componentProps: { placeholder: 'å¦ äººå伤亡ãè®¾å¤ææ¯', rows: 2 }, |
| | | }, |
| | | { |
| | | fieldName: 'likelihood', |
| | | label: 'L å¯è½æ§', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: LIKELIHOOD_OPTIONS, |
| | | placeholder: 'è¯·éæ© L', |
| | | }, |
| | | help: 'D = L Ã E Ã C', |
| | | }, |
| | | { |
| | | fieldName: 'exposure', |
| | | label: 'E æ´é²é¢ç', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: EXPOSURE_OPTIONS, |
| | | placeholder: 'è¯·éæ© E', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'consequence', |
| | | label: 'C åæä¸¥éæ§', |
| | | component: 'Select', |
| | | componentProps: { |
| | | options: CONSEQUENCE_OPTIONS, |
| | | placeholder: 'è¯·éæ© C', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'riskValue', |
| | | label: 'D é£é©å¼', |
| | | component: 'InputNumber', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | disabled: true, |
| | | placeholder: 'ç± LÃEÃC èªå¨è®¡ç®', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'riskLevel', |
| | | label: 'é£é©ç级', |
| | | component: 'Select', |
| | | componentProps: { |
| | | disabled: true, |
| | | options: getDictOptions(DICT_TYPE.MES_SAFETY_RISK_LEVEL, 'number'), |
| | | placeholder: 'ç±é£é©å¼èªå¨å¤å®', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'controlEngineering', |
| | | label: 'å·¥ç¨ææ¯æªæ½', |
| | | component: 'Textarea', |
| | | componentProps: { placeholder: 'å¦ å®è£
å®å
¨éãèéä¿æ¤', rows: 2 }, |
| | | }, |
| | | { |
| | | fieldName: 'controlManagement', |
| | | label: 'ç®¡çæªæ½', |
| | | component: 'Textarea', |
| | | componentProps: { placeholder: 'å¦ å®æå·¡æ£ãä½ä¸ç¥¨å®¡æ¹', rows: 2 }, |
| | | }, |
| | | { |
| | | fieldName: 'controlTraining', |
| | | label: 'å¹è®æè²æªæ½', |
| | | component: 'Textarea', |
| | | componentProps: { placeholder: 'å¦ å²åå¹è®ãä¸é¡¹å¹è®', rows: 2 }, |
| | | }, |
| | | { |
| | | fieldName: 'controlPpe', |
| | | label: '个ä½é²æ¤æªæ½', |
| | | component: 'Textarea', |
| | | componentProps: { placeholder: 'å¦ å®å
¨å¸½ã鲿¤æå¥', rows: 2 }, |
| | | }, |
| | | { |
| | | fieldName: 'controlEmergency', |
| | | label: 'åºæ¥å¤ç½®æªæ½', |
| | | component: 'Textarea', |
| | | componentProps: { placeholder: 'å¦ ç«å³åæºãçæ£äººå', rows: 2 }, |
| | | }, |
| | | { |
| | | fieldName: 'chargeUserId', |
| | | label: '管æ§è´£ä»»äºº', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | | placeholder: 'è¯·éæ©ç®¡æ§è´£ä»»äºº', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'evaluateDate', |
| | | label: 'æ¬æ¬¡è¯ä¼°æ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | placeholder: 'è¯·éæ©è¯ä¼°æ¥æ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'nextEvaluateDate', |
| | | label: '䏿¬¡è¯ä¼°æ¥æ', |
| | | component: 'DatePicker', |
| | | componentProps: { |
| | | class: '!w-full', |
| | | format: 'YYYY-MM-DD', |
| | | valueFormat: 'YYYY-MM-DD', |
| | | placeholder: 'è¯·éæ©ä¸æ¬¡è¯ä¼°æ¥æ', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'RadioGroup', |
| | | componentProps: { |
| | | buttonStyle: 'solid', |
| | | optionType: 'button', |
| | | options: [ |
| | | { label: 'ææ', value: 1 }, |
| | | { label: '已失æ', value: 0 }, |
| | | ], |
| | | }, |
| | | rules: z.number().default(1), |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { placeholder: '请è¾å
¥å¤æ³¨', rows: 2 }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions<MesSafetyRiskApi.Risk>['columns'] { |
| | | return [ |
| | | { field: 'code', title: 'é£é©ç¼ç ', width: 130 }, |
| | | { field: 'name', title: 'é£é©åç§°', minWidth: 180 }, |
| | | { field: 'unitName', title: 'é£é©åå
', minWidth: 150 }, |
| | | { field: 'workshopName', title: 'æå±è½¦é´', width: 110 }, |
| | | { |
| | | field: 'accidentType', |
| | | title: 'äºæ
ç±»å', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_SAFETY_ACCIDENT_TYPE }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'riskValue', |
| | | title: 'é£é©å¼ D', |
| | | width: 100, |
| | | align: 'right', |
| | | formatter: 'formatAmount2', |
| | | }, |
| | | { |
| | | field: 'riskLevel', |
| | | title: 'é£é©ç级', |
| | | width: 110, |
| | | slots: { default: 'riskLevel' }, |
| | | }, |
| | | { field: 'chargeUserName', title: '管æ§è´£ä»»äºº', width: 110 }, |
| | | { |
| | | field: 'evaluateDate', |
| | | title: 'è¯ä¼°æ¥æ', |
| | | width: 120, |
| | | }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | width: 90, |
| | | slots: { default: 'status' }, |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 200, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesSafetyRiskApi } from '#/api/safety/risk/list'; |
| | | |
| | | import { Page } from '#/packages/effects/common-ui/src'; |
| | | |
| | | import { message, Tag } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { deleteRisk, getRiskPage } from '#/api/safety/risk/list'; |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { riskLevelColor, riskLevelName, useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | defineOptions({ name: 'SafetyRiskList' }); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => |
| | | await getRiskPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }), |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<MesSafetyRiskApi.Risk>, |
| | | }); |
| | | |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | function handleEdit(row: MesSafetyRiskApi.Risk) { |
| | | formModalApi.setData({ formType: 'update', id: row.id }).open(); |
| | | } |
| | | |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | async function handleDelete(row: MesSafetyRiskApi.Risk) { |
| | | await deleteRisk(row.id!); |
| | | message.success('å 餿å'); |
| | | gridApi.query(); |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'æ°å¢é£é©', |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mes:safety-risk:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | |
| | | <template #riskLevel="{ row }"> |
| | | <Tag :color="riskLevelColor(row.riskLevel)"> |
| | | {{ row.riskLevelName || riskLevelName(row.riskLevel) || '-' }} |
| | | </Tag> |
| | | </template> |
| | | |
| | | <template #status="{ row }"> |
| | | <Tag :color="row.status === 1 ? 'success' : 'default'"> |
| | | {{ row.status === 1 ? 'ææ' : '已失æ' }} |
| | | </Tag> |
| | | </template> |
| | | |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'ç¼è¾', |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:safety-risk:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'å é¤', |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mes:safety-risk:delete'], |
| | | popConfirm: { |
| | | title: 'ç¡®å®å é¤è¯¥é£é©è®°å½åï¼', |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { MesSafetyRiskApi } from '#/api/safety/risk/list'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { Alert, message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { createRisk, getRisk, updateRisk } from '#/api/safety/risk/list'; |
| | | |
| | | import { calcRiskLevel, riskLevelName, useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | |
| | | const formType = ref<'create' | 'update'>('create'); |
| | | const isUpdate = computed(() => formType.value === 'update'); |
| | | const getTitle = computed(() => |
| | | isUpdate.value ? 'ä¿®æ¹é£é©æ¸
å' : 'æ°å¢é£é©æ¸
å', |
| | | ); |
| | | |
| | | /** 宿¶å±ç¤ºçè¯ä¼°ç»æ */ |
| | | const riskValue = ref<number>(); |
| | | const riskLevel = ref<number>(); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { class: 'w-full' }, |
| | | formItemClass: 'col-span-2', |
| | | labelWidth: 120, |
| | | }, |
| | | wrapperClass: 'grid-cols-2', |
| | | layout: 'horizontal', |
| | | schema: useFormSchema(), |
| | | showDefaultActions: false, |
| | | // L / E / C ä»»ä¸ååæ¶ï¼èªå¨éç® D ä¸é£é©ç级 |
| | | handleValuesChange: (values, changedFields) => { |
| | | const lecFields = ['likelihood', 'exposure', 'consequence']; |
| | | if (!lecFields.some((f) => changedFields.includes(f))) { |
| | | return; |
| | | } |
| | | const { likelihood, exposure, consequence } = values as MesSafetyRiskApi.Risk; |
| | | if ( |
| | | likelihood === undefined || |
| | | likelihood === null || |
| | | exposure === undefined || |
| | | exposure === null || |
| | | consequence === undefined || |
| | | consequence === null |
| | | ) { |
| | | riskValue.value = undefined; |
| | | riskLevel.value = undefined; |
| | | return; |
| | | } |
| | | const d = Number((likelihood * exposure * consequence).toFixed(2)); |
| | | riskValue.value = d; |
| | | riskLevel.value = calcRiskLevel(d); |
| | | formApi.setFieldValue('riskValue', d); |
| | | formApi.setFieldValue('riskLevel', riskLevel.value); |
| | | }, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = (await formApi.getValues()) as MesSafetyRiskApi.Risk; |
| | | try { |
| | | await (isUpdate.value ? updateRisk(data) : createRisk(data)); |
| | | emit('success'); |
| | | message.success('æä½æå'); |
| | | await modalApi.close(); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | riskValue.value = undefined; |
| | | riskLevel.value = undefined; |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ |
| | | formType: 'create' | 'update'; |
| | | id?: number; |
| | | }>(); |
| | | formType.value = data.formType; |
| | | await formApi.resetForm(); |
| | | if (data?.id) { |
| | | modalApi.lock(); |
| | | try { |
| | | const risk = await getRisk(data.id); |
| | | await formApi.setValues(risk); |
| | | riskValue.value = risk?.riskValue; |
| | | riskLevel.value = risk?.riskLevel; |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | } else { |
| | | formApi.setFieldValue('status', 1); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-2/3"> |
| | | <Form class="mx-4" /> |
| | | <div v-if="riskValue !== undefined" class="mx-4 mt-2"> |
| | | <Alert |
| | | :type="riskLevel === 1 ? 'error' : riskLevel === 2 ? 'warning' : 'info'" |
| | | show-icon |
| | | :message="`é£é©è¯ä¼°ç»æï¼D = ${riskValue}ï¼å¤å®ä¸ºã${riskLevelName(riskLevel)}ã`" |
| | | /> |
| | | </div> |
| | | </Modal> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import { requestClient } from '#/api/request'; |
| | | |
| | | /** |
| | | * 车é´ä¸æé项 |
| | | * |
| | | * å¤ç¨è½è模åå·²æä¾ç车é´é项æ¥å£ï¼è¿å MES 车é´è¡¨çåºç¡æ°æ®ï¼ |
| | | */ |
| | | export function getWorkshopOptions() { |
| | | return requestClient.get<Array<{ code?: string; id: number; name: string }>>( |
| | | '/mes/em/meter/workshop-options', |
| | | ); |
| | | } |
| | | |
| | | /** |
| | | * ç¨æ·ç²¾ç®å表ï¼ç¨äºè´£ä»»äººä¸æï¼ |
| | | */ |
| | | export function getSimpleUserList() { |
| | | return requestClient.get< |
| | | Array<{ id: number; nickname: string; username?: string }> |
| | | >('/system/user/simple-list'); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesSafetyRiskUnitApi } from '#/api/safety/risk/unit'; |
| | | |
| | | import { DICT_TYPE } from '#/packages/constants/src'; |
| | | import { getDictOptions } from '#/packages/effects/hooks/src'; |
| | | |
| | | import { z } from '#/adapter/form'; |
| | | import { getSimpleUserList, getWorkshopOptions } from '../shared'; |
| | | |
| | | /** å表çæç´¢è¡¨å */ |
| | | export function useGridFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'code', |
| | | label: 'åå
ç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { allowClear: true, placeholder: '请è¾å
¥é£é©åå
ç¼ç ' }, |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: 'åå
åç§°', |
| | | component: 'Input', |
| | | componentProps: { allowClear: true, placeholder: '请è¾å
¥é£é©åå
åç§°' }, |
| | | }, |
| | | { |
| | | fieldName: 'riskCategory', |
| | | label: 'é£é©ç±»å«', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.MES_SAFETY_RISK_CATEGORY, 'number'), |
| | | placeholder: 'è¯·éæ©é£é©ç±»å«', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.MES_SAFETY_UNIT_STATUS, 'number'), |
| | | placeholder: 'è¯·éæ©ç¶æ', |
| | | }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** æ°å¢/ä¿®æ¹ç表å */ |
| | | export function useFormSchema(): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | | component: 'Input', |
| | | dependencies: { triggerFields: [''], show: () => false }, |
| | | }, |
| | | { |
| | | fieldName: 'code', |
| | | label: 'åå
ç¼ç ', |
| | | component: 'Input', |
| | | componentProps: { placeholder: 'å¦ FX-001' }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'name', |
| | | label: 'åå
åç§°', |
| | | component: 'Input', |
| | | componentProps: { placeholder: 'å¦ é 纸车é´1#ç缸' }, |
| | | rules: 'required', |
| | | }, |
| | | { |
| | | fieldName: 'workshopId', |
| | | label: 'æå±è½¦é´', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | allowClear: true, |
| | | api: getWorkshopOptions, |
| | | labelField: 'name', |
| | | valueField: 'id', |
| | | placeholder: 'è¯·éæ©æå±è½¦é´', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'location', |
| | | label: 'å
·ä½ä½ç½®', |
| | | component: 'Input', |
| | | componentProps: { placeholder: 'å¦ é 纸车é´ä¸ä¾§' }, |
| | | }, |
| | | { |
| | | fieldName: 'riskCategory', |
| | | label: 'é£é©ç±»å«', |
| | | component: 'Select', |
| | | componentProps: { |
| | | allowClear: true, |
| | | options: getDictOptions(DICT_TYPE.MES_SAFETY_RISK_CATEGORY, 'number'), |
| | | placeholder: 'è¯·éæ©é£é©ç±»å«', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'chargeUserId', |
| | | label: '责任人', |
| | | component: 'ApiSelect', |
| | | componentProps: { |
| | | allowClear: true, |
| | | api: getSimpleUserList, |
| | | labelField: 'nickname', |
| | | valueField: 'id', |
| | | placeholder: 'è¯·éæ©è´£ä»»äºº', |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'status', |
| | | label: 'ç¶æ', |
| | | component: 'RadioGroup', |
| | | componentProps: { |
| | | buttonStyle: 'solid', |
| | | optionType: 'button', |
| | | options: getDictOptions(DICT_TYPE.MES_SAFETY_UNIT_STATUS, 'number'), |
| | | }, |
| | | rules: z.number().default(1), |
| | | }, |
| | | { |
| | | fieldName: 'remark', |
| | | label: '夿³¨', |
| | | component: 'Textarea', |
| | | formItemClass: 'col-span-2', |
| | | componentProps: { placeholder: '请è¾å
¥å¤æ³¨', rows: 3 }, |
| | | }, |
| | | ]; |
| | | } |
| | | |
| | | /** å表çåæ®µ */ |
| | | export function useGridColumns(): VxeTableGridOptions<MesSafetyRiskUnitApi.RiskUnit>['columns'] { |
| | | return [ |
| | | { field: 'code', title: 'åå
ç¼ç ', width: 130 }, |
| | | { field: 'name', title: 'åå
åç§°', minWidth: 180 }, |
| | | { field: 'workshopName', title: 'æå±è½¦é´', width: 120 }, |
| | | { field: 'location', title: 'å
·ä½ä½ç½®', minWidth: 150 }, |
| | | { |
| | | field: 'riskCategory', |
| | | title: 'é£é©ç±»å«', |
| | | width: 110, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_SAFETY_RISK_CATEGORY }, |
| | | }, |
| | | }, |
| | | { field: 'chargeUserName', title: '责任人', width: 100 }, |
| | | { |
| | | field: 'riskCount', |
| | | title: 'é£é©æ¡æ°', |
| | | width: 100, |
| | | align: 'right', |
| | | slots: { default: 'riskCount' }, |
| | | }, |
| | | { |
| | | field: 'status', |
| | | title: 'ç¶æ', |
| | | width: 90, |
| | | cellRender: { |
| | | name: 'CellDict', |
| | | props: { type: DICT_TYPE.MES_SAFETY_UNIT_STATUS }, |
| | | }, |
| | | }, |
| | | { |
| | | field: 'createTime', |
| | | title: 'å建æ¶é´', |
| | | width: 180, |
| | | formatter: 'formatDateTime', |
| | | }, |
| | | { |
| | | title: 'æä½', |
| | | width: 160, |
| | | fixed: 'right', |
| | | slots: { default: 'actions' }, |
| | | }, |
| | | ]; |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { MesSafetyRiskUnitApi } from '#/api/safety/risk/unit'; |
| | | |
| | | import { Page } from '#/packages/effects/common-ui/src'; |
| | | |
| | | import { Tag } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { deleteRiskUnit, getRiskUnitPage } from '#/api/safety/risk/unit'; |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useGridColumns, useGridFormSchema } from './data'; |
| | | import Form from './modules/form.vue'; |
| | | |
| | | defineOptions({ name: 'SafetyRiskUnit' }); |
| | | |
| | | const [FormModal, formModalApi] = useVbenModal({ |
| | | connectedComponent: Form, |
| | | destroyOnClose: true, |
| | | }); |
| | | |
| | | const [Grid, gridApi] = useVbenVxeGrid({ |
| | | formOptions: { |
| | | schema: useGridFormSchema(), |
| | | }, |
| | | gridOptions: { |
| | | columns: useGridColumns(), |
| | | height: 'auto', |
| | | keepSource: true, |
| | | proxyConfig: { |
| | | ajax: { |
| | | query: async ({ page }, formValues) => |
| | | await getRiskUnitPage({ |
| | | pageNo: page.currentPage, |
| | | pageSize: page.pageSize, |
| | | ...formValues, |
| | | }), |
| | | }, |
| | | }, |
| | | rowConfig: { |
| | | keyField: 'id', |
| | | isHover: true, |
| | | }, |
| | | toolbarConfig: { |
| | | refresh: true, |
| | | search: true, |
| | | }, |
| | | } as VxeTableGridOptions<MesSafetyRiskUnitApi.RiskUnit>, |
| | | }); |
| | | |
| | | /** æ°å¢ */ |
| | | function handleCreate() { |
| | | formModalApi.setData({ formType: 'create' }).open(); |
| | | } |
| | | |
| | | /** ç¼è¾ */ |
| | | function handleEdit(row: MesSafetyRiskUnitApi.RiskUnit) { |
| | | formModalApi.setData({ formType: 'update', id: row.id }).open(); |
| | | } |
| | | |
| | | /** å·æ° */ |
| | | function handleRefresh() { |
| | | gridApi.query(); |
| | | } |
| | | |
| | | /** å é¤ */ |
| | | async function handleDelete(row: MesSafetyRiskUnitApi.RiskUnit) { |
| | | await deleteRiskUnit(row.id!); |
| | | message.success('å 餿å'); |
| | | gridApi.query(); |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <Page auto-content-height> |
| | | <FormModal @success="handleRefresh" /> |
| | | <Grid> |
| | | <template #toolbar-tools> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'æ°å¢é£é©åå
', |
| | | type: 'primary', |
| | | icon: ACTION_ICON.ADD, |
| | | auth: ['mes:safety-risk-unit:create'], |
| | | onClick: handleCreate, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | |
| | | <template #riskCount="{ row }"> |
| | | <Tag v-if="row.riskCount > 0" color="processing">{{ row.riskCount }}</Tag> |
| | | <span v-else class="text-gray-400">0</span> |
| | | </template> |
| | | |
| | | <template #actions="{ row }"> |
| | | <TableAction |
| | | :actions="[ |
| | | { |
| | | label: 'ç¼è¾', |
| | | type: 'link', |
| | | icon: ACTION_ICON.EDIT, |
| | | auth: ['mes:safety-risk-unit:update'], |
| | | onClick: handleEdit.bind(null, row), |
| | | }, |
| | | { |
| | | label: 'å é¤', |
| | | type: 'link', |
| | | danger: true, |
| | | icon: ACTION_ICON.DELETE, |
| | | auth: ['mes:safety-risk-unit:delete'], |
| | | popConfirm: { |
| | | title: 'ç¡®å®å é¤è¯¥é£é©åå
åï¼', |
| | | confirm: handleDelete.bind(null, row), |
| | | }, |
| | | }, |
| | | ]" |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | </Page> |
| | | </template> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <script lang="ts" setup> |
| | | import type { MesSafetyRiskUnitApi } from '#/api/safety/risk/unit'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useVbenModal } from '@vben/common-ui'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { |
| | | createRiskUnit, |
| | | getRiskUnit, |
| | | updateRiskUnit, |
| | | } from '#/api/safety/risk/unit'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | |
| | | const formType = ref<'create' | 'update'>('create'); |
| | | const isUpdate = computed(() => formType.value === 'update'); |
| | | const getTitle = computed(() => |
| | | isUpdate.value ? 'ä¿®æ¹é£é©åå
' : 'æ°å¢é£é©åå
', |
| | | ); |
| | | |
| | | const [Form, formApi] = useVbenForm({ |
| | | commonConfig: { |
| | | componentProps: { class: 'w-full' }, |
| | | formItemClass: 'col-span-1', |
| | | labelWidth: 100, |
| | | }, |
| | | wrapperClass: 'grid-cols-2', |
| | | layout: 'horizontal', |
| | | schema: useFormSchema(), |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | const { valid } = await formApi.validate(); |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | const data = (await formApi.getValues()) as MesSafetyRiskUnitApi.RiskUnit; |
| | | try { |
| | | await (isUpdate.value |
| | | ? updateRiskUnit(data) |
| | | : createRiskUnit(data)); |
| | | emit('success'); |
| | | message.success('æä½æå'); |
| | | await modalApi.close(); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | }, |
| | | async onOpenChange(isOpen: boolean) { |
| | | if (!isOpen) { |
| | | return; |
| | | } |
| | | const data = modalApi.getData<{ formType: 'create' | 'update'; id?: number }>(); |
| | | formType.value = data.formType; |
| | | await formApi.resetForm(); |
| | | if (data?.id) { |
| | | modalApi.lock(); |
| | | try { |
| | | const unit = await getRiskUnit(data.id); |
| | | await formApi.setValues(unit); |
| | | } finally { |
| | | modalApi.unlock(); |
| | | } |
| | | } else { |
| | | formApi.setFieldValue('status', 1); |
| | | } |
| | | }, |
| | | }); |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-1/2"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |