feat:模具管理-点检保养模块-添加检验项目/检验方案/任务配置/工单查询页面
parent
5a42cca0c7
commit
45d1099458
@ -0,0 +1,151 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible" width="720px">
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
|
||||
<el-form-item label="方案名称" prop="planName" required>
|
||||
<el-input v-model="formData.planName" placeholder="请输入方案名称" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="方案类型" prop="planType" required>
|
||||
<el-select v-model="formData.planType" placeholder="请选择方案类型" class="!w-full">
|
||||
<el-option :value="1" label="保养" />
|
||||
<el-option :value="2" label="维护" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="描述" prop="description">
|
||||
<el-input v-model="formData.description" placeholder="请输入描述" type="textarea" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="关联项目" prop="subjectIds">
|
||||
<el-select
|
||||
v-model="formData.subjectIds"
|
||||
multiple
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择关联项目"
|
||||
class="!w-full"
|
||||
>
|
||||
<el-option v-for="item in subjectOptions" :key="item.id" :label="item.subjectName" :value="item.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
<el-button type="primary" @click="submitForm" :disabled="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { FormRules } from 'element-plus'
|
||||
import { DvSubjectApi, DvSubjectVO } from '@/api/mes/dvsubject'
|
||||
import { PlanMaintenanceApi, PlanMaintenanceVO } from '@/api/mes/planmaintenance'
|
||||
|
||||
defineOptions({ name: 'MoldInspectionPlanForm' })
|
||||
|
||||
const { t } = useI18n()
|
||||
const message = useMessage()
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('')
|
||||
const formLoading = ref(false)
|
||||
const formType = ref<'create' | 'update'>('create')
|
||||
|
||||
const subjectOptions = ref<DvSubjectVO[]>([])
|
||||
const ensureSubjectOptionsLoaded = async () => {
|
||||
if (subjectOptions.value.length) return
|
||||
const res = await DvSubjectApi.getDvSubjectPage({})
|
||||
const list = Array.isArray(res) ? res : res?.list
|
||||
subjectOptions.value = (list ?? []) as DvSubjectVO[]
|
||||
}
|
||||
|
||||
const parseIds = (value: any): Array<number | string> => {
|
||||
if (!value) return []
|
||||
const raw = Array.isArray(value)
|
||||
? value
|
||||
: String(value)
|
||||
.split(',')
|
||||
.map((v) => v.trim())
|
||||
.filter((v) => v !== '')
|
||||
|
||||
return raw
|
||||
.map((v) => {
|
||||
if (typeof v === 'number') return v
|
||||
const s = String(v).trim()
|
||||
if (!s) return undefined
|
||||
const n = Number(s)
|
||||
if (Number.isFinite(n) && String(n) === s) return n
|
||||
return s
|
||||
})
|
||||
.filter((v): v is number | string => v !== undefined)
|
||||
}
|
||||
|
||||
const initFormData = () => ({
|
||||
id: undefined as PlanMaintenanceVO['id'],
|
||||
planName: '' as string,
|
||||
planType: undefined as any,
|
||||
description: '' as string,
|
||||
subjectIds: [] as Array<number | string>
|
||||
})
|
||||
|
||||
const formData = ref(initFormData())
|
||||
const formRules = reactive<FormRules>({
|
||||
planName: [{ required: true, message: '方案名称不能为空', trigger: 'blur' }],
|
||||
planType: [{ required: true, message: '方案类型不能为空', trigger: 'change' }]
|
||||
})
|
||||
const formRef = ref()
|
||||
|
||||
const open = async (type: 'create' | 'update', row?: Partial<PlanMaintenanceVO>) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = t('action.' + type)
|
||||
formType.value = type
|
||||
resetForm()
|
||||
await ensureSubjectOptionsLoaded()
|
||||
|
||||
if (type === 'update' && row) {
|
||||
formData.value = {
|
||||
...initFormData(),
|
||||
id: row.id,
|
||||
planName: (row.planName as any) ?? '',
|
||||
planType: (row.planType as any) ?? undefined,
|
||||
description: (row.description as any) ?? '',
|
||||
subjectIds: parseIds((row as any).subjectIds ?? (row as any).subjectIdS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
const submitForm = async () => {
|
||||
await formRef.value.validate()
|
||||
formLoading.value = true
|
||||
try {
|
||||
const data = {
|
||||
id: formData.value.id,
|
||||
planName: formData.value.planName,
|
||||
planType: formData.value.planType,
|
||||
description: formData.value.description,
|
||||
subjectIdS: formData.value.subjectIds?.length ? formData.value.subjectIds.join(',') : undefined
|
||||
}
|
||||
if (formType.value === 'create') {
|
||||
await PlanMaintenanceApi.createPlanMaintenance(data)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
await PlanMaintenanceApi.updatePlanMaintenance(data)
|
||||
message.success(t('common.updateSuccess'))
|
||||
}
|
||||
dialogVisible.value = false
|
||||
emit('success')
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const resetForm = () => {
|
||||
formData.value = initFormData()
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -0,0 +1,328 @@
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="60px">
|
||||
<el-form-item label="名称" prop="planName">
|
||||
<el-input
|
||||
v-model="queryParams.planName"
|
||||
placeholder="请输入名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="planType">
|
||||
<el-select v-model="queryParams.planType" placeholder="请选择类型" clearable class="!w-240px">
|
||||
<el-option :value="1" label="保养" />
|
||||
<el-option :value="2" label="维护" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="描述" prop="description">
|
||||
<el-input
|
||||
v-model="queryParams.description"
|
||||
placeholder="请输入描述"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
|
||||
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
|
||||
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['mes:plan-maintenance:create']">
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||
</el-button>
|
||||
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['mes:plan-maintenance:delete']">
|
||||
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
@click="handleExport"
|
||||
:loading="exportLoading"
|
||||
v-hasPermi="['mes:plan-maintenance:export']"
|
||||
>
|
||||
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
row-key="id"
|
||||
:stripe="true"
|
||||
:show-overflow-tooltip="true"
|
||||
@expand-change="handleExpandChange"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
|
||||
<el-table-column type="expand" width="48">
|
||||
<template #default="scope">
|
||||
<div class="p-12px">
|
||||
<el-table
|
||||
v-loading="subjectLoadingMap[String(scope.row.id)]"
|
||||
:data="subjectListMap[String(scope.row.id)] ?? []"
|
||||
:stripe="true"
|
||||
:show-overflow-tooltip="true"
|
||||
size="small"
|
||||
>
|
||||
<el-table-column label="序号" align="center" width="80">
|
||||
<template #default="s2">
|
||||
{{ s2.$index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="编码" align="center" prop="subjectCode" />
|
||||
<el-table-column label="名称" align="center" prop="subjectName" />
|
||||
<el-table-column label="检验方式" align="center" prop="inspectionMethod" width="120">
|
||||
<template #default="s2">
|
||||
<span v-if="s2.row.inspectionMethod === undefined || s2.row.inspectionMethod === null || s2.row.inspectionMethod === ''">-</span>
|
||||
<el-tag
|
||||
v-else
|
||||
effect="light"
|
||||
:type="getTagType('Inspection_method', s2.row.inspectionMethod)"
|
||||
:color="getTagColor('Inspection_method', s2.row.inspectionMethod)"
|
||||
:style="getTagStyle('Inspection_method', s2.row.inspectionMethod)"
|
||||
disable-transitions
|
||||
>
|
||||
{{ getTagLabel('Inspection_method', s2.row.inspectionMethod) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="判定基准" align="center" prop="judgmentCriteria" />
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="序号" align="center" width="80">
|
||||
<template #default="scope">
|
||||
{{ (queryParams.pageNo - 1) * queryParams.pageSize + scope.$index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="名称" align="center" prop="planName" min-width="160" />
|
||||
<el-table-column label="类型" align="center" prop="planType" width="110">
|
||||
<template #default="scope">
|
||||
<el-tag effect="light" :type="getPlanTypeTagType(scope.row.planType)">
|
||||
{{ getPlanTypeLabel(scope.row.planType) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="描述" align="center" prop="description" min-width="220" />
|
||||
<el-table-column label="创建人" align="center" prop="creatorName" width="140" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
|
||||
<el-table-column label="更新时间" align="center" prop="updateTime" :formatter="dateFormatter" width="180" />
|
||||
<el-table-column label="操作" align="center" fixed="right" width="160">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="openForm('update', scope.row)" v-hasPermi="['mes:plan-maintenance:update']">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:plan-maintenance:delete']">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</ContentWrap>
|
||||
|
||||
<InspectionPlanForm ref="formRef" @success="getList" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getStrDictOptions } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import download from '@/utils/download'
|
||||
import { PlanMaintenanceApi, PlanMaintenanceSubjectVO, PlanMaintenanceVO } from '@/api/mes/planmaintenance'
|
||||
import InspectionPlanForm from './InspectionPlanForm.vue'
|
||||
import { isHexColor } from '@/utils/color'
|
||||
import { useDictStoreWithOut } from '@/store/modules/dict'
|
||||
|
||||
defineOptions({ name: 'MoldInspectionPlan' })
|
||||
|
||||
const message = useMessage()
|
||||
const { t } = useI18n()
|
||||
|
||||
const dictStore = useDictStoreWithOut()
|
||||
const dictReady = ref(false)
|
||||
|
||||
const loading = ref(false)
|
||||
const list = ref<PlanMaintenanceVO[]>([])
|
||||
const total = ref(0)
|
||||
const exportLoading = ref(false)
|
||||
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
planName: undefined as string | undefined,
|
||||
planType: undefined as number | undefined,
|
||||
description: undefined as string | undefined
|
||||
})
|
||||
|
||||
const queryFormRef = ref()
|
||||
|
||||
const tableRef = ref()
|
||||
const selectedIds = ref<(number | string)[]>([])
|
||||
const handleSelectionChange = (rows: any[]) => {
|
||||
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined && id !== null && id !== '') ?? []
|
||||
}
|
||||
|
||||
const subjectListMap = ref<Record<string, PlanMaintenanceSubjectVO[]>>({})
|
||||
const subjectLoadingMap = ref<Record<string, boolean>>({})
|
||||
|
||||
const getTagDict = (dictType: string, value: any) => {
|
||||
if (!dictReady.value) return undefined
|
||||
const v = value === '' || value === null || value === undefined ? undefined : String(value)
|
||||
if (!v) return undefined
|
||||
return getStrDictOptions(dictType).find((d) => d.value === v)
|
||||
}
|
||||
|
||||
const getTagLabel = (dictType: string, value: any) => {
|
||||
const found = getTagDict(dictType, value)
|
||||
return found?.label ?? (value ?? '')
|
||||
}
|
||||
|
||||
const getTagType = (dictType: string, value: any) => {
|
||||
const found = getTagDict(dictType, value)
|
||||
const type = found?.colorType
|
||||
if (type + '' === 'primary' || type + '' === 'default') return '' as any
|
||||
return (type ?? '') as any
|
||||
}
|
||||
|
||||
const getTagColor = (dictType: string, value: any) => {
|
||||
const found = getTagDict(dictType, value)
|
||||
if (found?.cssClass && isHexColor(found.cssClass)) return found.cssClass
|
||||
return ''
|
||||
}
|
||||
|
||||
const getTagStyle = (dictType: string, value: any) => {
|
||||
const color = getTagColor(dictType, value)
|
||||
if (!color) return ''
|
||||
return 'color: #fff'
|
||||
}
|
||||
|
||||
const normalizeList = (res: any): { list: any[]; total: number } => {
|
||||
if (Array.isArray(res)) return { list: res, total: res.length }
|
||||
return { list: res?.list ?? [], total: res?.total ?? 0 }
|
||||
}
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await PlanMaintenanceApi.getPlanMaintenancePage({
|
||||
pageNo: queryParams.pageNo,
|
||||
pageSize: queryParams.pageSize,
|
||||
planName: queryParams.planName,
|
||||
planType: queryParams.planType,
|
||||
description: queryParams.description
|
||||
})
|
||||
const normalized = normalizeList(res)
|
||||
list.value = normalized.list as PlanMaintenanceVO[]
|
||||
total.value = normalized.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value?.resetFields?.()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
const ensureSubjectListLoaded = async (id: number | string) => {
|
||||
const key = String(id)
|
||||
if (!key) return
|
||||
if (subjectListMap.value[key]) return
|
||||
subjectLoadingMap.value[key] = true
|
||||
try {
|
||||
const res = await PlanMaintenanceApi.getSubjectList(id)
|
||||
const data = Array.isArray(res) ? res : res?.list ?? res ?? []
|
||||
subjectListMap.value[key] = (data ?? []) as PlanMaintenanceSubjectVO[]
|
||||
} finally {
|
||||
subjectLoadingMap.value[key] = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleExpandChange = async (row: PlanMaintenanceVO, expandedRows: PlanMaintenanceVO[]) => {
|
||||
const isExpanded = expandedRows.some((r) => String(r.id) === String(row.id))
|
||||
if (!isExpanded) return
|
||||
if (row?.id === undefined || row?.id === null || row?.id === '') return
|
||||
await ensureSubjectListLoaded(row.id)
|
||||
}
|
||||
|
||||
const getPlanTypeLabel = (value: any) => {
|
||||
const v = value === '' || value === null || value === undefined ? undefined : Number(value)
|
||||
if (v === 1) return '保养'
|
||||
if (v === 2) return '维护'
|
||||
return value ?? ''
|
||||
}
|
||||
|
||||
const getPlanTypeTagType = (value: any) => {
|
||||
const v = value === '' || value === null || value === undefined ? undefined : Number(value)
|
||||
if (v === 1) return 'success'
|
||||
if (v === 2) return 'primary'
|
||||
return ''
|
||||
}
|
||||
|
||||
const formRef = ref()
|
||||
const openForm = (type: 'create' | 'update', row?: PlanMaintenanceVO) => {
|
||||
formRef.value?.open(type, row)
|
||||
}
|
||||
|
||||
const buildIdsParam = (ids: number | string | Array<number | string>) => {
|
||||
return Array.isArray(ids) ? ids.join(',') : String(ids)
|
||||
}
|
||||
|
||||
const handleDelete = async (ids: number | string | Array<number | string>) => {
|
||||
try {
|
||||
await message.delConfirm()
|
||||
await PlanMaintenanceApi.deletePlanMaintenance(buildIdsParam(ids))
|
||||
message.success(t('common.delSuccess'))
|
||||
selectedIds.value = []
|
||||
tableRef.value?.clearSelection?.()
|
||||
await getList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const handleBatchDelete = async () => {
|
||||
if (!selectedIds.value.length) {
|
||||
message.error('请选择需要删除的数据')
|
||||
return
|
||||
}
|
||||
await handleDelete(selectedIds.value)
|
||||
}
|
||||
|
||||
const handleExport = async () => {
|
||||
if (!selectedIds.value.length) {
|
||||
message.error('请选择需要导出的数据')
|
||||
return
|
||||
}
|
||||
try {
|
||||
await message.exportConfirm()
|
||||
exportLoading.value = true
|
||||
const data = await PlanMaintenanceApi.exportPlanMaintenance({ ids: selectedIds.value.join(',') })
|
||||
download.excel(data, '方案维护.xls')
|
||||
} catch {
|
||||
} finally {
|
||||
exportLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await dictStore.setDictMap()
|
||||
dictReady.value = true
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -0,0 +1,245 @@
|
||||
<template>
|
||||
<Dialog :title="dialogTitle" v-model="dialogVisible">
|
||||
<el-form
|
||||
ref="formRef"
|
||||
:model="formData"
|
||||
:rules="formRules"
|
||||
label-width="110px"
|
||||
v-loading="formLoading"
|
||||
>
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input v-model="formData.name" placeholder="请输入名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="taskType">
|
||||
<el-radio-group v-model="formData.taskType">
|
||||
<el-radio :label="1">点检</el-radio>
|
||||
<el-radio :label="2">保养</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="设备列表" prop="deviceList">
|
||||
<el-select
|
||||
v-model="formData.deviceList"
|
||||
multiple
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择设备列表"
|
||||
class="!w-full"
|
||||
>
|
||||
<el-option v-for="item in deviceOptions" :key="String(item.id)" :label="item.deviceName" :value="String(item.id)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目表单" prop="projectForm">
|
||||
<el-select
|
||||
v-model="formData.projectForm"
|
||||
multiple
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择项目表单"
|
||||
class="!w-full"
|
||||
>
|
||||
<el-option v-for="item in planOptions" :key="String(item.id)" :label="item.planName" :value="String(item.id)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="起止日期" prop="dateRange">
|
||||
<el-date-picker
|
||||
v-model="formData.dateRange"
|
||||
value-format="YYYY-MM-DD"
|
||||
type="daterange"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
class="!w-320px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="cron 表达式" prop="cronExpression">
|
||||
<crontab v-model="formData.cronExpression" />
|
||||
</el-form-item>
|
||||
<el-form-item label="可操作人" prop="operableUsers">
|
||||
<el-select
|
||||
v-model="formData.operableUsers"
|
||||
multiple
|
||||
filterable
|
||||
clearable
|
||||
placeholder="请选择可操作人"
|
||||
class="!w-full"
|
||||
>
|
||||
<el-option v-for="item in users" :key="String(item.id)" :label="item.nickname" :value="String(item.id)" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="是否启用" prop="enabled">
|
||||
<el-radio-group v-model="formData.enabled">
|
||||
<el-radio v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" :key="String(dict.value)" :label="dict.value">
|
||||
{{ dict.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
|
||||
<el-button @click="dialogVisible = false">取 消</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DICT_TYPE, getBoolDictOptions } from '@/utils/dict'
|
||||
import { TaskManagementApi, TaskManagementVO } from '@/api/mes/taskManagement'
|
||||
import { DeviceLedgerApi } from '@/api/mes/deviceledger'
|
||||
import { PlanMaintenanceApi } from '@/api/mes/planmaintenance'
|
||||
import { getSimpleUserList, UserVO } from '@/api/system/user'
|
||||
|
||||
defineOptions({ name: 'MoldTaskConfigurationForm' })
|
||||
|
||||
const { t } = useI18n()
|
||||
const message = useMessage()
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const dialogTitle = ref('')
|
||||
const formLoading = ref(false)
|
||||
const formType = ref('')
|
||||
const formRef = ref()
|
||||
|
||||
type DeviceOption = {
|
||||
id: number | string
|
||||
deviceName: string
|
||||
}
|
||||
|
||||
type PlanOption = {
|
||||
id: number | string
|
||||
planName: string
|
||||
}
|
||||
|
||||
const deviceOptions = ref<DeviceOption[]>([])
|
||||
const planOptions = ref<PlanOption[]>([])
|
||||
const users = ref<UserVO[]>([])
|
||||
|
||||
const parseIdsValue = (value: any): string[] => {
|
||||
if (!value) return []
|
||||
if (Array.isArray(value)) return value.map((v) => String(v).trim()).filter(Boolean)
|
||||
return String(value)
|
||||
.split(',')
|
||||
.map((v) => v.trim())
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
const toCommaSeparatedIds = (value: any): string | undefined => {
|
||||
const ids = parseIdsValue(value)
|
||||
return ids.length ? ids.join(',') : undefined
|
||||
}
|
||||
|
||||
const ensureOptionsLoaded = async () => {
|
||||
const [deviceRes, planRes, userRes] = await Promise.all([
|
||||
DeviceLedgerApi.getDeviceLedgerPage({}),
|
||||
PlanMaintenanceApi.getPlanMaintenancePage({ pageNo: 1, pageSize: 100 }),
|
||||
getSimpleUserList()
|
||||
])
|
||||
deviceOptions.value = (deviceRes?.list ?? []) as DeviceOption[]
|
||||
planOptions.value = (planRes?.list ?? []) as PlanOption[]
|
||||
users.value = userRes ?? []
|
||||
}
|
||||
|
||||
const formData = ref({
|
||||
id: undefined as number | undefined,
|
||||
name: undefined as string | undefined,
|
||||
taskType: undefined as number | undefined,
|
||||
deviceList: [] as string[],
|
||||
projectForm: [] as string[],
|
||||
dateRange: [] as string[],
|
||||
cronExpression: undefined as string | undefined,
|
||||
operableUsers: [] as string[],
|
||||
enabled: true as boolean
|
||||
})
|
||||
|
||||
const formRules = reactive({
|
||||
name: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
|
||||
taskType: [{ required: true, message: '类型不能为空', trigger: 'change' }],
|
||||
enabled: [{ required: true, message: '是否启用不能为空', trigger: 'change' }]
|
||||
})
|
||||
|
||||
const resetForm = () => {
|
||||
formData.value = {
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
taskType: undefined,
|
||||
deviceList: [],
|
||||
projectForm: [],
|
||||
dateRange: [],
|
||||
cronExpression: undefined,
|
||||
operableUsers: [],
|
||||
enabled: true
|
||||
}
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
|
||||
const open = async (type: string, row?: TaskManagementVO) => {
|
||||
dialogVisible.value = true
|
||||
dialogTitle.value = t('action.' + type)
|
||||
formType.value = type
|
||||
resetForm()
|
||||
await ensureOptionsLoaded()
|
||||
|
||||
if (type === 'update' && row) {
|
||||
formData.value.id = row.id
|
||||
formData.value.name = row.name
|
||||
formData.value.taskType = row.taskType
|
||||
formData.value.deviceList = parseIdsValue((row as any).deviceList)
|
||||
const projectFormIds = parseIdsValue((row as any).projectForm)
|
||||
if (projectFormIds.length) {
|
||||
formData.value.projectForm = projectFormIds
|
||||
} else {
|
||||
const projectFormNames = parseIdsValue((row as any).projectFormName)
|
||||
const mappedIds = projectFormNames
|
||||
.map((name) => planOptions.value.find((p) => p.planName === name)?.id)
|
||||
.filter((id) => id !== undefined && id !== null)
|
||||
.map((id) => String(id))
|
||||
formData.value.projectForm = mappedIds
|
||||
}
|
||||
formData.value.dateRange = [row.startDate, row.endDate].filter(Boolean) as string[]
|
||||
formData.value.cronExpression = row.cronExpression
|
||||
formData.value.operableUsers = parseIdsValue((row as any).operableUsers)
|
||||
if (typeof row.enabled === 'boolean') {
|
||||
formData.value.enabled = row.enabled
|
||||
} else if (row.enabled === 'true' || row.enabled === 'false') {
|
||||
formData.value.enabled = row.enabled === 'true'
|
||||
} else {
|
||||
formData.value.enabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
|
||||
const submitForm = async () => {
|
||||
await formRef.value.validate()
|
||||
formLoading.value = true
|
||||
try {
|
||||
const [startDate, endDate] = Array.isArray(formData.value.dateRange) ? formData.value.dateRange : []
|
||||
const payload: TaskManagementVO = {
|
||||
id: formData.value.id,
|
||||
name: formData.value.name,
|
||||
taskType: formData.value.taskType,
|
||||
deviceList: toCommaSeparatedIds((formData.value as any).deviceList),
|
||||
projectForm: toCommaSeparatedIds((formData.value as any).projectForm),
|
||||
startDate: startDate || undefined,
|
||||
endDate: endDate || undefined,
|
||||
cronExpression: formData.value.cronExpression,
|
||||
operableUsers: toCommaSeparatedIds((formData.value as any).operableUsers),
|
||||
enabled: formData.value.enabled
|
||||
}
|
||||
|
||||
if (formType.value === 'create') {
|
||||
await TaskManagementApi.createTaskManagement(payload)
|
||||
message.success(t('common.createSuccess'))
|
||||
} else {
|
||||
await TaskManagementApi.updateTaskManagement(payload)
|
||||
message.success(t('common.updateSuccess'))
|
||||
}
|
||||
dialogVisible.value = false
|
||||
emit('success')
|
||||
} finally {
|
||||
formLoading.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -0,0 +1,230 @@
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<el-form
|
||||
class="-mb-15px"
|
||||
:model="queryParams"
|
||||
ref="queryFormRef"
|
||||
:inline="true"
|
||||
label-width="68px"
|
||||
>
|
||||
<el-form-item label="名称" prop="name">
|
||||
<el-input
|
||||
v-model="queryParams.name"
|
||||
placeholder="请输入名称"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="taskType">
|
||||
<el-select v-model="queryParams.taskType" placeholder="请选择类型" clearable class="!w-240px">
|
||||
<el-option v-for="opt in taskTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="项目表单" prop="projectForm">
|
||||
<el-input
|
||||
v-model="queryParams.projectForm"
|
||||
placeholder="请输入项目表单"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="handleQuery">
|
||||
<Icon icon="ep:search" class="mr-5px" /> 搜索
|
||||
</el-button>
|
||||
<el-button @click="resetQuery">
|
||||
<Icon icon="ep:refresh" class="mr-5px" /> 重置
|
||||
</el-button>
|
||||
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['mes:task-management:create']">
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 新增
|
||||
</el-button>
|
||||
<el-button
|
||||
type="success"
|
||||
plain
|
||||
@click="handleExport"
|
||||
:loading="exportLoading"
|
||||
v-hasPermi="['mes:task-management:export']"
|
||||
>
|
||||
<Icon icon="ep:download" class="mr-5px" /> 导出
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
|
||||
<ContentWrap>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
:stripe="true"
|
||||
:show-overflow-tooltip="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column type="index" label="序号" align="center" width="70" />
|
||||
<el-table-column label="名称" align="center" prop="name" min-width="140" />
|
||||
<el-table-column label="类型" align="center" prop="taskType" width="90">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.taskType === 1" type="primary">点检</el-tag>
|
||||
<el-tag v-else-if="scope.row.taskType === 2" type="success">保养</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="项目表单" align="center" prop="projectForm" min-width="140" />
|
||||
<el-table-column label="开始日期" align="center" prop="startDate" :formatter="dateFormatter2" width="120" />
|
||||
<el-table-column label="结束日期" align="center" prop="endDate" :formatter="dateFormatter2" width="120" />
|
||||
<el-table-column label="cron 表达式" align="center" prop="cronExpression" min-width="180" />
|
||||
<el-table-column label="启用" align="center" prop="enabled" width="90">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.enabled" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建人" align="center" prop="creator" width="120" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
|
||||
<el-table-column label="更新时间" align="center" prop="updateTime" :formatter="dateFormatter" width="180" />
|
||||
<el-table-column label="操作" fixed="right" align="center" width="230">
|
||||
<template #default="scope">
|
||||
<el-button
|
||||
link
|
||||
type="success"
|
||||
@click="handleCreateTicket(scope.row.id)"
|
||||
:loading="ticketLoadingId === scope.row.id"
|
||||
>
|
||||
新增工单管理
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
type="primary"
|
||||
@click="openForm('update', scope.row)"
|
||||
v-hasPermi="['mes:task-management:update']"
|
||||
>
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:task-management:delete']">
|
||||
删除
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
</ContentWrap>
|
||||
|
||||
<TaskConfigurationForm ref="formRef" @success="getList" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import { dateFormatter, dateFormatter2 } from '@/utils/formatTime'
|
||||
import download from '@/utils/download'
|
||||
import { TaskManagementApi, TaskManagementVO } from '@/api/mes/taskManagement'
|
||||
import TaskConfigurationForm from './TaskConfigurationForm.vue'
|
||||
|
||||
defineOptions({ name: 'MoldTaskConfiguration' })
|
||||
|
||||
const message = useMessage()
|
||||
const { t } = useI18n()
|
||||
|
||||
const taskTypeOptions = [
|
||||
{ label: '点检', value: 1 },
|
||||
{ label: '保养', value: 2 }
|
||||
]
|
||||
|
||||
const loading = ref(true)
|
||||
const list = ref<TaskManagementVO[]>([])
|
||||
const total = ref(0)
|
||||
const exportLoading = ref(false)
|
||||
const selectedIds = ref<number[]>([])
|
||||
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
name: undefined as string | undefined,
|
||||
taskType: undefined as number | undefined,
|
||||
projectForm: undefined as string | undefined
|
||||
})
|
||||
const queryFormRef = ref()
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await TaskManagementApi.getTaskManagementPage(queryParams)
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
const handleSelectionChange = (rows: TaskManagementVO[]) => {
|
||||
selectedIds.value = rows
|
||||
.map((r) => r.id)
|
||||
.filter((id): id is number => typeof id === 'number')
|
||||
}
|
||||
|
||||
const formRef = ref()
|
||||
const openForm = (type: string, row?: TaskManagementVO) => {
|
||||
formRef.value.open(type, row)
|
||||
}
|
||||
|
||||
const handleDelete = async (id?: number) => {
|
||||
if (!id) return
|
||||
try {
|
||||
await message.delConfirm()
|
||||
await TaskManagementApi.deleteTaskManagement(String(id))
|
||||
message.success(t('common.delSuccess'))
|
||||
await getList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
const ticketLoadingId = ref<number | undefined>(undefined)
|
||||
const handleCreateTicket = async (id?: number) => {
|
||||
if (!id) return
|
||||
ticketLoadingId.value = id
|
||||
try {
|
||||
await TaskManagementApi.createTaskManagementTicket(id)
|
||||
message.success('创建工单成功')
|
||||
} catch {
|
||||
message.error('创建工单失败')
|
||||
} finally {
|
||||
ticketLoadingId.value = undefined
|
||||
}
|
||||
}
|
||||
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
await message.exportConfirm()
|
||||
exportLoading.value = true
|
||||
const params: Record<string, any> = { ...queryParams }
|
||||
if (selectedIds.value.length > 0) {
|
||||
params.ids = selectedIds.value.join(',')
|
||||
}
|
||||
const data = await TaskManagementApi.exportTaskManagement(params)
|
||||
download.excel(data, '任务配置.xls')
|
||||
} catch {
|
||||
} finally {
|
||||
exportLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
|
||||
<el-form-item label="单号" prop="planNo">
|
||||
<el-input
|
||||
v-model="queryParams.planNo"
|
||||
placeholder="请输入单号"
|
||||
clearable
|
||||
@keyup.enter="handleQuery"
|
||||
class="!w-240px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="planType">
|
||||
<el-select v-model="queryParams.planType" placeholder="请选择类型" clearable class="!w-240px">
|
||||
<el-option v-for="opt in planTypeOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="作业状态" prop="jobStatus">
|
||||
<el-select v-model="queryParams.jobStatus" placeholder="请选择作业状态" clearable class="!w-240px">
|
||||
<el-option v-for="opt in getStrDictOptions('job_status')" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="结果" prop="jobResult">
|
||||
<el-select v-model="queryParams.jobResult" placeholder="请选择结果" clearable class="!w-240px">
|
||||
<el-option v-for="opt in jobResultOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button @click="resetQuery">
|
||||
<Icon icon="ep:refresh" class="mr-5px" /> 重置
|
||||
</el-button>
|
||||
<el-button type="primary" @click="handleQuery">
|
||||
<Icon icon="ep:search" class="mr-5px" /> 查询
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</ContentWrap>
|
||||
|
||||
<ContentWrap>
|
||||
<div class="mb-10px">
|
||||
<el-button type="warning" plain @click="handleBatchCancel" :disabled="!selectedIds.length" :loading="cancelLoading">
|
||||
取消任务
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="list"
|
||||
:stripe="true"
|
||||
:show-overflow-tooltip="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
@row-click="handleRowClick"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column type="index" label="序号" align="center" width="70" />
|
||||
<el-table-column label="单号" align="center" prop="planNo" min-width="160" />
|
||||
<el-table-column label="设备名称" align="center" prop="deviceName" min-width="160" />
|
||||
<el-table-column label="类型" align="center" prop="planType" width="90">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="String(scope.row.planType) === '1'" type="primary">点检</el-tag>
|
||||
<el-tag v-else-if="String(scope.row.planType) === '2'" type="success">保养</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="计划配置名称" align="center" prop="configName" min-width="160" />
|
||||
<el-table-column label="作业状态" align="center" prop="jobStatus" width="120">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="'job_status'" :value="scope.row.jobStatus" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="作业人" align="center" prop="operatorName" width="140" />
|
||||
<el-table-column label="作业时间" align="center" prop="taskTime" :formatter="dateFormatter" width="180" />
|
||||
<el-table-column label="计划结束作业时间" align="center" prop="taskEndTime" :formatter="dateFormatter" width="180" />
|
||||
<el-table-column label="结果" align="center" prop="jobResult" width="90">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.jobResult == '1'" type="success">通过</el-tag>
|
||||
<el-tag v-else-if="scope.row.jobResult == '2'" type="danger">不通过</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" min-width="160" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180" />
|
||||
</el-table>
|
||||
|
||||
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||
</ContentWrap>
|
||||
|
||||
<TicketResultDialog ref="resultDialogRef" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
import { getStrDictOptions } from '@/utils/dict'
|
||||
import { useDictStoreWithOut } from '@/store/modules/dict'
|
||||
import { TicketManagementApi, TicketManagementVO } from '@/api/mes/ticketManagement'
|
||||
import TicketResultDialog from '@/views/mes/workOrderManagement/components/TicketResultDialog.vue'
|
||||
|
||||
defineOptions({ name: 'MoldWorkOrderInquiry' })
|
||||
|
||||
const message = useMessage()
|
||||
const dictStore = useDictStoreWithOut()
|
||||
|
||||
const planTypeOptions = [
|
||||
{ label: '点检', value: '1' },
|
||||
{ label: '保养', value: '2' }
|
||||
]
|
||||
const jobResultOptions = [
|
||||
{ label: '通过', value: 'OK' },
|
||||
{ label: '不通过', value: 'NG' }
|
||||
]
|
||||
|
||||
const loading = ref(true)
|
||||
const list = ref<TicketManagementVO[]>([])
|
||||
const total = ref(0)
|
||||
const selectedIds = ref<number[]>([])
|
||||
const cancelLoading = ref(false)
|
||||
|
||||
const queryParams = reactive({
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
planNo: undefined as string | undefined,
|
||||
planType: undefined as string | undefined,
|
||||
jobStatus: undefined as string | undefined,
|
||||
jobResult: undefined as string | undefined
|
||||
})
|
||||
|
||||
const queryFormRef = ref()
|
||||
|
||||
const getList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await TicketManagementApi.getTicketManagementPage(queryParams)
|
||||
list.value = data.list
|
||||
total.value = data.total
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
const resetQuery = () => {
|
||||
queryFormRef.value.resetFields()
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
const handleSelectionChange = (rows: TicketManagementVO[]) => {
|
||||
selectedIds.value = rows
|
||||
.map((r) => r.id)
|
||||
.filter((id): id is number => typeof id === 'number')
|
||||
}
|
||||
|
||||
const handleBatchCancel = async () => {
|
||||
if (!selectedIds.value.length) return
|
||||
try {
|
||||
await message.confirm('确认取消选中的任务吗?')
|
||||
cancelLoading.value = true
|
||||
await TicketManagementApi.batchUpdateTicketStatus({ ids: selectedIds.value.join(','), jobStatus: '2' })
|
||||
message.success('取消任务成功')
|
||||
selectedIds.value = []
|
||||
await getList()
|
||||
} catch {
|
||||
} finally {
|
||||
cancelLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const resultDialogRef = ref<InstanceType<typeof TicketResultDialog>>()
|
||||
|
||||
const handleRowClick = async (row: TicketManagementVO, column: any) => {
|
||||
if (column?.type === 'selection') return
|
||||
if (!row?.id) return
|
||||
await resultDialogRef.value?.open({
|
||||
managementId: row.id,
|
||||
title: row.planNo ? `检验结果-${row.planNo}` : '检验结果'
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await dictStore.setDictMap()
|
||||
await getList()
|
||||
})
|
||||
</script>
|
||||
|
||||
Loading…
Reference in New Issue