diff --git a/.env.local b/.env.local index 121499b4..2167ba7a 100644 --- a/.env.local +++ b/.env.local @@ -8,7 +8,8 @@ VITE_DEV=true # 线上环境 # VITE_BASE_URL='https://besure.ngsk.tech:7001' # 本地联调 -VITE_BASE_URL='http://192.168.5.113:48081' +VITE_BASE_URL='http://192.168.5.107:48081' +# VITE_BASE_URL='http://192.168.5.135:48081' # 文件上传类型:server - 后端上传, client - 前端直连上传,仅支持 S3 服务 diff --git a/src/api/iot/recipeConfig/index.ts b/src/api/iot/recipeConfig/index.ts index 90e6a386..53034c1e 100644 --- a/src/api/iot/recipeConfig/index.ts +++ b/src/api/iot/recipeConfig/index.ts @@ -177,6 +177,10 @@ export const RecipeConfigApi = { return await request.get({ url: `/iot/recipe-device-attribute/page`, params }) }, + updateRecipeDeviceAttribute: async (data: { recipeId: string | number; ids: number[] }) => { + return await request.put({ url: `/iot/recipe-device-attribute/update`, data }) + }, + saveRecipePointConfig: async (data: { recipeId: string | number; attributeIds: number[] }) => { ensureMockSeeded() await sleep(120) diff --git a/src/api/mes/deviceledger/index.ts b/src/api/mes/deviceledger/index.ts index f62231ae..aa625753 100644 --- a/src/api/mes/deviceledger/index.ts +++ b/src/api/mes/deviceledger/index.ts @@ -17,9 +17,8 @@ export interface DeviceLedgerVO { deviceLocation: string // 设备位置 useDept?: string // 使用部门 deviceManager: string // 设备负责人 - quantity?: number // 数量 - productionDate: Date // 设备生产日期 - factoryEntryDate: Date // 设备入厂日期 + productionDate: string | number | Date // 设备生产日期 + factoryEntryDate: string | number | Date // 设备入厂日期 deviceRemark: string // 设备备注 remark: string // 备注 creator?: string // 创建人 @@ -51,8 +50,8 @@ export const DeviceLedgerApi = { }, // 删除设备类型 - deleteDeviceLedger: async (id: number) => { - return await request.delete({ url: `/mes/device-ledger/delete?id=` + id }) + deleteDeviceLedger: async (ids: string) => { + return await request.delete({ url: `/mes/device-ledger/delete?ids=` + ids }) }, // 导出设备类型 Excel diff --git a/src/api/mes/dvsubject/index.ts b/src/api/mes/dvsubject/index.ts index f6e4bff8..02b9ac41 100644 --- a/src/api/mes/dvsubject/index.ts +++ b/src/api/mes/dvsubject/index.ts @@ -1,45 +1,50 @@ -import request from '@/config/axios' - -// 维保项目 VO -export interface DvSubjectVO { - id: number // ID - subjectCode: string // 项目编码 - subjectName: string // 项目名称 - subjectType: string // 项目类型 - subjectContent: string // 项目内容 - subjectStandard: string // 标准 - isEnable: boolean // 是否启用 -} - -// 维保项目 API -export const DvSubjectApi = { - // 查询维保项目分页 - getDvSubjectPage: async (params: any) => { - return await request.get({ url: `/mes/dv-subject/page`, params }) - }, - - // 查询维保项目详情 - getDvSubject: async (id: number) => { - return await request.get({ url: `/mes/dv-subject/get?id=` + id }) - }, - - // 新增维保项目 - createDvSubject: async (data: DvSubjectVO) => { - return await request.post({ url: `/mes/dv-subject/create`, data }) - }, - - // 修改维保项目 - updateDvSubject: async (data: DvSubjectVO) => { - return await request.put({ url: `/mes/dv-subject/update`, data }) - }, - - // 删除维保项目 - deleteDvSubject: async (id: number) => { - return await request.delete({ url: `/mes/dv-subject/delete?id=` + id }) - }, - - // 导出维保项目 Excel - exportDvSubject: async (params) => { - return await request.download({ url: `/mes/dv-subject/export-excel`, params }) - }, -} \ No newline at end of file +import request from '@/config/axios' + +// 维保项目 VO +export interface DvSubjectVO { + id?: number // ID + subjectCode: string // 项目编码 + subjectName: string // 项目名称 + subjectType?: string // 项目类型 + subjectContent?: string // 项目内容 + subjectStandard?: string // 标准 + isEnable: string // 是否启用 + inspectionMethod: string // 检验方式 + valueType: string // 值类型 + judgmentCriteria: string // 判定基准 + creator?: string // 创建人 + createTime?: string | number | Date // 创建时间 +} + +// 维保项目 API +export const DvSubjectApi = { + // 查询维保项目分页 + getDvSubjectPage: async (params: any) => { + return await request.get({ url: `/mes/dv-subject/page`, params }) + }, + + // 查询维保项目详情 + getDvSubject: async (id: number) => { + return await request.get({ url: `/mes/dv-subject/get?id=` + id }) + }, + + // 新增维保项目 + createDvSubject: async (data: DvSubjectVO) => { + return await request.post({ url: `/mes/dv-subject/create`, data }) + }, + + // 修改维保项目 + updateDvSubject: async (data: DvSubjectVO) => { + return await request.put({ url: `/mes/dv-subject/update`, data }) + }, + + // 删除维保项目 + deleteDvSubject: async (ids: string) => { + return await request.delete({ url: `/mes/dv-subject/delete?ids=` + ids }) + }, + + // 导出维保项目 Excel + exportDvSubject: async (params) => { + return await request.download({ url: `/mes/dv-subject/export-excel`, params }) + }, +} diff --git a/src/api/mes/planmaintenance/index.ts b/src/api/mes/planmaintenance/index.ts new file mode 100644 index 00000000..a2a875ad --- /dev/null +++ b/src/api/mes/planmaintenance/index.ts @@ -0,0 +1,47 @@ +import request from '@/config/axios' + +export interface PlanMaintenanceVO { + id?: number | string + planName: string + planType: number | string + description?: string + subjectIdS?: string + creator?: string + creatorName?: string + createTime?: string | number | Date + updateTime?: string | number | Date +} + +export interface PlanMaintenanceSubjectVO { + id?: number | string + subjectCode?: string + subjectName?: string + inspectionMethod?: string + judgmentCriteria?: string +} + +export const PlanMaintenanceApi = { + getPlanMaintenancePage: async (params: any) => { + return await request.get({ url: `/mes/plan-maintenance/page`, params }) + }, + + getSubjectList: async (id: number | string) => { + return await request.get({ url: `/mes/plan-maintenance/getSubjectList`, params: { id } }) + }, + + createPlanMaintenance: async (data: any) => { + return await request.post({ url: `/mes/plan-maintenance/create`, data }) + }, + + updatePlanMaintenance: async (data: any) => { + return await request.put({ url: `/mes/plan-maintenance/update`, params: data }) + }, + + deletePlanMaintenance: async (ids: string) => { + return await request.delete({ url: `/mes/plan-maintenance/delete?ids=` + ids }) + }, + + exportPlanMaintenance: async (params: any) => { + return await request.download({ url: `/mes/plan-maintenance/export-excel`, params }) + } +} diff --git a/src/api/mes/taskManagement/index.ts b/src/api/mes/taskManagement/index.ts new file mode 100644 index 00000000..cad0b3f7 --- /dev/null +++ b/src/api/mes/taskManagement/index.ts @@ -0,0 +1,44 @@ +import request from '@/config/axios' + +export interface TaskManagementVO { + id?: number + name?: string + taskType?: number + deviceList?: string + projectForm?: string + startDate?: string + endDate?: string + cronExpression?: string + operableUsers?: string + enabled?: boolean + execFrequency?: string + frequencyValue?: string + time?: string + validMinutes?: number + creator?: string + createTime?: string + updateTime?: string +} + +export const TaskManagementApi = { + getTaskManagementPage: async (params: any) => { + return await request.get({ url: `/mes/task-management/page`, params }) + }, + + createTaskManagement: async (data: TaskManagementVO) => { + return await request.post({ url: `/mes/task-management/create`, data }) + }, + + updateTaskManagement: async (data: TaskManagementVO) => { + return await request.put({ url: `/mes/task-management/update`, data }) + }, + + deleteTaskManagement: async (ids: string) => { + return await request.delete({ url: `/mes/task-management/delete?ids=` + ids }) + }, + + exportTaskManagement: async (params: any) => { + return await request.download({ url: `/mes/task-management/export-excel`, params }) + } +} + diff --git a/src/views/formula/formulaConfig/index.vue b/src/views/formula/formulaConfig/index.vue index f63a98fd..4fbb86ad 100644 --- a/src/views/formula/formulaConfig/index.vue +++ b/src/views/formula/formulaConfig/index.vue @@ -21,6 +21,9 @@ v-model="queryParams.productName" placeholder="请输入产品名称" clearable 查询 + + 重置 + 新增 @@ -49,7 +52,7 @@ ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-to 配置 - 编辑 + 编辑 删除 @@ -60,15 +63,9 @@ ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-to +ref="detailRef" :visible="detailVisible" + :recipe-id="detailMeta.id ? String(detailMeta.id) : undefined" :manual-recipe-id="detailMeta.id" + :recipe-code="detailMeta.recipeCode" :name="detailMeta.name" @config="handleDetailConfig" @close="closeDetail" /> @@ -111,9 +108,59 @@ v-model="dialogForm.machineName" placeholder="请选择关联设备" clearable f - + + + + 来源 + {{ filteredSourceItems.length }} + + + + + + + + + + + + + >> + + + << + + + + + + 目标 + {{ filteredTargetItems.length }} + + + + + + + + + + 取 消 @@ -138,6 +185,7 @@ const message = useMessage() const { t } = useI18n() const loading = ref(false) +const queryFormRef = ref() const queryParams = reactive({ pageNo: 1, pageSize: 10, @@ -184,6 +232,11 @@ const handleQuery = () => { getList() } +const resetQuery = () => { + queryFormRef.value?.resetFields?.() + handleQuery() +} + const handlePagination = () => { getList() } @@ -342,19 +395,23 @@ const detailVisible = ref(false) const detailMeta = reactive({ id: undefined as number | undefined, recipeCode: '', - name: '' + name: '', + deviceId: undefined as number | undefined, + machineName: '' }) const openDetail = async (row: RecipeConfigVO) => { detailMeta.id = row.id detailMeta.recipeCode = row.recipeCode detailMeta.name = row.name ?? row.recipeName ?? '' + detailMeta.deviceId = row.deviceId + detailMeta.machineName = row.machineName ?? row.deviceName ?? '' detailVisible.value = true } const handleDetailConfig = () => { - if (!detailMeta.recipeCode) return - openConfigDialog(detailMeta.recipeCode) + if (!detailMeta.id) return + openConfigDialog(detailMeta.id) } const handleRowClick = async (row: RecipeConfigVO, column: any) => { @@ -374,34 +431,136 @@ type TransferItem = { key: number; label: string; disabled?: boolean } const configVisible = ref(false) const configLoading = ref(false) -const configRecipeId = ref(undefined) +const configRecipeId = ref(undefined) const configCandidates = ref([]) const configSelectedKeys = ref([]) +const configSelectedItems = ref([]) + +const sourceKeyword = ref('') +const targetKeyword = ref('') +const sourceCheckedKeys = ref([]) +const targetCheckedKeys = ref([]) + +const configDeviceLabel = computed(() => { + const name = detailMeta.machineName?.trim() + if (name) return name + if (detailMeta.deviceId !== undefined && detailMeta.deviceId !== null) return String(detailMeta.deviceId) + return '-' +}) + +const normalizeKey = (value: any): number | undefined => { + if (value === null || value === undefined || value === '') return undefined + const n = Number(value) + if (Number.isNaN(n)) return undefined + return n +} + +const selectedKeySet = computed(() => { + return new Set(configSelectedKeys.value ?? []) +}) + +const contains = (text: string, keyword: string) => { + const k = (keyword ?? '').trim().toLowerCase() + if (!k) return true + return (text ?? '').toLowerCase().includes(k) +} + +const filteredSourceItems = computed(() => { + return (configCandidates.value ?? []).filter((it) => contains(it.label, sourceKeyword.value)) +}) + +const filteredTargetItems = computed(() => { + const set = selectedKeySet.value + return (configCandidates.value ?? []) + .filter((it) => set.has(it.key)) + .filter((it) => contains(it.label, targetKeyword.value)) +}) + +const isSourceSelectable = (row: TransferItem) => { + return !selectedKeySet.value.has(row.key) +} + +const getSourceRowClass = ({ row }: { row: TransferItem }) => { + return selectedKeySet.value.has(row.key) ? 'formula-config-row--disabled' : '' +} + +const handleSourceSelectionChange = (rows: TransferItem[]) => { + sourceCheckedKeys.value = (rows ?? []).map((r) => r.key) +} + +const handleTargetSelectionChange = (rows: TransferItem[]) => { + targetCheckedKeys.value = (rows ?? []).map((r) => r.key) +} + +const addToTarget = () => { + const next = new Set(configSelectedKeys.value ?? []) + for (const key of sourceCheckedKeys.value ?? []) next.add(key) + configSelectedKeys.value = Array.from(next.values()) + sourceCheckedKeys.value = [] +} + +const removeFromTarget = () => { + const toRemove = new Set(targetCheckedKeys.value ?? []) + configSelectedKeys.value = (configSelectedKeys.value ?? []).filter((k) => !toRemove.has(k)) + targetCheckedKeys.value = [] +} + +const buildTransferLabel = (item: any) => { + return `${item.attributeName ?? item.pointName ?? ''}${item.attributeType || item.pointType ? '(' + (item.attributeType ?? item.pointType) : ''}${item.dataType ? '/' + item.dataType : ''}${item.dataUnit ? ' ' + item.dataUnit : ''}${item.attributeType || item.pointType ? ')' : ''}` +} + +const loadConfigCandidatesByDevice = async (deviceId: number) => { + const data = await DeviceApi.getDeviceAttributePage({ pageNo: 1, pageSize: 100, deviceId }) + const list = (data?.list ?? data?.data ?? []) as any[] + const deviceItems = (list ?? []) + .map((item: any) => { + const key = normalizeKey(item?.attributeId ?? item?.id) + if (key === undefined) return undefined + return { + key, + label: buildTransferLabel(item) + } as TransferItem + }) + .filter((it: any) => it && typeof it.key === 'number') as TransferItem[] + const merged = new Map() + for (const it of deviceItems) merged.set(it.key, it) + for (const it of configSelectedItems.value) { + if (!merged.has(it.key)) merged.set(it.key, it) + } + configCandidates.value = Array.from(merged.values()) +} -const openConfigDialog = async (recipeCode: string) => { +const openConfigDialog = async (recipeId: number | string) => { configVisible.value = true - configRecipeId.value = recipeCode + configRecipeId.value = recipeId configSelectedKeys.value = [] configCandidates.value = [] + configSelectedItems.value = [] + sourceKeyword.value = '' + targetKeyword.value = '' + sourceCheckedKeys.value = [] + targetCheckedKeys.value = [] configLoading.value = true try { - const [candidateRes, selectedRes] = await Promise.all([ - DeviceApi.getDeviceContactModelPage(), - RecipeConfigApi.getRecipePointDetailPage({ pageNo: 1, pageSize: 100, recipeId: recipeCode }) - ]) - - const candidateList = Array.isArray(candidateRes) - ? candidateRes - : ((candidateRes as any)?.list ?? (candidateRes as any)?.data ?? []) - - configCandidates.value = (candidateList ?? []).map((item: any) => ({ - key: item.id, - label: `${item.attributeName ?? item.pointName ?? ''}${item.attributeType || item.pointType ? '(' + (item.attributeType ?? item.pointType) : ''}${item.dataType ? '/' + item.dataType : ''}${item.dataUnit ? ' ' + item.dataUnit : ''}${item.attributeType || item.pointType ? ')' : ''}` - })) - - configSelectedKeys.value = (selectedRes.list ?? []) + const selectedRes = await RecipeConfigApi.getRecipePointDetailPage({ recipeId, pageNo: 1, pageSize: 100 }) + const selectedList = Array.isArray(selectedRes) ? selectedRes : selectedRes?.list ?? selectedRes?.data ?? [] + const selectedKeys = (selectedList ?? []) .map((item: any) => (item.attributeId !== undefined ? item.attributeId : item.id)) + .map((id: any) => normalizeKey(id)) .filter((id: any) => typeof id === 'number') + configSelectedKeys.value = selectedKeys + configSelectedItems.value = (selectedList ?? []) + .map((item: any) => ({ + key: normalizeKey(item.attributeId !== undefined ? item.attributeId : item.id), + label: buildTransferLabel(item) + })) + .filter((it: any) => typeof it.key === 'number') + const deviceId = detailMeta.deviceId + if (deviceId !== undefined && deviceId !== null) { + await loadConfigCandidatesByDevice(deviceId) + } else { + configCandidates.value = configSelectedItems.value + } } finally { configLoading.value = false } @@ -411,13 +570,10 @@ const submitConfig = async () => { if (!configRecipeId.value) return configLoading.value = true try { - await RecipeConfigApi.saveRecipePointConfig({ - recipeId: configRecipeId.value, - attributeIds: configSelectedKeys.value - }) + await RecipeConfigApi.updateRecipeDeviceAttribute({ recipeId: configRecipeId.value, ids: configSelectedKeys.value }) message.success(t('common.updateSuccess')) configVisible.value = false - if (detailVisible.value && detailMeta.recipeCode === configRecipeId.value) { + if (detailVisible.value && String(detailMeta.id) === String(configRecipeId.value)) { await detailRef.value?.refresh?.() } } finally { @@ -432,20 +588,51 @@ onMounted(() => { diff --git a/src/views/mes/deviceledger/DeviceLedgerForm.vue b/src/views/mes/deviceledger/DeviceLedgerForm.vue index d587ed99..b996dafa 100644 --- a/src/views/mes/deviceledger/DeviceLedgerForm.vue +++ b/src/views/mes/deviceledger/DeviceLedgerForm.vue @@ -57,21 +57,20 @@ - - - - - - + + + + - + - + @@ -104,9 +104,11 @@ - + + + - - - - 选择 - + + + + @@ -140,27 +149,12 @@ - - - - - - - - 选择 - - - - diff --git a/src/views/mes/deviceledger/index.vue b/src/views/mes/deviceledger/index.vue index 7ae38e3d..8968bfa5 100644 --- a/src/views/mes/deviceledger/index.vue +++ b/src/views/mes/deviceledger/index.vue @@ -20,7 +20,7 @@ :model="queryParams" ref="queryFormRef" :inline="true" - label-width="90px" + label-width="60px" > 新增 + + 批量删除 + - + + {{ (queryParams.pageNo - 1) * queryParams.pageSize + scope.$index + 1 }} @@ -101,16 +113,15 @@ - - - - - + + + + - - + + - + @@ -187,7 +198,7 @@ diff --git a/src/views/mes/planMaintenance/PlanMaintenanceForm.vue b/src/views/mes/planMaintenance/PlanMaintenanceForm.vue new file mode 100644 index 00000000..9ef6641f --- /dev/null +++ b/src/views/mes/planMaintenance/PlanMaintenanceForm.vue @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 确 定 + 取 消 + + + + + diff --git a/src/views/mes/planMaintenance/index.vue b/src/views/mes/planMaintenance/index.vue new file mode 100644 index 00000000..67511475 --- /dev/null +++ b/src/views/mes/planMaintenance/index.vue @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + + + 搜索 + 重置 + + 新增 + + + 批量删除 + + + 导出 + + + + + + + + + + + + + {{ s2.$index + 1 }} + + + + + + + - + + {{ getTagLabel('Inspection_method', s2.row.inspectionMethod) }} + + + + + + + + + + + + {{ (queryParams.pageNo - 1) * queryParams.pageSize + scope.$index + 1 }} + + + + + + + {{ getPlanTypeLabel(scope.row.planType) }} + + + + + + + + + + + 编辑 + + + 删除 + + + + + + + + + + + + diff --git a/src/views/mes/producereport/ProduceReportDetailForm.vue b/src/views/mes/producereport/ProduceReportDetailForm.vue index 63cdf38f..c9e7b94e 100644 --- a/src/views/mes/producereport/ProduceReportDetailForm.vue +++ b/src/views/mes/producereport/ProduceReportDetailForm.vue @@ -169,7 +169,7 @@ const dialogVisible = ref(false) // 弹窗的是否展示 const dialogTitle = ref('') // 弹窗的标题 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 const formType = ref('') // 表单的类型:create - 新增;update - 修改 -const formData = ref({ +const formData = ref({ id: undefined, reportId: undefined, planId: undefined, diff --git a/src/views/mes/taskManagement/TaskManagementForm.vue b/src/views/mes/taskManagement/TaskManagementForm.vue new file mode 100644 index 00000000..eec67eba --- /dev/null +++ b/src/views/mes/taskManagement/TaskManagementForm.vue @@ -0,0 +1,159 @@ + + + + + + + + + 点检 + 保养 + + + + + + + + + + + + + + + + + + + + + {{ dict.label }} + + + + + + 确 定 + 取 消 + + + + + + diff --git a/src/views/mes/taskManagement/index.vue b/src/views/mes/taskManagement/index.vue new file mode 100644 index 00000000..1daa508a --- /dev/null +++ b/src/views/mes/taskManagement/index.vue @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + 搜索 + 重置 + + 新增 + + + 导出 + + + + + + + + + + + + + 点检 + 保养 + - + + + + + + + + + + + + + + + + + + + + + 编辑 + + + 删除 + + + + + + + + + + + + +