+
+ :placeholder="t('EquipmentManagement.EquipmentLedger.placeholderBeijianIds')" @clear="clearBeijian" @click="openBeijianDialog"/>
@@ -138,11 +137,11 @@
@@ -178,9 +177,11 @@
{{ t('action.export') }}
-
+
+
@@ -191,6 +192,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('common.query') }}
+
+
+
+ {{ t('common.reset') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('common.cancel') }}
+ {{ t('common.ok') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('common.query') }}
+
+
+
+ {{ t('common.reset') }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('common.cancel') }}
+ {{ t('common.ok') }}
+
+
+
@@ -199,14 +316,15 @@ import { dateFormatter, formatDate } from '@/utils/formatTime'
import download from '@/utils/download'
import { DeviceLedgerApi, DeviceLedgerVO } from '@/api/mes/deviceledger'
import { DeviceTypeApi, DeviceTypeTreeVO } from '@/api/mes/devicetype'
-import { CriticalComponentApi } from '@/api/mes/criticalComponent'
-import { TicketManagementApi } from '@/api/mes/ticketManagement'
-import { DvRepairApi } from '@/api/mes/dvrepair'
+import {CriticalComponentApi, CriticalComponentVO} from '@/api/mes/criticalComponent'
+import { getSimpleUserList, UserVO } from '@/api/system/user'
+import {ProductApi, ProductVO} from '@/api/erp/product/product'
import QrcodeActionCard from '@/components/QrcodeActionCard/index.vue'
import { useTagsViewStore } from '@/store/modules/tagsView'
-import { downloadByUrl } from '@/utils/filt'
-import {ref} from "vue";
-
+import type { FormRules } from 'element-plus'
+import { ref } from 'vue'
+import {ElTable} from "element-plus";
+import { DICT_TYPE } from '@/utils/dict'
defineOptions({ name: 'MesDeviceLedgerEditDetail' })
const { t } = useI18n()
@@ -214,461 +332,606 @@ const message = useMessage()
const route = useRoute()
const { delView } = useTagsViewStore()
const { currentRoute } = useRouter()
-
const deviceId = computed(() => Number(route.params.id))
const detailLoading = ref(false)
const tableLoading = ref(false)
const detailData = ref()
const detailActiveTab = ref('criticalComponent')
+const criticalComponentDialogVisible = ref(false)
+const beijianDialogVisible = ref(false)
+const criticalComponentDraft = ref([])
+const beijianDraft = ref([])
+const list = ref([])
+const bjList = ref([])
+const loading = ref(true)
+const total = ref(0)
+const bjTotal = ref(0)
+const selectedIds = ref([])
+const bjSelectedIds = ref([])
+// 表格引用
+const multipleTableRef = ref>()
+const bjMultipleTableRef = ref>()
+const queryFormRef = ref()
+const bjQueryFormRef = ref()
+const parseIdsValue = (value: any): number[] => {
+ if (!value) return []
+ if (Array.isArray(value)) return value.map((v) => Number(v)).filter((v) => !Number.isNaN(v))
+ return String(value)
+ .split(',')
+ .map((v) => Number(v.trim()))
+ .filter((v) => !Number.isNaN(v))
+}
+const selectedRows = ref([]) // 存储所有选中的行
+const bjSelectedRows = ref([]) // 存储所有选中的行
+const queryParams = reactive({
+ pageNo: 1,
+ pageSize: 10,
+ code: undefined as string | undefined,
+ name: undefined as string | undefined,
+ description: undefined as string | undefined,
+ remark: undefined as string | undefined,
+ createTime: [] as string[]
+})
-const deviceTypeNameMap = ref>({})
-const formData = ref({
+const bjQueryParams = reactive({
+ pageNo: 1,
+ pageSize: 10,
+ name: undefined,
+ categoryId: undefined
})
-const buildDeviceTypeNameMap = (nodes: DeviceTypeTreeVO[]) => {
- const map: Record = {}
- const stack = [...nodes]
- while (stack.length) {
- const node = stack.pop()!
- if (typeof node.id === 'number') map[node.id] = node.name
- if (Array.isArray(node.children) && node.children.length) stack.push(...node.children)
- }
- deviceTypeNameMap.value = map
-}
-const getDeviceTypeName = (value: any) => {
- const id = typeof value === 'number' ? value : Number(value)
- if (!Number.isNaN(id) && deviceTypeNameMap.value[id]) return deviceTypeNameMap.value[id]
- return value ?? ''
+const handleQuery = () => {
+ queryParams.pageNo = 1
+ getList()
+}
+const resetQuery = () => {
+ queryFormRef.value.resetFields()
+ handleQuery()
}
-const detailTemplateJson = computed(() => {
- const templateJson = detailData.value?.templateJson
- if (!templateJson) return undefined
- if (typeof templateJson === 'string') {
- try {
- return JSON.parse(templateJson)
- } catch {
- return undefined
- }
- }
- return templateJson
-})
-
-type FileUrlItem = {
- fileName: string
- fileUrl: string
+/** 配件搜索按钮操作 */
+const bjHandleQuery = () => {
+ bjQueryParams.pageNo = 1
+ bjGetList()
}
-const getFileNameFromUrl = (url: string) => {
- const cleanUrl = url.split('?')[0]
- const fileName = cleanUrl.substring(cleanUrl.lastIndexOf('/') + 1)
- return decodeURIComponent(fileName || url)
+/** 配件重置按钮操作 */
+const bjResetQuery = () => {
+ bjQueryFormRef.value.resetFields()
+ bjHandleQuery()
}
-const parseFileUrlList = (value: any): FileUrlItem[] => {
- if (!value) return []
- let rawList: any[] = []
- if (Array.isArray(value)) {
- rawList = value
- } else if (typeof value === 'string') {
- const trimmed = value.trim()
- if (!trimmed) return []
- try {
- const parsed = JSON.parse(trimmed)
- rawList = Array.isArray(parsed) ? parsed : [parsed]
- } catch {
- rawList = trimmed
- .split(',')
- .map((url) => ({ fileUrl: url.trim() }))
- .filter((item) => item.fileUrl)
- }
- } else if (typeof value === 'object') {
- rawList = [value]
- }
- return rawList
- .map((item) => {
- if (!item) return undefined
- const fileUrl = typeof item === 'string' ? item : item.fileUrl
- if (!fileUrl) return undefined
- const normalizedUrl = String(fileUrl).trim()
- if (!normalizedUrl) return undefined
- const fileName =
- typeof item === 'string'
- ? getFileNameFromUrl(normalizedUrl)
- : item.fileName || getFileNameFromUrl(normalizedUrl)
- return {
- fileName: String(fileName),
- fileUrl: normalizedUrl
- }
- })
- .filter((item): item is FileUrlItem => Boolean(item))
+const handleSelectionChange = (rows: CriticalComponentVO[]) => {
+ selectedIds.value = rows.map((r) => r.id).filter((id): id is number => typeof id === 'number')
+ // 获取当前页所有行的 id
+ const currentPageIds = rows.map(item => item.id)
+
+ // 从已选中的数组中移除当前页的数据
+ selectedRows.value = selectedRows.value.filter(
+ item => !currentPageIds.includes(item.id)
+ )
+ // 添加当前页新选中的数据
+ selectedRows.value.push(...rows)
}
-const fileUrlList = computed(() => parseFileUrlList(detailData.value?.fileUrl))
+// 存储当前已选中的行
+const currentSelectedRows = ref([])
-const handleDownloadFile = (row: FileUrlItem) => {
- downloadByUrl({
- url: row.fileUrl,
- fileName: row.fileName
- })
-}
+// select 事件:row 是当前操作的行,selected 是操作后的状态
+const handleSelect = (selection, row) => {
+ // 判断是选中还是取消选中
+ const isSelected = selection.includes(row)
+ if (isSelected) {
+ // console.log(`✅ 行被选中: ID=${row.id}, Name=${row.name}`)
+ ids.value.push(row.id)
+ } else {
-const buildDetailPrintData = () => {
- return {
- id: detailData.value?.id,
- deviceCode: detailData.value?.deviceCode,
- deviceName: detailData.value?.deviceName,
- deviceSpec: detailData.value?.deviceSpec,
- deviceBrand: detailData.value?.deviceBrand,
- deviceModel: detailData.value?.deviceModel,
- deviceLocation: detailData.value?.deviceLocation,
- remark: detailData.value?.remark ?? detailData.value?.deviceRemark,
- qrcodeUrl: detailData.value?.qrcodeUrl
+ ids.value = ids.value.filter(
+ item => item !== row.id
+ )
+ // console.log(`❌ 行被取消选中: ID=${row.id}, Name=${row.name}`)
+ }
+ // 更新当前选中状态
+ currentSelectedRows.value = selection
+}
+
+
+const handleSelectAll = (selection) => {
+ ids.value = selection?.map((row) => row.id).filter((id) => id !== undefined) ?? []
+
+ /* let newVar = selection?.map((row) => row.id).filter((id) => id !== undefined) ?? [];
+ newVar.forEach(row => {
+ ids.value.push(row)
+ })*/
+}
+const confirmCriticalComponentDialog = () => {
+ //let ids = selectedRows.value.map(item => item.id);
+ //const validMap = new Set(criticalComponentOptions.value.map((item) => item.value))
+ //const selected = Array.from(new Set(criticalComponentDraft.value.map((v) => Number(v)).filter((v) => validMap.has(v))))
+ formData.value.componentIds = filterValidSelectedIds(ids.value, criticalComponentOptions.value)
+ criticalComponentDialogVisible.value = false
+ //multipleTableRef.value.clearSelection()
+}
+const filterValidSelectedIds = (selectedIds: any[], options: SelectionOption[]) => {
+ const validIds = new Set(options.map((item) => item.value))
+ return Array.from(
+ new Set(
+ (selectedIds ?? [])
+ .map((id) => normalizeNumberish(id))
+ .filter((id): id is number => id !== undefined && validIds.has(id))
+ )
+ )
+}
+const confirmBeijianDialog = () => {
+ // let ids = bjSelectedRows.value.map(item => item.id);
+ /* const validMap = new Set(beijianOptions.value.map((item) => item.value))
+ const selected = Array.from(new Set(beijianDraft.value.map((v) => Number(v)).filter((v) => validMap.has(v))))*/
+ formData.value.beijianIds = filterValidSelectedIds(bjIds.value, beijianOptions.value)
+ beijianDialogVisible.value = false
+ //multipleTableRef.value.clearSelection()
+}
+
+const bjHandleSelectionChange = (rows: CriticalComponentVO[]) => {
+ bjSelectedIds.value = rows.map((r) => r.id).filter((id): id is number => typeof id === 'number')
+ // 获取当前页所有行的 id
+ const currentPageIds = rows.map(item => item.id)
+
+ // 从已选中的数组中移除当前页的数据
+ bjSelectedRows.value = bjSelectedRows.value.filter(
+ item => !currentPageIds.includes(item.id)
+ )
+ // 添加当前页新选中的数据
+ bjSelectedRows.value.push(...rows)
+}
+
+// 存储当前已选中的行
+const bjCurrentSelectedRows = ref([])
+
+// select 事件:row 是当前操作的行,selected 是操作后的状态
+const bjHandleSelect = (selection, row) => {
+ // 判断是选中还是取消选中
+ const isSelected = selection.includes(row)
+ if (isSelected) {
+ // console.log(`✅ 行被选中: ID=${row.id}, Name=${row.name}`)
+ bjIds.value.push(row.id)
+ } else {
+ bjIds.value = bjIds.value.filter(
+ item => item !== row.id
+ )
+ // console.log(`❌ 行被取消选中: ID=${row.id}, Name=${row.name}`)
}
+ // 更新当前选中状态
+ bjCurrentSelectedRows.value = selection
}
-const formatDetailDate = (value: any) => {
- if (!value) return ''
- return formatDate(new Date(value), 'YYYY-MM-DD')
+
+const bjHandleSelectAll = (selection) => {
+ bjIds.value = selection?.map((row) => row.id).filter((id) => id !== undefined) ?? []
}
-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)}`
- }
- const tryDateFromNumber = (v: any) => {
- const num = Number(v)
- if (!Number.isFinite(num)) return undefined
- const s = String(v).trim()
- const ms = s.length === 10 ? num * 1000 : num
- const d = new Date(ms)
- if (Number.isNaN(d.getTime())) return undefined
- return d
- }
- const tryDateFromString = (v: any) => {
- const s = String(v).trim()
- if (!s) return undefined
- const d = new Date(s)
- if (Number.isNaN(d.getTime())) return undefined
- return d
+
+const getList = async () => {
+ loading.value = true
+ try {
+ const data = await CriticalComponentApi.getCriticalComponentPage(queryParams)
+ list.value = data.list
+ total.value = data.total
+ // 数据加载后,重新设置选中状态
+ nextTick(() => {
+ toggleSelection()
+ })
+ } finally {
+ loading.value = false
}
- const d = typeof raw === 'number' ? tryDateFromNumber(raw) : tryDateFromNumber(raw) ?? tryDateFromString(raw)
- if (d) return formatDate(d, 'YYYY-MM-DD HH:mm:ss')
- return String(raw)
}
-const getResultLabel = (value: any) => {
- const v = value === '' || value === null || value === undefined ? undefined : String(value)
- if (!v) return '-'
- const upper = v.toUpperCase()
- if (v === '0') return '待检测'
- if (v === '1' || upper === 'OK') return '通过'
- if (v === '2' || upper === 'NG') return '不通过'
- return v
+/** 配件查询列表 */
+const bjGetList = async () => {
+ loading.value = true
+ try {
+ bjQueryParams.categoryId = 5
+ const data = await ProductApi.getProductPage(bjQueryParams)
+ bjList.value = data.list
+ bjTotal.value = data.total
+ // 数据加载后,重新设置选中状态
+ nextTick(() => {
+ bjToggleSelection()
+ })
+ } finally {
+ loading.value = false
+ }
}
+// 切换选中状态
+const toggleSelection = () => {
+ if (!multipleTableRef.value || !selectedRows.value.length) return
-const getResultTagType = (value: any) => {
- const v = value === '' || value === null || value === undefined ? undefined : String(value)
- if (!v) return 'info'
- const upper = v.toUpperCase()
- if (v === '1' || upper === 'OK') return 'success'
- if (v === '2' || upper === 'NG') return 'danger'
- if (v === '0') return 'info'
- return 'info'
-}
+ // 遍历当前页的数据
+ list.value.forEach(row => {
+ // 检查这一行是否在已选中数组中
+ const isSelected = selectedRows.value.some(item => item.id === row.id)
-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 deviceImageList = computed(() => parseImages(detailData.value?.images))
-const firstDeviceImage = computed(() => deviceImageList.value[0] ?? '')
-const deviceManagerName = computed(() => (detailData.value as any)?.deviceManagerName ?? detailData.value?.deviceManager ?? '')
-
-type HistoryStepItem = {
- key: string
- name: string
- result: any
- method?: any
- criteria?: any
- images?: string[]
- remark?: any
- taskTime?: any
- createTime?: any
-}
-type HistoryStepGroup = { key: string; time: string; operator: string; items: HistoryStepItem[] }
-
-const buildStepGroups = (
- rows: any[],
- options: { timeField: string; nameFieldCandidates: string[]; resultFieldCandidates: string[] }
-) => {
- const groups = new Map()
- for (const row of rows ?? []) {
- const time = formatHistoryTime(row?.taskTime ?? row?.[options.timeField] ?? row?.createTime)
- const operator = String(row?.operator ?? 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,
- taskTime: row?.taskTime,
- createTime: row?.createTime
- }
- if (!groups.has(groupKey)) {
- groups.set(groupKey, { key: groupKey, time, operator, items: [item] })
+ if (isSelected) {
+ // 如果应该选中,就选中
+ multipleTableRef.value!.toggleRowSelection(row, true)
} else {
- groups.get(groupKey)!.items.push(item)
+ // 否则取消选中
+ multipleTableRef.value!.toggleRowSelection(row, false)
}
- }
- return Array.from(groups.values()).sort((a, b) => String(b.time).localeCompare(String(a.time)))
+ })
}
-const inspectionHistory = ref([])
-const maintainHistory = ref([])
+// 切换选中状态
+const bjToggleSelection = () => {
+ if (!bjMultipleTableRef.value || !bjSelectedRows.value.length) return
-const inspectionStepGroups = computed(() => {
- return buildStepGroups(inspectionHistory.value, {
- timeField: 'inspectionTime',
- nameFieldCandidates: ['inspectionItemName', 'name'],
- resultFieldCandidates: ['inspectionResult']
- })
-})
+ // 遍历当前页的数据
+ bjList.value.forEach(row => {
+ // 检查这一行是否在已选中数组中
+ const isSelected = bjSelectedRows.value.some(item => item.id === row.id)
-const maintainStepGroups = computed(() => {
- return buildStepGroups(maintainHistory.value, {
- timeField: 'inspectionTime',
- nameFieldCandidates: ['maintainItemName', 'inspectionItemName', 'name'],
- resultFieldCandidates: ['maintainResult', 'inspectionResult']
+ if (isSelected) {
+ // 如果应该选中,就选中
+ bjMultipleTableRef.value!.toggleRowSelection(row, true)
+ } else {
+ // 否则取消选中
+ bjMultipleTableRef.value!.toggleRowSelection(row, false)
+ }
})
-})
+}
-type RepairHistoryRow = {
- id?: any
- repairId?: any
- repairCode?: any
- repairName?: any
- subjectId?: any
- subjectCode?: any
- subjectName?: any
- subjectContent?: any
- subjectStandard?: any
- malfunction?: any
- malfunctionUrl?: any
- repairDes?: any
- remark?: any
- createTime?: any
- finishDate?: any
- result?: any
- repairResult?: any
- malfunctionImages?: string[]
-}
-type RepairHistoryGroup = { key: string; name: string; items: RepairHistoryRow[] }
-
-const repairActiveNames = ref([])
-const repairList = ref([])
-
-const repairGroups = computed(() => {
- const groupsMap = new Map()
- for (const row of repairList.value ?? []) {
- const key = String(row.repairCode ?? row.repairId ?? row.subjectName ?? '-')
- if (!groupsMap.has(key)) {
- groupsMap.set(key, {
- key,
- name: String(row.repairName ?? row.repairCode ?? key),
- items: []
- })
+const ids = ref([])
+const bjIds = ref([])
+const openCriticalComponentDialog = () => {
+ criticalComponentDraft.value = [...(formData.value.componentIds ?? [])]
+ criticalComponentDialogVisible.value = true
+ ids.value = [...(formData.value.componentIds ?? [])]
+ setDefaultSelections()
+}
+const openBeijianDialog = () => {
+ beijianDraft.value = [...(formData.value.beijianIds ?? [])]
+ beijianDialogVisible.value = true
+ bjIds.value = [...(formData.value.beijianIds ?? [])]
+ setBJDefaultSelections()
+}
+
+// 设置默认选中的行
+const setDefaultSelections = () => {
+ // 等待DOM更新完成
+ nextTick(() => {
+ if (!multipleTableRef.value) return
+ multipleTableRef.value.clearSelection()
+ const rawSubjectIds = toRaw(formData.value.componentIds)
+ if (rawSubjectIds.length != 0) {
+ let row = {
+ id: undefined
+ }
+ multipleTableRef.value.toggleRowSelection(row, true)
}
- const group = groupsMap.get(key)!
- group.items.push({
- ...row,
- malfunctionImages: parseImages(row?.malfunctionUrl)
+ // 遍历数据,找到需要选中的行
+ list.value.forEach(row => {
+ let id = row.id;
+ if (rawSubjectIds.includes(row.id)) {
+ multipleTableRef.value.toggleRowSelection(row, true)
+ }
})
- }
- const groups = Array.from(groupsMap.values()).filter((g) => g.items.length)
- return groups.sort((a, b) => {
- const at = formatHistoryTime(a.items?.[0]?.finishDate ?? a.items?.[0]?.createTime)
- const bt = formatHistoryTime(b.items?.[0]?.finishDate ?? b.items?.[0]?.createTime)
- return String(bt).localeCompare(String(at))
})
-})
-
-const inspectionExportLoading = ref(false)
-const inspectionDateRange = ref(undefined)
-const maintainExportLoading = ref(false)
-const maintainDateRange = ref(undefined)
-const repairExportLoading = ref(false)
-const repairDateRange = ref(undefined)
-const criticalExportLoading = ref(false)
-const spareExportLoading = ref(false)
+}
-const fetchInspectionHistory = async () => {
- if (!deviceId.value) return
- const params: any = { deviceId: deviceId.value }
- if (inspectionDateRange.value && inspectionDateRange.value.length === 2) {
- params.startTime = inspectionDateRange.value[0]
- params.endTime = inspectionDateRange.value[1]
+// 设置默认选中的行
+const setBJDefaultSelections = () => {
+ // 等待DOM更新完成
+ nextTick(() => {
+ if (!bjMultipleTableRef.value) return
+ bjMultipleTableRef.value.clearSelection()
+ const rawSubjectIds = toRaw(formData.value.beijianIds)
+ if (rawSubjectIds.length != 0) {
+ let row = {
+ id: undefined
+ }
+ bjMultipleTableRef.value.toggleRowSelection(row, true)
+ }
+ // 遍历数据,找到需要选中的行
+ bjList.value.forEach(row => {
+ let id = row.id;
+ if (rawSubjectIds.includes(row.id)) {
+ bjMultipleTableRef.value.toggleRowSelection(row, true)
+ }
+ })
+ })
+}
+const normalizeNumberish = (value: any): number | undefined => {
+ if (value === null || value === undefined || value === '') return undefined
+ if (typeof value === 'number') return Number.isFinite(value) ? value : undefined
+ if (typeof value === 'string') {
+ const trimmed = value.trim()
+ if (!trimmed) return undefined
+ const n = Number(trimmed)
+ return Number.isFinite(n) ? n : undefined
}
- const data = await TicketManagementApi.getInspectionByDeviceId(params)
- inspectionHistory.value = Array.isArray(data) ? data : []
+ return undefined
}
-const handleQueryInspection = async () => {
- await fetchInspectionHistory()
+const normalizeYmd = (value: any): string | undefined => {
+ if (value === null || value === undefined || value === '') return undefined
+ if (typeof value === 'string') {
+ const trimmed = value.trim()
+ const matched = trimmed.match(/^(\d{4}-\d{2}-\d{2})/)
+ if (matched?.[1]) return matched[1]
+ const parsed = Date.parse(trimmed)
+ if (!Number.isNaN(parsed)) return formatDate(new Date(parsed), 'YYYY-MM-DD')
+ return trimmed
+ }
+ if (typeof value === 'number') return formatDate(new Date(value), 'YYYY-MM-DD')
+ if (value instanceof Date) return formatDate(value, 'YYYY-MM-DD')
+ return formatDate(new Date(value), 'YYYY-MM-DD')
}
-const handleResetInspection = async () => {
- inspectionDateRange.value = undefined
- await fetchInspectionHistory()
-}
+const initFormData = () => ({
+ id: undefined,
+ images: undefined,
+ deviceCode: undefined,
+ isCode: true,
+ deviceName: undefined,
+ deviceStatus: undefined,
+ deviceBrand: undefined,
+ deviceModel: undefined,
+ deviceSpec: undefined,
+ isScheduled: 0,
+ ratedCapacity: undefined,
+ deviceType: undefined as number | undefined,
+ deviceLine: undefined as number | undefined,
+ supplier: undefined,
+ workshop: undefined,
+ deviceLocation: undefined,
+ systemOrg: undefined,
+ deviceManagerIds: [] as number[],
+ productionDate: undefined,
+ factoryEntryDate: undefined,
+ remark: undefined,
+ componentIds: [] as number[],
+ beijianIds: [] as number[],
+ fileUrl: '',
+ qrcodeUrl: undefined,
+ templateJson: undefined,
+ sort: undefined,
+ dvId: undefined
+})
-const fetchMaintainHistory = async () => {
- if (!deviceId.value) return
- const params: any = { deviceId: deviceId.value }
- if (maintainDateRange.value && maintainDateRange.value.length === 2) {
- params.startTime = maintainDateRange.value[0]
- params.endTime = maintainDateRange.value[1]
+const formLoading = ref(false)
+const fileUploading = ref(false)
+const formType = ref('update')
+const formRef = ref()
+const formData = ref({
+ ...initFormData()
+})
+const isScheduledEnabled = computed(() => Number(formData.value.isScheduled) === 1)
+const validateDeviceCode = (_rule, value, callback) => {
+ if (Boolean(formData.value.isCode)) {
+ callback()
+ return
+ }
+ if (value === undefined || value === null || String(value).trim() === '') {
+ callback(new Error(t('EquipmentManagement.EquipmentLedger.validatorDeviceCodeRequired')))
+ return
+ }
+ callback()
+}
+const validateScheduledRequired = (label: string) => (_rule, value, callback) => {
+ if (!isScheduledEnabled.value) {
+ callback()
+ return
}
- const data = await TicketManagementApi.getMaintenanceByDeviceId(params)
- maintainHistory.value = Array.isArray(data) ? data : []
+ const normalized = normalizeNumberish(value)
+ if (normalized === undefined) {
+ callback(new Error(String(label)))
+ return
+ }
+ callback()
}
+const formRules = reactive({
+ deviceCode: [{ validator: validateDeviceCode, trigger: ['blur', 'change'] }],
+ deviceName: [{ required: true, message: t('EquipmentManagement.EquipmentLedger.placeholderDeviceName'), trigger: 'blur' }],
+ deviceType: [{ required: true, message: t('EquipmentManagement.EquipmentLedger.placeholderDeviceType'), trigger: 'change' }],
+ ratedCapacity: [{ validator: validateScheduledRequired('ratedCapacity'), trigger: ['blur', 'change'] }]
+})
+const treeSelectProps = { label: 'name', children: 'children' }
+const deviceTypeTree = ref([])
+const users = ref([])
+type SelectionOption = { label: string; value: number }
+const criticalComponentOptions = ref([])
+const beijianOptions = ref([])
+const savedCriticalComponentOptions = ref([])
+const savedBeijianOptions = ref([])
+
+const buildCriticalComponentOptions = (items: any[] = []): SelectionOption[] =>
+ (items ?? [])
+ .map((item: any) => {
+ const id = normalizeNumberish(item?.id)
+ if (id === undefined) return undefined
+ const code = item.code ? String(item.code) : ''
+ const name = item.name ? String(item.name) : ''
+ const label = code && name ? `${code}-${name}` : name || code || String(id)
+ return { label, value: id }
+ })
+ .filter((item): item is SelectionOption => Boolean(item))
+
+const buildBeijianOptions = (items: any[] = []): SelectionOption[] =>
+ (items ?? [])
+ .map((item: any) => {
+ const id = normalizeNumberish(item?.id)
+ if (id === undefined) return undefined
+ const code = item.barCode ? String(item.barCode) : ''
+ const name = item.name ? String(item.name) : ''
+ const label = code && name ? `${code}-${name}` : name || code || String(id)
+ return { label, value: id }
+ })
+ .filter((item): item is SelectionOption => Boolean(item))
+
+const mergeSelectionOptions = (...groups: SelectionOption[][]): SelectionOption[] => {
+ const optionMap = new Map()
+ groups.flat().forEach((item) => optionMap.set(item.value, item))
+ return Array.from(optionMap.values())
+}
+
+const formatSelectedSummary = (ids: number[], options: SelectionOption[]) => {
+ const optionMap = new Map(options.map((item) => [item.value, item.label]))
+ const labels = ids.map((id) => optionMap.get(id)).filter((v): v is string => Boolean(v))
+ if (!labels.length) return ''
+ if (labels.length <= 3) return labels.join(', ')
+ return `${labels.slice(0, 3).join(', ')}...${labels.length}`
+}
+
+const criticalComponentDisplay = computed(() =>
+ formatSelectedSummary(
+ formData.value.componentIds ?? [],
+ mergeSelectionOptions(criticalComponentOptions.value, savedCriticalComponentOptions.value)
+ )
+)
+const beijianDisplay = computed(() =>
+ formatSelectedSummary(formData.value.beijianIds ?? [], mergeSelectionOptions(beijianOptions.value, savedBeijianOptions.value))
+)
+const criticalComponentTableData = computed(() => {
+ const detailList = (detailData.value as any)?.componentList
+ if (Array.isArray(detailList) && detailList.length) return detailList
+
+ const selectedIds = new Set((formData.value.componentIds ?? []).map((id: any) => Number(id)).filter((id: number) => !Number.isNaN(id)))
+ if (!selectedIds.size) return []
+
+ const optionMap = new Map()
+ ;[...criticalComponentOptions.value, ...savedCriticalComponentOptions.value].forEach((item: any) => {
+ optionMap.set(Number(item.value), item)
+ })
-const handleQueryMaintain = async () => {
- await fetchMaintainHistory()
+ return Array.from(selectedIds).map((id) => {
+ const option = optionMap.get(id)
+ const label = option?.label ?? String(id)
+ const [code, ...nameParts] = label.split('-')
+ return {
+ id,
+ code: nameParts.length ? code : '',
+ name: nameParts.length ? nameParts.join('-') : label,
+ description: '',
+ remark: '',
+ createTime: undefined
+ }
+ })
+})
+
+const clearCriticalComponent = () => {
+ formData.value.componentIds = []
+}
+const clearBeijian = () => {
+ formData.value.beijianIds = []
}
-const handleResetMaintain = async () => {
- maintainDateRange.value = undefined
- await fetchMaintainHistory()
+const handleFileUploadingChange = (uploading: boolean) => {
+ fileUploading.value = uploading
}
-const fetchRepairHistory = async () => {
- if (!deviceId.value) return
- const params: any = { deviceId: deviceId.value }
- if (repairDateRange.value && repairDateRange.value.length === 2) {
- params.startTime = repairDateRange.value[0]
- params.endTime = repairDateRange.value[1]
+watch(
+ () => formData.value.isScheduled,
+ () => {
+ formRef.value?.clearValidate?.(['ratedCapacity'])
}
- const data = await DvRepairApi.getRepairListByDeviceId(params)
- repairList.value = Array.isArray(data) ? data : []
-}
+)
-const handleQueryRepair = async () => {
- await fetchRepairHistory()
+const handleCodeAutoChange = (value: boolean) => {
+ if (value) {
+ formData.value.deviceCode = undefined
+ }
+ formRef.value?.clearValidate('deviceCode')
}
-const handleResetRepair = async () => {
- repairDateRange.value = undefined
- await fetchRepairHistory()
+const getQrcodeRefreshUrl = () => {
+ if (!formData.value.id || !formData.value.deviceCode) return ''
+ return `/mes/device-ledger/regenerate-code?id=${formData.value.id}&code=${encodeURIComponent(String(formData.value.deviceCode))}`
}
-const handleExportInspection = async () => {
- if (!deviceId.value) return
- try {
- await message.exportConfirm()
- inspectionExportLoading.value = true
- const params: any = { deviceId: deviceId.value }
- if (inspectionDateRange.value && inspectionDateRange.value.length === 2) {
- params.startTime = inspectionDateRange.value[0]
- params.endTime = inspectionDateRange.value[1]
- }
- const data = await TicketManagementApi.exportInspection(params)
- download.excel(data, '点检履历.xls')
- } catch {
- } finally {
- inspectionExportLoading.value = false
+const buildPrintData = () => {
+ return {
+ id: formData.value.id,
+ deviceCode: formData.value.deviceCode,
+ deviceName: formData.value.deviceName,
+ deviceSpec: formData.value.deviceSpec,
+ deviceBrand: formData.value.deviceBrand,
+ deviceModel: formData.value.deviceModel,
+ deviceLocation: formData.value.deviceLocation,
+ remark: formData.value.remark,
+ qrcodeUrl: formData.value.qrcodeUrl
}
}
-const handleExportMaintain = async () => {
- if (!deviceId.value) return
- try {
- await message.exportConfirm()
- maintainExportLoading.value = true
- const params: any = { deviceId: deviceId.value }
- if (maintainDateRange.value && maintainDateRange.value.length === 2) {
- params.startTime = maintainDateRange.value[0]
- params.endTime = maintainDateRange.value[1]
- }
- const data = await TicketManagementApi.exportMaintenance(params)
- download.excel(data, '保养履历.xls')
- } catch {
- } finally {
- maintainExportLoading.value = false
+const handleQrcodeRefreshSuccess = async (data: any) => {
+ if (!formData.value.id) return
+ if (data?.qrcodeUrl) {
+ formData.value.qrcodeUrl = data.qrcodeUrl
+ return
}
-}
-
-const handleExportRepair = async () => {
- if (!deviceId.value) return
- try {
- await message.exportConfirm()
- repairExportLoading.value = true
- const params: any = { deviceId: deviceId.value }
- if (repairDateRange.value && repairDateRange.value.length === 2) {
- params.startTime = repairDateRange.value[0]
- params.endTime = repairDateRange.value[1]
- }
- const data = await DvRepairApi.exportRepairExcel(params)
- download.excel(data, '维修履历.xls')
- } catch {
- } finally {
- repairExportLoading.value = false
+ const detail = await DeviceLedgerApi.getDeviceLedger(formData.value.id)
+ formData.value.qrcodeUrl = detail?.qrcodeUrl
+ formData.value.deviceCode = detail?.deviceCode ?? formData.value.deviceCode
+}
+
+const ensureOptionsLoaded = async () => {
+ const [deviceTypeRes, userRes, criticalRes, beijianRes] = await Promise.all([
+ DeviceTypeApi.getDeviceTypeTree({ pageNo: 1, pageSize: 10 }),
+ getSimpleUserList(),
+ CriticalComponentApi.getCriticalComponentList(),
+ ProductApi.getComponentSimpleList()
+ ])
+ deviceTypeTree.value = deviceTypeRes ?? []
+ users.value = userRes ?? []
+ criticalComponentOptions.value = buildCriticalComponentOptions(criticalRes ?? [])
+ beijianOptions.value = buildBeijianOptions(beijianRes ?? [])
+}
+
+const bindFormData = (detail: DeviceLedgerVO) => {
+ const templateJson = (detail as any)?.templateJson
+ const parsedTemplateJson =
+ typeof templateJson === 'string'
+ ? (() => {
+ try {
+ return JSON.parse(templateJson)
+ } catch {
+ return undefined
+ }
+ })()
+ : templateJson
+ formData.value = {
+ ...initFormData(),
+ ...(detail as any),
+ templateJson: parsedTemplateJson,
+ isCode: (detail as any)?.isCode ?? false,
+ isScheduled: normalizeNumberish((detail as any)?.isScheduled) ?? 0,
+ ratedCapacity: normalizeNumberish((detail as any)?.ratedCapacity),
+ deviceType: normalizeNumberish((detail as any)?.deviceType),
+ deviceLine: normalizeNumberish((detail as any)?.deviceLine),
+ deviceManagerIds: parseIdsValue((detail as any)?.deviceManager),
+ productionDate: normalizeYmd((detail as any)?.productionDate),
+ factoryEntryDate: normalizeYmd((detail as any)?.factoryEntryDate),
+ componentIds: parseIdsValue((detail as any)?.componentId),
+ beijianIds: parseIdsValue((detail as any)?.beijianId),
+ qrcodeUrl: (detail as any)?.qrcodeUrl
}
+ savedCriticalComponentOptions.value = buildCriticalComponentOptions((detail as any)?.componentList ?? [])
+ savedBeijianOptions.value = buildBeijianOptions((detail as any)?.beijianList ?? [])
}
+const criticalExportLoading = ref(false)
const handleExportCriticalComponent = async () => {
if (!deviceId.value) return
try {
await message.exportConfirm()
criticalExportLoading.value = true
const data = await CriticalComponentApi.exportDeviceComponent({ id: deviceId.value })
- download.excel(data, '关键件.xls')
+ download.excel(data, 'critical-component.xls')
} catch {
} finally {
criticalExportLoading.value = false
}
}
-const handleExportSpareBased = async () => {
- if (!deviceId.value) return
- try {
- await message.exportConfirm()
- spareExportLoading.value = true
- const data = await DeviceLedgerApi.exportSpareBased({ id: deviceId.value })
- download.excel(data, '备件.xls')
- } catch {
- } finally {
- spareExportLoading.value = false
- }
-}
-
-const getTypeTreeForNameMap = async () => {
- const data = await DeviceTypeApi.getDeviceTypeTree({ pageNo: 1, pageSize: 10 })
- const treeChildren = JSON.parse(JSON.stringify(data ?? []))
- buildDeviceTypeNameMap(treeChildren)
-}
const getDetail = async () => {
if (!deviceId.value) {
@@ -678,27 +941,27 @@ const getDetail = async () => {
}
detailLoading.value = true
try {
- detailData.value = await DeviceLedgerApi.getDeviceLedger(deviceId.value)
- await fetchInspectionHistory()
- await fetchMaintainHistory()
- await fetchRepairHistory()
- const keys = repairGroups.value.map((g) => g.key)
- repairActiveNames.value = keys.length ? [keys[0]] : []
+ const detail = await DeviceLedgerApi.getDeviceLedger(deviceId.value)
+ detailData.value = detail
+ bindFormData(detail)
} finally {
detailLoading.value = false
}
}
onMounted(async () => {
- await getTypeTreeForNameMap()
- await getDetail()
+ await ensureOptionsLoaded()
+ // await getDetail()
+ getList()
+
+ bjGetList()
})
-.device-ledger-history-image-error {
- display: flex;
- width: 100%;
- height: 100%;
- font-size: 12px;
- color: var(--el-text-color-secondary);
- background: var(--el-fill-color);
- align-items: center;
- justify-content: center;
-}
-.device-ledger-repair-collapse {
- padding: 8px 8px 0;
-}
-.device-ledger-repair-title {
- display: flex;
- align-items: center;
- justify-content: space-between;
- width: 100%;
-}
-.device-ledger-repair-name {
- font-weight: 600;
- color: var(--el-text-color-primary);
-}
-.device-ledger-repair-meta {
- font-size: 12px;
- color: var(--el-text-color-secondary);
-}
-.device-ledger-history-item-text {
- color: var(--el-text-color-regular);
-}
-
From 2534340dda0583b3ab6558a75f6716f7ece7cfeb Mon Sep 17 00:00:00 2001
From: liutao <790864623@qq.com>
Date: Thu, 28 May 2026 17:34:45 +0800
Subject: [PATCH 05/18] update
---
.../mes/deviceledger/detail/editIndex.vue | 92 ++++++++++++++-----
1 file changed, 70 insertions(+), 22 deletions(-)
diff --git a/src/views/mes/deviceledger/detail/editIndex.vue b/src/views/mes/deviceledger/detail/editIndex.vue
index 30acd00b..926713b1 100644
--- a/src/views/mes/deviceledger/detail/editIndex.vue
+++ b/src/views/mes/deviceledger/detail/editIndex.vue
@@ -618,28 +618,6 @@ const setDefaultSelections = () => {
})
}
-// 设置默认选中的行
-const setBJDefaultSelections = () => {
- // 等待DOM更新完成
- nextTick(() => {
- if (!bjMultipleTableRef.value) return
- bjMultipleTableRef.value.clearSelection()
- const rawSubjectIds = toRaw(formData.value.beijianIds)
- if (rawSubjectIds.length != 0) {
- let row = {
- id: undefined
- }
- bjMultipleTableRef.value.toggleRowSelection(row, true)
- }
- // 遍历数据,找到需要选中的行
- bjList.value.forEach(row => {
- let id = row.id;
- if (rawSubjectIds.includes(row.id)) {
- bjMultipleTableRef.value.toggleRowSelection(row, true)
- }
- })
- })
-}
const normalizeNumberish = (value: any): number | undefined => {
if (value === null || value === undefined || value === '') return undefined
if (typeof value === 'number') return Number.isFinite(value) ? value : undefined
@@ -949,8 +927,78 @@ const getDetail = async () => {
}
}
+
+// 方法1:直接监听 data
+watch(bjList, (newData, oldData) => {
+ // 可以在这里执行相关操作
+ if (newData.length > 0) {
+ // 数据加载完成后的操作
+ setBJDefaultSelections()
+ }
+}, { deep: true })
+
+
+//const defaultSelectedIds = [144, 143,141]
+
+// 设置默认选中的行
+const setBJDefaultSelections = () => {
+ // 等待DOM更新完成
+ nextTick(() => {
+ if (!bjMultipleTableRef.value) return
+ bjMultipleTableRef.value.clearSelection()
+ const rawSubjectIds = toRaw(formData.value.beijianIds)
+ if (rawSubjectIds.length != 0) {
+ let row = {
+ id: undefined
+ }
+ bjMultipleTableRef.value.toggleRowSelection(row, true)
+ }
+ // 遍历数据,找到需要选中的行
+ bjList.value.forEach(row => {
+ let id = row.id;
+ if (rawSubjectIds.includes(row.id)) {
+ bjMultipleTableRef.value.toggleRowSelection(row, true)
+ }
+ })
+ })
+}
+async function initForm() {
+ // 修改时,设置数据
+ if (deviceId.value) {
+ formLoading.value = true
+ try {
+ const detail = await DeviceLedgerApi.getDeviceLedger(deviceId.value)
+ const templateJson = (detail as any)?.templateJson
+ const parsedTemplateJson = typeof templateJson === 'string'
+ ? JSON.parse(templateJson)
+ : templateJson
+ formData.value = {
+ ...initFormData(),
+ ...(detail as any),
+ templateJson: parsedTemplateJson,
+ isCode: (detail as any)?.isCode ?? false,
+ isScheduled: normalizeNumberish((detail as any)?.isScheduled ?? (detail as any)?.isScheduled) ?? 0,
+ ratedCapacity: normalizeNumberish((detail as any)?.ratedCapacity),
+ deviceType: normalizeNumberish((detail as any)?.deviceType),
+ deviceLine: normalizeNumberish((detail as any)?.deviceLine),
+ deviceManagerIds: parseIdsValue((detail as any)?.deviceManager),
+ productionDate: normalizeYmd((detail as any)?.productionDate),
+ factoryEntryDate: normalizeYmd((detail as any)?.factoryEntryDate),
+ componentIds: parseIdsValue((detail as any)?.componentId),
+ beijianIds: parseIdsValue((detail as any)?.beijianId),
+ qrcodeUrl: (detail as any)?.qrcodeUrl,
+ }
+ savedCriticalComponentOptions.value = buildCriticalComponentOptions((detail as any)?.componentList ?? [])
+ savedBeijianOptions.value = buildBeijianOptions((detail as any)?.beijianList ?? [])
+ } finally {
+ formLoading.value = false
+ }
+ }
+}
+
onMounted(async () => {
await ensureOptionsLoaded()
+ initForm()
// await getDetail()
getList()
From 5c81e130b0efe1e2baf9a2f50e8fab40a445b5bd Mon Sep 17 00:00:00 2001
From: liutao <790864623@qq.com>
Date: Fri, 29 May 2026 08:22:34 +0800
Subject: [PATCH 06/18] update
---
.../mes/deviceledger/detail/editIndex.vue | 199 +++++++++++++-----
1 file changed, 147 insertions(+), 52 deletions(-)
diff --git a/src/views/mes/deviceledger/detail/editIndex.vue b/src/views/mes/deviceledger/detail/editIndex.vue
index 926713b1..6bfb0854 100644
--- a/src/views/mes/deviceledger/detail/editIndex.vue
+++ b/src/views/mes/deviceledger/detail/editIndex.vue
@@ -156,10 +156,7 @@
-
+
@@ -177,11 +174,20 @@
{{ t('action.export') }}
-
+
-
+
+
+
+
+
@@ -189,7 +195,11 @@
-
+
+
+
+ {{ t('common.cancel') }}
+ {{ t('common.save') }}
-
+
{
@@ -404,36 +424,32 @@ const bjResetQuery = () => {
const handleSelectionChange = (rows: CriticalComponentVO[]) => {
selectedIds.value = rows.map((r) => r.id).filter((id): id is number => typeof id === 'number')
- // 获取当前页所有行的 id
+ // 获取当前页所有行�?id
const currentPageIds = rows.map(item => item.id)
// 从已选中的数组中移除当前页的数据
selectedRows.value = selectedRows.value.filter(
item => !currentPageIds.includes(item.id)
)
- // 添加当前页新选中的数据
- selectedRows.value.push(...rows)
+ // 添加当前页新选中的数�? selectedRows.value.push(...rows)
}
// 存储当前已选中的行
-const currentSelectedRows = ref([])
-// select 事件:row 是当前操作的行,selected 是操作后的状态
-const handleSelect = (selection, row) => {
+const handleSelect = (selection: any[], row: any) => {
// 判断是选中还是取消选中
const isSelected = selection.includes(row)
if (isSelected) {
- // console.log(`✅ 行被选中: ID=${row.id}, Name=${row.name}`)
+ // console.log(`�?行被选中: ID=${row.id}, Name=${row.name}`)
ids.value.push(row.id)
} else {
ids.value = ids.value.filter(
item => item !== row.id
)
- // console.log(`❌ 行被取消选中: ID=${row.id}, Name=${row.name}`)
+ // console.log(`�?行被取消选中: ID=${row.id}, Name=${row.name}`)
}
- // 更新当前选中状态
- currentSelectedRows.value = selection
+ // 更新当前选中状�? currentSelectedRows.value = selection
}
@@ -451,6 +467,7 @@ const confirmCriticalComponentDialog = () => {
//const selected = Array.from(new Set(criticalComponentDraft.value.map((v) => Number(v)).filter((v) => validMap.has(v))))
formData.value.componentIds = filterValidSelectedIds(ids.value, criticalComponentOptions.value)
criticalComponentDialogVisible.value = false
+ syncCriticalComponentRows()
//multipleTableRef.value.clearSelection()
}
const filterValidSelectedIds = (selectedIds: any[], options: SelectionOption[]) => {
@@ -474,35 +491,31 @@ const confirmBeijianDialog = () => {
const bjHandleSelectionChange = (rows: CriticalComponentVO[]) => {
bjSelectedIds.value = rows.map((r) => r.id).filter((id): id is number => typeof id === 'number')
- // 获取当前页所有行的 id
+ // 获取当前页所有行�?id
const currentPageIds = rows.map(item => item.id)
// 从已选中的数组中移除当前页的数据
bjSelectedRows.value = bjSelectedRows.value.filter(
item => !currentPageIds.includes(item.id)
)
- // 添加当前页新选中的数据
- bjSelectedRows.value.push(...rows)
+ // 添加当前页新选中的数�? bjSelectedRows.value.push(...rows)
}
// 存储当前已选中的行
-const bjCurrentSelectedRows = ref([])
-// select 事件:row 是当前操作的行,selected 是操作后的状态
-const bjHandleSelect = (selection, row) => {
+const bjHandleSelect = (selection: any[], row: any) => {
// 判断是选中还是取消选中
const isSelected = selection.includes(row)
if (isSelected) {
- // console.log(`✅ 行被选中: ID=${row.id}, Name=${row.name}`)
+ // console.log(`�?行被选中: ID=${row.id}, Name=${row.name}`)
bjIds.value.push(row.id)
} else {
bjIds.value = bjIds.value.filter(
item => item !== row.id
)
- // console.log(`❌ 行被取消选中: ID=${row.id}, Name=${row.name}`)
+ // console.log(`�?行被取消选中: ID=${row.id}, Name=${row.name}`)
}
- // 更新当前选中状态
- bjCurrentSelectedRows.value = selection
+ // 更新当前选中状�? bjCurrentSelectedRows.value = selection
}
@@ -517,7 +530,6 @@ const getList = async () => {
const data = await CriticalComponentApi.getCriticalComponentPage(queryParams)
list.value = data.list
total.value = data.total
- // 数据加载后,重新设置选中状态
nextTick(() => {
toggleSelection()
})
@@ -534,7 +546,6 @@ const bjGetList = async () => {
const data = await ProductApi.getProductPage(bjQueryParams)
bjList.value = data.list
bjTotal.value = data.total
- // 数据加载后,重新设置选中状态
nextTick(() => {
bjToggleSelection()
})
@@ -542,13 +553,11 @@ const bjGetList = async () => {
loading.value = false
}
}
-// 切换选中状态
const toggleSelection = () => {
if (!multipleTableRef.value || !selectedRows.value.length) return
// 遍历当前页的数据
list.value.forEach(row => {
- // 检查这一行是否在已选中数组中
const isSelected = selectedRows.value.some(item => item.id === row.id)
if (isSelected) {
@@ -561,13 +570,11 @@ const toggleSelection = () => {
})
}
-// 切换选中状态
const bjToggleSelection = () => {
if (!bjMultipleTableRef.value || !bjSelectedRows.value.length) return
// 遍历当前页的数据
bjList.value.forEach(row => {
- // 检查这一行是否在已选中数组中
const isSelected = bjSelectedRows.value.some(item => item.id === row.id)
if (isSelected) {
@@ -606,13 +613,12 @@ const setDefaultSelections = () => {
let row = {
id: undefined
}
- multipleTableRef.value.toggleRowSelection(row, true)
+ multipleTableRef.value!.toggleRowSelection(row, true)
}
// 遍历数据,找到需要选中的行
list.value.forEach(row => {
- let id = row.id;
if (rawSubjectIds.includes(row.id)) {
- multipleTableRef.value.toggleRowSelection(row, true)
+ multipleTableRef.value!.toggleRowSelection(row, true)
}
})
})
@@ -721,6 +727,7 @@ const criticalComponentOptions = ref([])
const beijianOptions = ref([])
const savedCriticalComponentOptions = ref([])
const savedBeijianOptions = ref([])
+const editableCriticalComponentRows = ref([])
const buildCriticalComponentOptions = (items: any[] = []): SelectionOption[] =>
(items ?? [])
@@ -769,9 +776,11 @@ const criticalComponentDisplay = computed(() =>
const beijianDisplay = computed(() =>
formatSelectedSummary(formData.value.beijianIds ?? [], mergeSelectionOptions(beijianOptions.value, savedBeijianOptions.value))
)
-const criticalComponentTableData = computed(() => {
+const buildCriticalComponentTableRows = () => {
const detailList = (detailData.value as any)?.componentList
- if (Array.isArray(detailList) && detailList.length) return detailList
+ if (Array.isArray(detailList) && detailList.length) {
+ return detailList.map((item: any) => ({ ...item, count: normalizeNumberish(item?.count) ?? 0 }))
+ }
const selectedIds = new Set((formData.value.componentIds ?? []).map((id: any) => Number(id)).filter((id: number) => !Number.isNaN(id)))
if (!selectedIds.size) return []
@@ -789,12 +798,17 @@ const criticalComponentTableData = computed(() => {
id,
code: nameParts.length ? code : '',
name: nameParts.length ? nameParts.join('-') : label,
+ count: 0,
description: '',
remark: '',
createTime: undefined
}
})
-})
+}
+
+const syncCriticalComponentRows = () => {
+ editableCriticalComponentRows.value = buildCriticalComponentTableRows()
+}
const clearCriticalComponent = () => {
formData.value.componentIds = []
@@ -895,8 +909,65 @@ const bindFormData = (detail: DeviceLedgerVO) => {
savedCriticalComponentOptions.value = buildCriticalComponentOptions((detail as any)?.componentList ?? [])
savedBeijianOptions.value = buildBeijianOptions((detail as any)?.beijianList ?? [])
}
+ syncCriticalComponentRows()
const criticalExportLoading = ref(false)
+
+const normalizeFileUrlAsJsonArrayString = (value: any): string | undefined => {
+ if (value === null || value === undefined || value === '') return undefined
+ if (typeof value === 'string') return value.trim() || undefined
+ if (Array.isArray(value)) return JSON.stringify(value)
+ return JSON.stringify(value)
+}
+
+const buildSubmitData = () => {
+ const componentRows = editableCriticalComponentRows.value.map((row: any) => ({
+ ...row,
+ id: normalizeNumberish(row?.id),
+ count: normalizeNumberish(row?.count) ?? 0
+ })).filter((row: any) => row.id !== undefined)
+ formData.value.componentIds = componentRows.map((row: any) => row.id)
+
+ const data = {
+ ...(formData.value as any),
+ isScheduled: normalizeNumberish((formData.value as any).isScheduled) ?? 0,
+ ratedCapacity: normalizeNumberish((formData.value as any).ratedCapacity),
+ deviceType: normalizeNumberish(formData.value.deviceType),
+ deviceLine: normalizeNumberish((formData.value as any).deviceLine),
+ productionDate: normalizeYmd(formData.value.productionDate),
+ factoryEntryDate: normalizeYmd(formData.value.factoryEntryDate),
+ deviceManager: formData.value.deviceManagerIds?.length ? formData.value.deviceManagerIds.join(',') : undefined,
+ componentId: formData.value.componentIds?.length ? formData.value.componentIds.join(',') : undefined,
+ componentList: componentRows,
+ beijianId: formData.value.beijianIds?.length ? formData.value.beijianIds.join(',') : undefined,
+ fileUrl: normalizeFileUrlAsJsonArrayString((formData.value as any).fileUrl)
+ } as unknown as DeviceLedgerVO
+
+ delete (data as any).deviceManagerIds
+ delete (data as any).componentIds
+ delete (data as any).beijianIds
+ return data
+}
+
+const submitForm = async () => {
+ if (fileUploading.value) {
+ message.warning(t('common.loading'))
+ return
+ }
+ await formRef.value?.validate?.()
+ formLoading.value = true
+ try {
+ await DeviceLedgerApi.updateDeviceLedger(buildSubmitData())
+ message.success(t('common.updateSuccess'))
+ await getDetail()
+ } finally {
+ formLoading.value = false
+ }
+}
+
+const handleCancelEdit = async () => {
+ await getDetail()
+}
const handleExportCriticalComponent = async () => {
if (!deviceId.value) return
try {
@@ -928,11 +999,8 @@ const getDetail = async () => {
}
-// 方法1:直接监听 data
-watch(bjList, (newData, oldData) => {
- // 可以在这里执行相关操作
+watch(bjList, (newData) => {
if (newData.length > 0) {
- // 数据加载完成后的操作
setBJDefaultSelections()
}
}, { deep: true })
@@ -951,13 +1019,12 @@ const setBJDefaultSelections = () => {
let row = {
id: undefined
}
- bjMultipleTableRef.value.toggleRowSelection(row, true)
+ bjMultipleTableRef.value!.toggleRowSelection(row, true)
}
// 遍历数据,找到需要选中的行
bjList.value.forEach(row => {
- let id = row.id;
if (rawSubjectIds.includes(row.id)) {
- bjMultipleTableRef.value.toggleRowSelection(row, true)
+ bjMultipleTableRef.value!.toggleRowSelection(row, true)
}
})
})
@@ -968,6 +1035,7 @@ async function initForm() {
formLoading.value = true
try {
const detail = await DeviceLedgerApi.getDeviceLedger(deviceId.value)
+ detailData.value = detail
const templateJson = (detail as any)?.templateJson
const parsedTemplateJson = typeof templateJson === 'string'
? JSON.parse(templateJson)
@@ -990,6 +1058,7 @@ async function initForm() {
}
savedCriticalComponentOptions.value = buildCriticalComponentOptions((detail as any)?.componentList ?? [])
savedBeijianOptions.value = buildBeijianOptions((detail as any)?.beijianList ?? [])
+ syncCriticalComponentRows()
} finally {
formLoading.value = false
}
@@ -1010,7 +1079,7 @@ onMounted(async () => {
.device-ledger-detail-body {
position: relative;
max-height: 100vh;
- padding-top: 2px;
+ padding: 2px 0 72px;
}
.device-ledger-detail-title {
@@ -1062,6 +1131,22 @@ onMounted(async () => {
text-overflow: ellipsis;
white-space: nowrap;
}
+.device-ledger-action-bar {
+/* position: sticky;
+ bottom: 0;*/
+ position: fixed;
+ right: 24px;
+ bottom: 0;
+ left: 240px;
+ z-index: 10;
+ display: flex;
+ justify-content: flex-end;
+ gap: 12px;
+ padding: 12px 16px;
+ border-top: 1px solid var(--el-border-color-lighter);
+ background: var(--el-bg-color);
+ box-shadow: 0 -4px 12px rgb(0 0 0 / 6%);
+}
@@ -1069,3 +1154,13 @@ onMounted(async () => {
+
+
+
+
+
+
+
+
+
+
From 97d450e8aa30eda5db7e082eac4608e7fb87e537 Mon Sep 17 00:00:00 2001
From: zhongwenkai <3478244299@qq.com>
Date: Fri, 29 May 2026 15:26:53 +0800
Subject: [PATCH 07/18] =?UTF-8?q?style:=20=E4=BF=AE=E6=94=B9=E8=AE=BE?=
=?UTF-8?q?=E5=A4=87=E7=AE=A1=E7=90=86=E4=B8=AD=E8=AE=BE=E5=A4=87=E5=85=B3?=
=?UTF-8?q?=E9=94=AE=E4=BB=B6=E7=9A=84=E6=96=B0=E5=A2=9E/=E7=BC=96?=
=?UTF-8?q?=E8=BE=91=E5=BC=B9=E6=A1=86=E6=A0=B7=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../CriticalComponentForm.vue | 265 ++++++++-----
src/views/mes/criticalComponent/index.vue | 354 ++++++++++--------
2 files changed, 368 insertions(+), 251 deletions(-)
diff --git a/src/views/mes/criticalComponent/CriticalComponentForm.vue b/src/views/mes/criticalComponent/CriticalComponentForm.vue
index e9d7c164..c099d59c 100644
--- a/src/views/mes/criticalComponent/CriticalComponentForm.vue
+++ b/src/views/mes/criticalComponent/CriticalComponentForm.vue
@@ -1,104 +1,107 @@
-
-
+
+
diff --git a/src/views/mes/criticalComponent/index.vue b/src/views/mes/criticalComponent/index.vue
index e311b84d..8b68930e 100644
--- a/src/views/mes/criticalComponent/index.vue
+++ b/src/views/mes/criticalComponent/index.vue
@@ -1,154 +1,204 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
-
-
-
-
-
- {{ t('common.query') }}
-
-
-
- {{ t('common.reset') }}
-
-
-
- {{ t('action.add') }}
-
-
-
- {{ t('EquipmentManagement.EquipmentKeyItems.batchDelete') }}
-
-
-
- {{ t('action.import') }}
-
-
-
- {{ t('action.export') }}
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ showAllFilters ? t('FactoryModeling.FactoryStructure.collapseText') : t('FactoryModeling.FactoryStructure.expandText') }}
+
+
+
+
+
+ {{ t('common.query') }}
+
+
+
+ {{ t('common.reset') }}
+
+
+
+ {{ t('action.add') }}
+
+
+
+ {{ t('EquipmentManagement.EquipmentKeyItems.batchDelete') }}
+
+
+
+ {{ t('action.import') }}
+
+
+
+ {{ t('action.export') }}
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ t('EquipmentManagement.EquipmentKeyItems.edit') }}
-
-
- {{ t('EquipmentManagement.EquipmentKeyItems.delete') }}
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ t('EquipmentManagement.EquipmentKeyItems.edit') }}
+
+
+ {{ t('EquipmentManagement.EquipmentKeyItems.delete') }}
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+@media (max-width: 1199px) {
+ .device-basic-media {
+ justify-content: flex-start;
+ }
+ .device-media-panel {
+ max-width: none;
+ }
+}
+@media (max-width: 767px) {
+ .device-basic-fields :deep(.el-col) {
+ max-width: 100%;
+ flex: 0 0 100%;
+ }
+ .device-code-row :deep(.el-col:first-child) {
+ max-width: 75%;
+ flex: 0 0 75%;
+ }
+
+ .device-code-row :deep(.el-col:last-child) {
+ max-width: 25%;
+ flex: 0 0 25%;
+ }
+}
+
From e7abc6cfc7f126fbcb0dca887ce7a368400c10fe Mon Sep 17 00:00:00 2001
From: zhongwenkai <3478244299@qq.com>
Date: Fri, 29 May 2026 17:38:53 +0800
Subject: [PATCH 11/18] =?UTF-8?q?style:=20=E4=BF=AE=E6=94=B9=E5=A4=87?=
=?UTF-8?q?=E4=BB=B6=E7=AE=A1=E7=90=86=E4=B8=AD=E5=A4=87=E4=BB=B6=E5=85=A5?=
=?UTF-8?q?=E5=BA=93=E7=9A=84=E6=96=B0=E5=A2=9E/=E7=BC=96=E8=BE=91?=
=?UTF-8?q?=E5=BC=B9=E6=A1=86=E6=A0=B7=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/views/erp/component/in/StockInForm.vue | 256 +++++++++++++--------
src/views/erp/component/in/index.vue | 20 +-
2 files changed, 173 insertions(+), 103 deletions(-)
diff --git a/src/views/erp/component/in/StockInForm.vue b/src/views/erp/component/in/StockInForm.vue
index 03cee405..bf4c1cc4 100644
--- a/src/views/erp/component/in/StockInForm.vue
+++ b/src/views/erp/component/in/StockInForm.vue
@@ -1,100 +1,108 @@
-
+
+
diff --git a/src/views/erp/component/in/index.vue b/src/views/erp/component/in/index.vue
index 39a1a982..38bf25e8 100644
--- a/src/views/erp/component/in/index.vue
+++ b/src/views/erp/component/in/index.vue
@@ -1,6 +1,7 @@
-
-
+
+
+
-
+
+
-
-
+
+
+
+
diff --git a/src/views/erp/component/out/index.vue b/src/views/erp/component/out/index.vue
index e2da4546..e89456bb 100644
--- a/src/views/erp/component/out/index.vue
+++ b/src/views/erp/component/out/index.vue
@@ -1,6 +1,7 @@
-
-
+
+
+
+
-
-
+
+
+
+
diff --git a/src/views/erp/stock/out/index.vue b/src/views/erp/stock/out/index.vue
index f11f485c..98fe6a75 100644
--- a/src/views/erp/stock/out/index.vue
+++ b/src/views/erp/stock/out/index.vue
@@ -1,5 +1,7 @@
-
+
+
+
+
-
-
+
+
+
+
diff --git a/src/views/mes/moldget/index.vue b/src/views/mes/moldget/index.vue
index e5ab245b..ad033595 100644
--- a/src/views/mes/moldget/index.vue
+++ b/src/views/mes/moldget/index.vue
@@ -1,6 +1,8 @@
-
+
+
+
+
-
-
+
+
+
+
+
diff --git a/src/views/mes/moldreturn/index.vue b/src/views/mes/moldreturn/index.vue
index 77993fb8..114ad4b2 100644
--- a/src/views/mes/moldreturn/index.vue
+++ b/src/views/mes/moldreturn/index.vue
@@ -1,5 +1,8 @@
-
+
+
+
+
+
-
-
+
+
+
From f82a2485a86ff7408fd239b8372b8c171dc8b548 Mon Sep 17 00:00:00 2001
From: zhongwenkai <3478244299@qq.com>
Date: Mon, 1 Jun 2026 09:20:16 +0800
Subject: [PATCH 17/18] =?UTF-8?q?style:=20=E4=BF=AE=E6=94=B9=E5=9F=BA?=
=?UTF-8?q?=E7=A1=80=E8=AE=BE=E6=96=BD=E4=B8=AD=E7=94=A8=E6=88=B7=E5=8F=8D?=
=?UTF-8?q?=E9=A6=88=E7=9A=84=E6=96=B0=E5=A2=9E/=E7=BC=96=E8=BE=91?=
=?UTF-8?q?=E5=BC=B9=E6=A1=86=E6=A0=B7=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/views/iot/feedback/FeedbackForm.vue | 116 ++++++++++++++++++------
src/views/iot/feedback/index.vue | 18 +++-
2 files changed, 102 insertions(+), 32 deletions(-)
diff --git a/src/views/iot/feedback/FeedbackForm.vue b/src/views/iot/feedback/FeedbackForm.vue
index 6482e582..cd968fe6 100644
--- a/src/views/iot/feedback/FeedbackForm.vue
+++ b/src/views/iot/feedback/FeedbackForm.vue
@@ -1,28 +1,34 @@
-