From 4392c41e1a268e551aaf90b48c1f1c82ff6fe846 Mon Sep 17 00:00:00 2001 From: hwj Date: Thu, 22 Jan 2026 09:57:21 +0800 Subject: [PATCH 01/15] =?UTF-8?q?feat=EF=BC=9A=E9=87=87=E9=9B=86=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E6=A8=A1=E5=9E=8B-=E7=82=B9=E4=BD=8D=E8=A7=84?= =?UTF-8?q?=E5=88=99-=E6=B7=BB=E5=8A=A0=E6=96=B0=E5=A2=9E=E5=BC=B9?= =?UTF-8?q?=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/iot/devicemodel/index.vue | 71 +++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/views/iot/devicemodel/index.vue b/src/views/iot/devicemodel/index.vue index 1b8cf46c..f844aa4d 100644 --- a/src/views/iot/devicemodel/index.vue +++ b/src/views/iot/devicemodel/index.vue @@ -149,6 +149,12 @@ link type="primary" @click="openForm('update', scope.row.id)" +
+ + 新增告警规则 + +
+ + + + + + + + + + + + + + + + @@ -546,6 +574,15 @@ const ruleForm = reactive>({ ruleValue: undefined, }) +const createRuleDialogVisible = ref(false) +const createRuleFormLoading = ref(false) +const createRuleFormRef = ref() +const createRuleForm = reactive({ + identifier: 'ALARM', + fieldName: '', + defaultValue: '报警', +}) + const extraPointRules = ref< Array<{ id?: number @@ -601,6 +638,17 @@ const isRunningIdentifier = computed(() => { return (ruleForm.identifier || '').toString().toUpperCase() === 'RUNNING' }) +const openCreateRuleForm = () => { + if (!attributeModelId.value) { + message.error('请先选择模型') + return + } + createRuleForm.identifier = 'ALARM' + createRuleForm.fieldName = '报警' + createRuleForm.defaultValue = '报警' + createRuleDialogVisible.value = true +} + const openRuleForm = (row: DeviceModelRuleVO & { pointRulesVOList?: any[] }) => { ruleForm.id = row.id ruleForm.identifier = row.identifier @@ -703,6 +751,29 @@ const handleAddPointRule = () => { }) } +const handleCreateRuleSubmit = async () => { + if (!attributeModelId.value) return + if (!createRuleForm.fieldName) { + message.warning('请输入名称') + return + } + try { + createRuleFormLoading.value = true + const payload = { + identifier: createRuleForm.identifier, + fieldName: createRuleForm.fieldName, + defaultValue: createRuleForm.defaultValue, + modelId: attributeModelId.value, + } + await request.post({ url: '/iot/device-model-rules/create', data: payload }) + message.success('新增成功') + createRuleDialogVisible.value = false + await getRuleList() + } finally { + createRuleFormLoading.value = false + } +} + const handleRemovePointRule = (index: number) => { if (index < 0 || index >= extraPointRules.value.length) return extraPointRules.value.splice(index, 1) From a7dc1d1632c3c7411b1df77d3c80e5d262343fbd Mon Sep 17 00:00:00 2001 From: hwj Date: Thu, 22 Jan 2026 11:21:35 +0800 Subject: [PATCH 02/15] =?UTF-8?q?feat=EF=BC=9A=E9=87=87=E9=9B=86=E8=AE=BE?= =?UTF-8?q?=E5=A4=87-=E6=B7=BB=E5=8A=A0=E7=82=B9=E4=BD=8D=E8=A7=84?= =?UTF-8?q?=E5=88=99=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/iot/device/index.vue | 570 ++++++++++++++++++++++++++++++++- 1 file changed, 560 insertions(+), 10 deletions(-) diff --git a/src/views/iot/device/index.vue b/src/views/iot/device/index.vue index 854b40c1..544e231f 100644 --- a/src/views/iot/device/index.vue +++ b/src/views/iot/device/index.vue @@ -145,12 +145,263 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'" - - - - - - + + @@ -158,6 +409,7 @@ link :type="isRowConnected(scope.row) ? 'warning' : 'success'" import { getStrDictOptions, DICT_TYPE } from '@/utils/dict' import { dateFormatter } from '@/utils/formatTime' import download from '@/utils/download' +import request from '@/config/axios' import { DeviceApi, DeviceConnectParams, DeviceVO } from '@/api/iot/device' import DeviceForm from './DeviceForm.vue' import DeviceAttributeList from './components/DeviceAttributeList.vue' @@ -288,14 +540,30 @@ const handleExport = async () => { } } +interface DevicePointRuleVO { + id: number + identifier: string + fieldName: string + fieldRule: string + defaultValue: string + deviceId: number + createTime?: string | number | Date + ruleAttributeId?: number + ruleOperator?: string + ruleValue?: string | number +} + const attributeDeviceId = ref(undefined) const attributeDeviceName = ref('') +const deviceTabActive = ref('deviceAttribute') + const deviceAttributeTabLabel = computed(() => { - if (!attributeDeviceId.value) { - return '设备属性' - } - return attributeDeviceName.value ? `设备属性:${attributeDeviceName.value}` : '设备属性' + return '设备属性' +}) + +const deviceRuleTabLabel = computed(() => { + return '点位规则' }) const handleShowAttribute = (row: any) => { @@ -303,6 +571,288 @@ const handleShowAttribute = (row: any) => { attributeDeviceName.value = row?.deviceName ?? '' } +const ruleLoading = ref(false) +const ruleList = ref([]) +const ruleTotal = ref(0) +const ruleQueryParams = reactive({ + pageNo: 1, + pageSize: 10, + identifier: undefined as string | undefined, + fieldName: undefined as string | undefined, + fieldRule: undefined as string | undefined, + defaultValue: undefined as string | undefined, + deviceId: undefined as number | undefined, +}) +const ruleQueryFormRef = ref() + +const ruleAttributeOptions = ref([]) + +const getRuleList = async () => { + if (!attributeDeviceId.value) return + ruleLoading.value = true + try { + const params = { + ...ruleQueryParams, + deviceId: attributeDeviceId.value, + } + const data = await request.get({ url: '/iot/device-point-rules/page', params }) + const listData = Array.isArray((data as any)?.list) ? (data as any).list : (Array.isArray(data) ? data : []) + const totalData = (data as any)?.total ?? listData.length + ruleList.value = listData as DevicePointRuleVO[] + ruleTotal.value = totalData + } finally { + ruleLoading.value = false + } +} + +const handleRuleQuery = () => { + if (!attributeDeviceId.value) return + ruleQueryParams.pageNo = 1 + getRuleList() +} + +const resetRuleQuery = () => { + if (!attributeDeviceId.value) return + ruleQueryFormRef.value?.resetFields?.() + handleRuleQuery() +} + +const loadRuleAttributeOptions = async (deviceId: number) => { + try { + const res = await DeviceApi.getDeviceAttributePage({ pageNo: 1, pageSize: 1000, deviceId }) + const data = Array.isArray((res as any)?.list) ? (res as any).list : (Array.isArray(res) ? res : []) + ruleAttributeOptions.value = data as any[] + } catch { + ruleAttributeOptions.value = [] + } +} + +watch( + () => attributeDeviceId.value, + async (val) => { + ruleQueryParams.deviceId = val ?? undefined + if (!val) { + ruleList.value = [] + ruleTotal.value = 0 + ruleAttributeOptions.value = [] + return + } + ruleQueryParams.pageNo = 1 + await Promise.all([getRuleList(), loadRuleAttributeOptions(val)]) + } +) + +const ruleDialogVisible = ref(false) +const ruleFormLoading = ref(false) +const ruleFormRef = ref() +const ruleForm = reactive>({ + id: undefined, + identifier: '', + fieldName: '', + fieldRule: '', + defaultValue: '', + deviceId: undefined, + ruleAttributeId: undefined, + ruleOperator: undefined, + ruleValue: undefined, +}) + +const extraPointRules = ref< + Array<{ + id?: number + rule?: string + operator?: string + operatorRule?: string | number + }> +>([]) + +const runningRuleOptions = [ + { value: '1', label: '运行' }, + { value: '2', label: '待机中(不运行、没故障)' }, + { value: '3', label: '故障中(故障且待机)' }, + { value: '4', label: '报警中(故障且运行)' }, +] + +const alarmRuleOptions = [{ value: 'ALARM', label: '报警' }] + +const currentRuleOptions = computed(() => { + const id = (ruleForm.identifier || '').toString().toUpperCase() + if (id === 'RUNNING') return runningRuleOptions + if (id === 'ALARM') return alarmRuleOptions + return [] +}) + +const isRuleDisabled = (value: string, selfRule?: string | number) => { + if (!value) return false + const v = String(value) + const self = selfRule != null ? String(selfRule) : undefined + if (self === v) return false + if (ruleForm.fieldRule && String(ruleForm.fieldRule) === v && self !== v) return true + if ( + extraPointRules.value.some( + (item) => item.rule != null && String(item.rule) === v && String(item.rule) !== self + ) + ) { + return true + } + return false +} + +const ruleOperatorOptions = computed(() => getStrDictOptions('czsb_rules_conditions')) + +const isRunningIdentifier = computed(() => { + return (ruleForm.identifier || '').toString().toUpperCase() === 'RUNNING' +}) + +const openRuleForm = (row: DevicePointRuleVO & { pointRulesVOList?: any[] }) => { + ruleForm.id = row.id + ruleForm.identifier = row.identifier + ruleForm.fieldName = row.fieldName + ruleForm.defaultValue = row.defaultValue + ruleForm.deviceId = row.deviceId + + extraPointRules.value = [] + + const list = Array.isArray(row.pointRulesVOList) ? row.pointRulesVOList : [] + + if (list.length) { + const first = list[0] as any + ruleForm.fieldRule = (first.rule ?? row.fieldRule) as any + ruleForm.ruleAttributeId = first.id as any + ruleForm.ruleOperator = first.operator as any + ruleForm.ruleValue = first.operatorRule as any + extraPointRules.value = list.slice(1).map((item: any) => ({ + id: item.id, + rule: item.rule, + operator: item.operator, + operatorRule: item.operatorRule, + })) + } else { + ruleForm.fieldRule = row.fieldRule + ruleForm.ruleAttributeId = row.ruleAttributeId + ruleForm.ruleOperator = row.ruleOperator + ruleForm.ruleValue = row.ruleValue as any + } + + const options = currentRuleOptions.value + if (options.length && !options.some((item) => item.value === ruleForm.fieldRule)) { + ruleForm.fieldRule = options[0].value + } + ruleDialogVisible.value = true +} + +const handleRuleSubmit = async () => { + if (!ruleForm.id) return + try { + ruleFormLoading.value = true + const pointRulesVOList: any[] = [] + + if (ruleForm.ruleAttributeId && ruleForm.ruleOperator) { + pointRulesVOList.push({ + id: ruleForm.ruleAttributeId, + rule: ruleForm.fieldRule, + operator: ruleForm.ruleOperator, + operatorRule: ruleForm.ruleValue, + }) + } + + extraPointRules.value.forEach((item) => { + if (!item.id || !item.operator) return + pointRulesVOList.push({ + id: item.id, + rule: item.rule ?? ruleForm.fieldRule, + operator: item.operator, + operatorRule: item.operatorRule, + }) + }) + + const payload = { + id: ruleForm.id, + identifier: ruleForm.identifier, + fieldName: ruleForm.fieldName, + fieldRule: ruleForm.fieldRule, + defaultValue: ruleForm.defaultValue, + deviceId: ruleForm.deviceId ?? attributeDeviceId.value, + pointRulesVOList, + } + + await request.put({ url: '/iot/device-point-rules/update', data: payload }) + message.success('保存成功') + ruleDialogVisible.value = false + await getRuleList() + } finally { + ruleFormLoading.value = false + } +} + +const handleAddPointRule = () => { + if (!isRunningIdentifier.value) return + const allOptions = currentRuleOptions.value || [] + const used = new Set() + if (ruleForm.fieldRule) used.add(String(ruleForm.fieldRule)) + extraPointRules.value.forEach((item) => { + if (item.rule != null) used.add(String(item.rule)) + }) + const next = allOptions.find((opt) => !used.has(String(opt.value))) + if (!next) { + message.warning('已没有可用的点位规则可选') + return + } + extraPointRules.value.push({ + rule: next.value as any, + id: undefined, + operator: undefined, + operatorRule: undefined, + }) +} + +const handleRemovePointRule = (index: number) => { + if (index < 0 || index >= extraPointRules.value.length) return + extraPointRules.value.splice(index, 1) +} + +const createRuleDialogVisible = ref(false) +const createRuleFormLoading = ref(false) +const createRuleFormRef = ref() +const createRuleForm = reactive({ + identifier: 'ALARM', + fieldName: '', + defaultValue: '报警', +}) + +const openCreateRuleForm = () => { + if (!attributeDeviceId.value) { + message.error('请先选择设备') + return + } + createRuleForm.identifier = 'ALARM' + createRuleForm.fieldName = '报警' + createRuleForm.defaultValue = '报警' + createRuleDialogVisible.value = true +} + +const handleCreateRuleSubmit = async () => { + if (!attributeDeviceId.value) return + if (!createRuleForm.fieldName) { + message.warning('请输入名称') + return + } + try { + createRuleFormLoading.value = true + const payload = { + identifier: createRuleForm.identifier, + fieldName: createRuleForm.fieldName, + defaultValue: createRuleForm.defaultValue, + deviceId: attributeDeviceId.value, + } + await request.post({ url: '/iot/device-point-rules/create', data: payload }) + message.success('新增成功') + createRuleDialogVisible.value = false + await getRuleList() + } finally { + createRuleFormLoading.value = false + } +} const connectLoadingMap = reactive>({}) const getRowConnectValue = (row: any) => { From 287a42ffe16cf4c0a667cdb59282994d723cb84f Mon Sep 17 00:00:00 2001 From: hwj Date: Thu, 22 Jan 2026 11:22:53 +0800 Subject: [PATCH 03/15] =?UTF-8?q?style=EF=BC=9A=E9=87=87=E9=9B=86=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E6=A8=A1=E5=9E=8B-=E7=82=B9=E4=BD=8D=E8=A7=84?= =?UTF-8?q?=E5=88=99-=E6=9D=A1=E4=BB=B6=E4=BD=BF=E7=94=A8=E5=AD=97?= =?UTF-8?q?=E5=85=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/iot/devicemodel/index.vue | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/views/iot/devicemodel/index.vue b/src/views/iot/devicemodel/index.vue index f844aa4d..802f898f 100644 --- a/src/views/iot/devicemodel/index.vue +++ b/src/views/iot/devicemodel/index.vue @@ -195,7 +195,7 @@ link type="primary" @click="openForm('update', scope.row.id)"
-
+
{ return false } -const ruleOperatorOptions = [ - { value: 'TRUE', label: '为真' }, - { value: 'FALSE', label: '为假' }, - { value: 'EQ', label: '等于' }, - { value: 'LE', label: '小于等于' }, - { value: 'GE', label: '大于等于' }, -] +const ruleOperatorOptions = computed(() => getStrDictOptions('czsb_rules_conditions')) const isRunningIdentifier = computed(() => { return (ruleForm.identifier || '').toString().toUpperCase() === 'RUNNING' From 4647ed6b9a83f7de3bbd488481439d5cde2f43c7 Mon Sep 17 00:00:00 2001 From: hwj Date: Thu, 22 Jan 2026 11:36:22 +0800 Subject: [PATCH 04/15] =?UTF-8?q?style=EF=BC=9A=E9=87=87=E9=9B=86=E8=AE=BE?= =?UTF-8?q?=E5=A4=87-=E9=87=87=E9=9B=86=E5=91=A8=E6=9C=9F=E5=BF=85?= =?UTF-8?q?=E5=A1=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/iot/device/DeviceForm.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/views/iot/device/DeviceForm.vue b/src/views/iot/device/DeviceForm.vue index c40f6c77..c61a80f3 100644 --- a/src/views/iot/device/DeviceForm.vue +++ b/src/views/iot/device/DeviceForm.vue @@ -168,9 +168,11 @@ const formRules = reactive({ create: { deviceCode: [{ required: true, message: '设备编码不能为空', trigger: 'blur' }], deviceName: [{ required: true, message: '设备名称不能为空', trigger: 'blur' }], + sampleCycle: [{ required: true, message: '采集周期不能为空', trigger: 'blur' }], isEnable: [{ required: true, message: '是否启用不能为空', trigger: 'blur' }] }, update: { + sampleCycle: [{ required: true, message: '采集周期不能为空', trigger: 'blur' }], isEnable: [{ required: true, message: '是否启用不能为空', trigger: 'blur' }] }, setting: { From f4f448c48e0fe9a35eab48b2bd8cd087862df641 Mon Sep 17 00:00:00 2001 From: hwj Date: Thu, 22 Jan 2026 14:58:33 +0800 Subject: [PATCH 05/15] =?UTF-8?q?style=EF=BC=9A=E6=A8=A1=E5=85=B7=E8=AF=A6?= =?UTF-8?q?=E6=83=85-=E5=8E=9F=E5=BC=B9=E7=AA=97=E7=8E=B0=E6=94=B9?= =?UTF-8?q?=E6=88=90=E6=96=B0=E5=BC=80=E9=A1=B5=E9=9D=A2=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/router/modules/remaining.ts | 19 + src/views/erp/mold/components/MoldList.vue | 499 +-------------------- src/views/erp/mold/detail/index.vue | 486 ++++++++++++++++++++ 3 files changed, 508 insertions(+), 496 deletions(-) create mode 100644 src/views/erp/mold/detail/index.vue diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 986b6360..fdb8c006 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -579,6 +579,25 @@ const remainingRouter: AppRouteRecordRaw[] = [ } ] }, + { + path: '/erp', + component: Layout, + name: 'ErpCenter', + meta: { hidden: true }, + children: [ + { + path: 'mold/detail/:id', + name: 'ErpMoldDetail', + meta: { + title: '模具详情', + noCache: true, + hidden: true, + activeMenu: '/erp/mold' + }, + component: () => import('@/views/erp/mold/detail/index.vue') + } + ] + }, { path: '/:pathMatch(.*)*', diff --git a/src/views/erp/mold/components/MoldList.vue b/src/views/erp/mold/components/MoldList.vue index 95d02c4a..37512b08 100644 --- a/src/views/erp/mold/components/MoldList.vue +++ b/src/views/erp/mold/components/MoldList.vue @@ -58,218 +58,6 @@ link type="primary" @click="openForm('update', scope.row.id)" - -
- - {{ detailData?.code ?? '' }} - {{ detailData?.name ?? '' }} - - - - {{ detailData?.brandName ?? '' }} - {{ detailData?.moldType ?? '' }} - - - - {{ detailData?.moldSize ?? '' }} - {{ detailData?.useTime ?? '' }} - {{ detailData?.machineName ?? detailData?.machineId ?? '' - }} - {{ formatDetailDate(detailData?.inTime) }} - - - - {{ detailData?.remark ?? '' }} - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
- @@ -354,291 +142,10 @@ const recordFormRef = ref() const openRecordForm = (type: string, id?: number, brandId?: number) => { recordFormRef.value.open(type, id, brandId) } +const { push } = useRouter() -const detailVisible = ref(false) -const detailLoading = ref(false) -const detailData = ref<(MoldVO & Record) | null>(null) -const detailActiveTab = ref('check') - -const formatDetailDate = (value: any) => { - if (!value) return '' - return formatDate(new Date(value), 'YYYY-MM-DD') -} - -const formatHistoryTime = (value: any) => { - const raw = value ?? '-' - if (Array.isArray(raw) && raw.length >= 3) { - const [y, m, d, hh, mm, ss] = raw - const pad = (n: any) => String(n).padStart(2, '0') - if (hh !== undefined) return `${y}-${pad(m)}-${pad(d)} ${pad(hh)}:${pad(mm)}:${pad(ss)}` - return `${y}-${pad(m)}-${pad(d)}` - } - return String(raw) -} - -const getResultLabel = (value: any) => { - const v = value === '' || value === null || value === undefined ? undefined : String(value) - if (v === '0') return '待检测' - if (v === '1') return 'OK' - if (v === '2') return 'NG' - return '-' -} - -const getResultTagType = (value: any) => { - const v = value === '' || value === null || value === undefined ? undefined : String(value) - if (v === '1') return 'success' - if (v === '2') return 'danger' - if (v === '0') return 'info' - return 'info' -} - -const inspectionHistory = computed(() => { - const data: any = detailData.value - return data?.inspectionList ?? [] -}) - -const maintainHistory = computed(() => { - const data: any = detailData.value - const list = data?.maintainList ?? [] - return Array.isArray(list) ? list : [] -}) - -type HistoryStepItem = { - key: string - name: string - result: any - method?: any - criteria?: any - images?: string[] - remark?: any - inspectionTime?: any - createTime?: any -} - -type HistoryStepGroup = { key: string; time: string; operator: string; items: HistoryStepItem[] } - -const parseImages = (value: any): string[] => { - if (!value) return [] - if (Array.isArray(value)) return value.map(String).filter(Boolean) - const cleaned = String(value).replace(/[`'\"]/g, '').trim() - return cleaned - .split(',') - .map((v) => v.trim()) - .filter(Boolean) -} - -const buildStepGroups = ( - rows: any[], - options: { timeField: string; nameFieldCandidates: string[]; resultFieldCandidates: string[] } -) => { - const groups = new Map() - - for (const row of rows ?? []) { - const time = formatHistoryTime(row?.[options.timeField] ?? row?.createTime) - const operator = String(row?.creatorName ?? row?.creator ?? '-') - const groupKey = `${row?.managementId ?? ''}__${time}__${operator}` - - const name = - options.nameFieldCandidates - .map((k) => row?.[k]) - .find((v) => v !== undefined && v !== null && String(v).trim() !== '') ?? '-' - - const result = - options.resultFieldCandidates.map((k) => row?.[k]).find((v) => v !== undefined && v !== null) ?? undefined - - const item: HistoryStepItem = { - key: String(row?.id ?? `${groupKey}__${String(name)}`), - name: String(name), - result, - method: row?.inspectionMethod, - criteria: row?.judgmentCriteria, - images: parseImages(row?.images), - remark: row?.remark, - inspectionTime: row?.inspectionTime, - createTime: row?.createTime - } - - if (!groups.has(groupKey)) { - groups.set(groupKey, { key: groupKey, time, operator, items: [item] }) - } else { - groups.get(groupKey)!.items.push(item) - } - } - - return Array.from(groups.values()).sort((a, b) => String(b.time).localeCompare(String(a.time))) -} - -const inspectionStepGroups = computed(() => { - return buildStepGroups(inspectionHistory.value, { - timeField: 'inspectionTime', - nameFieldCandidates: ['inspectionItemName', 'name'], - resultFieldCandidates: ['inspectionResult'] - }) -}) - -const maintainStepGroups = computed(() => { - return buildStepGroups(maintainHistory.value, { - timeField: 'inspectionTime', - nameFieldCandidates: ['maintainItemName', 'inspectionItemName', 'name'], - resultFieldCandidates: ['maintainResult', 'inspectionResult'] - }) -}) - -type RepairHistoryRow = { - repairId?: any - subjectCode?: any - subjectName?: any - subjectContent?: any - subjectStandard?: any - malfunction?: any - repairDes?: any - remark?: any - createTime?: any -} - -const repairHistoryView = computed(() => { - const data: any = detailData.value - const raw = data?.repairList - if (!raw) return [] - if (Array.isArray(raw)) { - return raw as RepairHistoryRow[] - } - if (typeof raw === 'object') { - const result: RepairHistoryRow[] = [] - Object.values(raw as Record).forEach((rows: any) => { - if (Array.isArray(rows)) { - result.push(...(rows as RepairHistoryRow[])) - } - }) - return result - } - return [] -}) - -const openDetail = async (id: number) => { - detailVisible.value = true - detailActiveTab.value = 'check' - detailLoading.value = true - try { - detailData.value = await MoldBrandApi.getMold(id) - } finally { - detailLoading.value = false - } +const openDetail = (id: number) => { + push({ name: 'ErpMoldDetail', params: { id } }) } - - diff --git a/src/views/erp/mold/detail/index.vue b/src/views/erp/mold/detail/index.vue new file mode 100644 index 00000000..735acd23 --- /dev/null +++ b/src/views/erp/mold/detail/index.vue @@ -0,0 +1,486 @@ + + + + From 6c08ed1e18b0965a1135fb6439d0f1f1c23e4ca7 Mon Sep 17 00:00:00 2001 From: hwj Date: Thu, 22 Jan 2026 15:31:40 +0800 Subject: [PATCH 06/15] =?UTF-8?q?style=EF=BC=9A=E9=87=87=E9=9B=86=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E6=A8=A1=E5=9E=8B-ALARM=E6=A0=87=E8=AF=86=E7=AC=A6?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=B7=BB=E5=8A=A0=E5=88=A0=E9=99=A4=E6=8C=89?= =?UTF-8?q?=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/iot/devicemodel/index.vue | 30 +++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/views/iot/devicemodel/index.vue b/src/views/iot/devicemodel/index.vue index 802f898f..68ded9fe 100644 --- a/src/views/iot/devicemodel/index.vue +++ b/src/views/iot/devicemodel/index.vue @@ -167,11 +167,19 @@ link type="primary" @click="openForm('update', scope.row.id)" - + @@ -645,7 +653,15 @@ const openCreateRuleForm = () => { createRuleDialogVisible.value = true } -const openRuleForm = (row: DeviceModelRuleVO & { pointRulesVOList?: any[] }) => { +const openRuleForm = async (row: DeviceModelRuleVO & { pointRulesVOList?: any[] }) => { + const modelId = row.modelId || attributeModelId.value + if (!modelId) { + message.error('模型信息缺失,无法加载点位规则') + return + } + + await loadRuleAttributeOptions(modelId) + ruleForm.id = row.id ruleForm.identifier = row.identifier ruleForm.fieldName = row.fieldName @@ -726,6 +742,16 @@ const handleRuleSubmit = async () => { } } +const handleRuleDelete = async (id: number) => { + if (!id) return + try { + await message.delConfirm() + await request.delete({ url: '/iot/device-model-rules/delete?id=' + id }) + message.success(t('common.delSuccess')) + await getRuleList() + } catch { } +} + const handleAddPointRule = () => { if (!isRunningIdentifier.value) return const allOptions = currentRuleOptions.value || [] From c7bd47b73b0901d1aa9f695f7594fb04da116d33 Mon Sep 17 00:00:00 2001 From: hwj Date: Thu, 22 Jan 2026 15:33:10 +0800 Subject: [PATCH 07/15] =?UTF-8?q?style=EF=BC=9Acss=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/UploadFile/src/UploadFile.vue | 2 +- src/views/Home/Index.vue | 38 ++++++++++---------- src/views/erp/mold/detail/index.vue | 15 +++++--- src/views/formula/formulaConfig/index.vue | 12 +++---- src/views/mes/deviceledger/index.vue | 16 ++++----- src/views/mes/energydevicecheck/index.vue | 2 +- src/views/mes/zjschema/ZjSchemaForm.vue | 12 +++---- 7 files changed, 51 insertions(+), 46 deletions(-) diff --git a/src/components/UploadFile/src/UploadFile.vue b/src/components/UploadFile/src/UploadFile.vue index 9c770072..25f8a709 100644 --- a/src/components/UploadFile/src/UploadFile.vue +++ b/src/components/UploadFile/src/UploadFile.vue @@ -234,8 +234,8 @@ const emitUpdateModelValue = () => { .ellipsis-text { display: inline-block; max-width: 100px; - white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + white-space: nowrap; } diff --git a/src/views/Home/Index.vue b/src/views/Home/Index.vue index 7a4c8250..f76f6f2b 100644 --- a/src/views/Home/Index.vue +++ b/src/views/Home/Index.vue @@ -790,13 +790,13 @@ getAllApi() } .home-welcome { - min-height: 240px; display: flex; - justify-content: space-between; - align-items: center; - background: linear-gradient(90deg, #3a6bc5 0%, #2a5298 100%); + min-height: 240px; padding: 0 24px; + background: linear-gradient(90deg, #3a6bc5 0%, #2a5298 100%); border-radius: 4px; + justify-content: space-between; + align-items: center; } .home-welcome-left { @@ -804,9 +804,9 @@ getAllApi() } .home-welcome-title { + margin-bottom: 8px; font-size: 32px; font-weight: 500; - margin-bottom: 8px; } .home-welcome-desc { @@ -859,13 +859,13 @@ getAllApi() } .home-welcome-image { - max-height: 180px; width: auto; + max-height: 180px; } .production-overview-row { - margin-top: 16px; display: flex; + margin-top: 16px; align-items: stretch; gap: 48px; } @@ -878,9 +878,9 @@ getAllApi() } .production-overview-group-center { - border-left: 1px solid var(--el-border-color-lighter); - border-right: 1px solid var(--el-border-color-lighter); padding: 0 48px; + border-right: 1px solid var(--el-border-color-lighter); + border-left: 1px solid var(--el-border-color-lighter); } .production-overview-item { @@ -926,8 +926,8 @@ getAllApi() .stat-card { padding: 12px 16px; - border-radius: 6px; background-color: #f5f7fa; + border-radius: 6px; } .stat-label { @@ -968,18 +968,18 @@ getAllApi() } .progress-card { + display: flex; + height: 180px; padding: 12px 16px; - border-radius: 6px; background-color: #f5f7fa; - height: 180px; - display: flex; + border-radius: 6px; flex-direction: column; } .progress-card-header { + margin-bottom: 8px; font-size: 14px; font-weight: 600; - margin-bottom: 8px; } .progress-card-body { @@ -1013,8 +1013,8 @@ getAllApi() .mini-card { padding: 12px 16px; - border-radius: 6px; background-color: #f5f7fa; + border-radius: 6px; } .mini-label { @@ -1041,11 +1041,11 @@ getAllApi() } .todo-card { + display: flex; + height: 150px; padding: 12px 16px; - border-radius: 6px; background-color: #f5f7fa; - height: 150px; - display: flex; + border-radius: 6px; flex-direction: column; justify-content: space-between; } @@ -1061,7 +1061,7 @@ getAllApi() color: #909399; } -@media (max-width: 768px) { +@media (width <= 768px) { .home-welcome { flex-direction: column; align-items: flex-start; diff --git a/src/views/erp/mold/detail/index.vue b/src/views/erp/mold/detail/index.vue index 735acd23..4396ec69 100644 --- a/src/views/erp/mold/detail/index.vue +++ b/src/views/erp/mold/detail/index.vue @@ -27,7 +27,8 @@ -