kkk-ops 2 months ago
commit f9649fd03f

@ -23,6 +23,8 @@ export interface DeviceLedgerVO {
remark: string // 备注
fileUrl?: string // 附件下载
componentId?: string // 关键件ids集合
inspectionList?: any[]
maintainList?: any[]
creator?: string // 创建人
createTime?: string | number | Date
updateTime?: string | number | Date

@ -1,62 +1,62 @@
import request from '@/config/axios'
// 设备维修记录 VO
export interface DvRepairVO {
id: number // ID
repairCode: string // 维修单编号
repairName: string // 维修单名称
machineryId: number // 设备ID
machineryCode: string // 设备编码
machineryName: string // 设备名称
machineryBrand: string // 品牌
machinerySpec: string // 规格型号
machineryTypeId: number // 设备类型
requireDate: Date // 报修日期
finishDate: Date // 完成日期
confirmDate: Date // 验收日期
repairResult: string // 维修结果
acceptedBy: string // 维修人员
confirmBy: string // 验收人员
status: string // 单据状态
remark: string // 备注
}
// 设备维修记录 API
export const DvRepairApi = {
// 查询设备维修记录分页
getDvRepairPage: async (params: any) => {
return await request.get({ url: `/mes/dv-repair/page`, params })
},
// 查询设备维修记录详情
getDvRepair: async (id: number) => {
return await request.get({ url: `/mes/dv-repair/get?id=` + id })
},
// 新增设备维修记录
createDvRepair: async (data: DvRepairVO) => {
return await request.post({ url: `/mes/dv-repair/create`, data })
},
// 修改设备维修记录
updateDvRepair: async (data: DvRepairVO) => {
return await request.put({ url: `/mes/dv-repair/update`, data })
},
// 删除设备维修记录
deleteDvRepair: async (id: number) => {
return await request.delete({ url: `/mes/dv-repair/delete?id=` + id })
},
// 导出设备维修记录 Excel
exportDvRepair: async (params) => {
return await request.download({ url: `/mes/dv-repair/export-excel`, params })
},
// ==================== 子表(设备维修记录行) ====================
// 获得设备维修记录行列表
getDvRepairLineListByRepairId: async (repairId) => {
return await request.get({ url: `/mes/dv-repair/dv-repair-line/list-by-repair-id?repairId=` + repairId })
},
}
import request from '@/config/axios'
// 设备维修记录 VO
export interface DvRepairVO {
id: number // ID
repairCode: string // 维修单编号
repairName: string // 维修单名称
machineryId: number // 设备ID
machineryCode: string // 设备编码
machineryName: string // 设备名称
machineryBrand: string // 品牌
machinerySpec: string // 规格型号
machineryTypeId: number // 设备类型
requireDate: Date // 报修日期
finishDate: Date // 完成日期
confirmDate: Date // 验收日期
repairResult: string // 维修结果
acceptedBy: string // 维修人员
confirmBy: string // 验收人员
status: string // 单据状态
remark: string // 备注
}
// 设备维修记录 API
export const DvRepairApi = {
// 查询设备维修记录分页
getDvRepairPage: async (params: any) => {
return await request.get({ url: `/mes/dv-repair/page`, params })
},
// 查询设备维修记录详情
getDvRepair: async (id: number) => {
return await request.get({ url: `/mes/dv-repair/get?id=` + id })
},
// 新增设备维修记录
createDvRepair: async (data: DvRepairVO) => {
return await request.post({ url: `/mes/dv-repair/create`, data })
},
// 修改设备维修记录
updateDvRepair: async (data: DvRepairVO) => {
return await request.put({ url: `/mes/dv-repair/update`, data })
},
// 删除设备维修记录
deleteDvRepair: async (ids: string) => {
return await request.delete({ url: `/mes/dv-repair/delete?ids=` + ids })
},
// 导出设备维修记录 Excel
exportDvRepair: async (params) => {
return await request.download({ url: `/mes/dv-repair/export-excel`, params })
},
// ==================== 子表(设备维修记录行) ====================
// 获得设备维修记录行列表
getDvRepairLineListByRepairId: async (repairId) => {
return await request.get({ url: `/mes/dv-repair/dv-repair-line/list-by-repair-id?repairId=` + repairId })
},
}

@ -0,0 +1,49 @@
import request from '@/config/axios'
export interface RepairItemVO {
id?: number
subjectCode: string
subjectName: string
deviceType: string | number
deviceId?: string | number
componentId?: string | number
inspectionMethod?: string
valueType?: string
judgmentCriteria?: string
isEnable: string
deviceName?: string
componentName?: string
creatorName?: string
createTime?: string | number | Date
projectContent?: string
}
export const RepairItemsApi = {
getRepairItemsPage: async (params: any) => {
return await request.get({ url: `/mes/repair-tems/page`, params })
},
getComponentList: async (deviceId: number) => {
return await request.get({ url: `/mes/repair-tems/getComponentList`, params: { deviceId } })
},
getDeviceOrComponentList: async (params: { deviceId: number; componentId?: number; deviceType: number }) => {
return await request.get({ url: `/mes/repair-tems/getDeviceOrComponentList`, params })
},
createRepairItem: async (data: RepairItemVO) => {
return await request.post({ url: `/mes/repair-tems/create`, data })
},
updateRepairItem: async (data: RepairItemVO) => {
return await request.put({ url: `/mes/repair-tems/update`, data })
},
deleteRepairItems: async (ids: string) => {
return await request.delete({ url: `/mes/repair-tems/delete?ids=` + ids })
},
exportRepairItems: async (params: any) => {
return await request.download({ url: `/mes/repair-tems/export-excel`, params })
}
}

@ -73,19 +73,6 @@ const queryParams = reactive({
brandId: undefined as unknown
})
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.brandId,
(val: number) => {
if (!val) {
return
}
queryParams.brandId = val
handleQuery()
},
{ immediate: true, deep: true }
)
/** 查询列表 */
const getList = async () => {
loading.value = true
@ -104,6 +91,19 @@ const handleQuery = () => {
getList()
}
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.brandId,
(val: number) => {
if (!val) {
return
}
queryParams.brandId = val
handleQuery()
},
{ immediate: true, deep: true }
)
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {

@ -12,9 +12,9 @@
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="模具编码" align="center" prop="code"/>
<el-table-column label="模具名称" align="left" prop="name" />
<el-table-column label="单位" align="center" prop="unitName" />
<!-- <el-table-column label="机台" align="center" prop="machineId" /> -->
<el-table-column label="使用次数" align="center" prop="useTime" />
<!-- <el-table-column label="单位" align="center" prop="unitName" /> -->
<el-table-column label="使用次数/次" align="center" prop="useTime" />
<el-table-column
label="入库时间"
align="center"
@ -26,6 +26,7 @@
<dict-tag :type="DICT_TYPE.ERP_MOLD_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<!-- <el-table-column label="机台" align="center" prop="machineId" /> -->
<!-- <el-table-column label="模具图片" align="center" prop="images" /> -->
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="是否启用" align="center" prop="isEnable" >
@ -106,19 +107,6 @@ const queryParams = reactive({
brandId: undefined as unknown
})
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.brandId,
(val: number) => {
if (!val) {
return
}
queryParams.brandId = val
handleQuery()
},
{ immediate: true, deep: true }
)
/** 查询列表 */
const getList = async () => {
loading.value = true
@ -137,6 +125,19 @@ const handleQuery = () => {
getList()
}
/** 监听主表的关联字段的变化,加载对应的子表数据 */
watch(
() => props.brandId,
(val: number) => {
if (!val) {
return
}
queryParams.brandId = val
handleQuery()
},
{ immediate: true, deep: true }
)
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {

@ -26,31 +26,21 @@
class="!w-240px"
/>
</el-form-item>
<el-form-item label="规格" prop="moldType">
<el-input
v-model="queryParams.moldType"
placeholder="请输入规格"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="产品" prop="productId">
<el-form-item label="工序" prop="orgType">
<el-select
v-model="queryParams.productId"
v-model="queryParams.orgType"
placeholder="请选择工序"
clearable
filterable
placeholder="请选择产品"
class="!w-240px"
>
<el-option
v-for="item in productList"
:key="item.id"
:label="item.name"
:value="item.id"
v-for="dict in orgTypeOptions"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-form-item>
<!-- <el-form-item label="维保模式" prop="maintainType">
<el-select
v-model="queryParams.maintainType"
@ -66,15 +56,6 @@
/>
</el-select>
</el-form-item> -->
<el-form-item label="备注" prop="remark">
<el-input
v-model="queryParams.remark"
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>
@ -103,13 +84,17 @@
<!-- 列表 -->
<ContentWrap>
<el-table
ref="tableRef"
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
highlight-current-row
@current-change="handleCurrentChange"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column label="型号编码" align="center" prop="code"/>
<el-table-column label="型号名称" align="left" prop="name"/>
<el-table-column label="规格" align="center" prop="moldType" />
@ -168,26 +153,31 @@
<!-- 表单弹窗添加/修改 -->
<MoldBrandForm ref="formRef" @success="getList" />
<!-- 子表的列表 -->
<ContentWrap>
<ContentWrap v-if="currentBrandId">
<div class="mb-10px text-14px font-600">
{{ currentBrandDisplay }}
</div>
<el-tabs model-value="mold">
<el-tab-pane label="模具" name="mold">
<MoldList :brand-id="currentRow.id" />
</el-tab-pane>
<el-tab-pane label="产品" name="moldBrandProduct">
<MoldBrandProductList :brand-id="currentRow.id" />
<MoldList :brand-id="currentBrandId" />
</el-tab-pane>
<!-- <el-tab-pane label="产品" name="moldBrandProduct">
<MoldBrandProductList :brand-id="currentBrandId" />
</el-tab-pane> -->
</el-tabs>
</ContentWrap>
<ContentWrap v-else>
<el-empty description="请先点击上方列表选择一个模具型号" />
</ContentWrap>
</template>
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import { getStrDictOptions, DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { MoldBrandApi, MoldBrandVO } from '@/api/erp/mold'
import MoldBrandForm from './MoldBrandForm.vue'
import MoldList from './components/MoldList.vue'
import { ProductApi, ProductVO } from '@/api/erp/product/product'
import MoldBrandProductList from './components/MoldBrandProductList.vue'
/** 模具型号 列表 */
@ -195,7 +185,6 @@ defineOptions({ name: 'MoldBrand' })
const message = useMessage() //
const { t } = useI18n() //
const productList = ref<ProductVO[]>([]) //
const loading = ref(true) //
const list = ref<MoldBrandVO[]>([]) //
const total = ref(0) //
@ -204,6 +193,7 @@ const queryParams = reactive({
pageSize: 10,
code: undefined,
name: undefined,
orgType: undefined,
moldType: undefined,
productId: undefined,
useTime: [],
@ -216,6 +206,13 @@ const queryParams = reactive({
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
const orgTypeOptions = computed(() => getStrDictOptions(DICT_TYPE.MES_ORG_TYPE))
const tableRef = ref()
const selectedIds = ref<Array<number | string>>([])
const handleSelectionChange = (rows: any[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined && id !== null && id !== '') ?? []
}
/** 查询列表 */
const getList = async () => {
@ -267,7 +264,10 @@ const handleExport = async () => {
await message.exportConfirm()
//
exportLoading.value = true
const data = await MoldBrandApi.exportMoldBrand(queryParams)
const data = await MoldBrandApi.exportMoldBrand({
...queryParams,
...(selectedIds.value.length ? { ids: selectedIds.value.join(',') } : {})
})
download.excel(data, '模具型号.xls')
} catch {
} finally {
@ -276,15 +276,18 @@ const handleExport = async () => {
}
/** 选中行操作 */
const currentRow = ref({}) //
const handleCurrentChange = (row) => {
const currentRow = ref<MoldBrandVO | null>(null) //
const currentBrandId = computed(() => currentRow.value?.id)
const currentBrandDisplay = computed(() => {
if (!currentRow.value) return ''
return `${currentRow.value.name}-${currentRow.value.code}`
})
const handleCurrentChange = (row: MoldBrandVO | null) => {
currentRow.value = row
}
/** 初始化 **/
onMounted(async () => {
await getList()
//
productList.value = await ProductApi.getMesProductSimpleList()
})
</script>

@ -59,7 +59,13 @@
/>
<div v-loading="chartLoading">
<el-empty v-if="!selectedParam" description="请选择左侧参数" />
<EChart v-else :key="chartRenderKey" :options="chartOption" height="70vh" />
<el-empty v-else-if="chartState === 'empty'" description="暂无数据" />
<EChart
v-else-if="chartState === 'ready'"
:key="chartRenderKey"
:options="chartOption"
height="70vh"
/>
</div>
</ContentWrap>
</el-col>
@ -120,6 +126,7 @@ const selectedModelId = ref<number | undefined>(undefined)
const selectedParam = ref<DeviceTreeNode | null>(null)
const chartLoading = ref(false)
const chartState = ref<'idle' | 'loading' | 'empty' | 'ready'>('idle')
const chartXAxis = ref<string[]>([])
const chartSeries = ref<{ name: string; data: Array<number | null> }[]>([])
const chartRenderKey = ref(0)
@ -251,6 +258,7 @@ const loadTree = async () => {
selectedParam.value = null
selectedDeviceId.value = undefined
selectedModelId.value = undefined
chartState.value = 'idle'
chartXAxis.value = []
chartSeries.value = []
}
@ -300,6 +308,7 @@ const fetchChart = async () => {
return date.includes(':') ? date : `${date} ${suffix}`
}
chartState.value = 'loading'
chartLoading.value = true
resetChartData()
try {
@ -313,6 +322,7 @@ const fetchChart = async () => {
if (!rows.length) {
chartXAxis.value = []
chartSeries.value = []
chartState.value = 'empty'
return
}
@ -356,8 +366,11 @@ const fetchChart = async () => {
const values = keys.map((k) => toNumber(firstRow[k]))
chartSeries.value = [{ name: param?.label || '参数', data: values }]
}
chartState.value = chartXAxis.value.length && chartSeries.value.length ? 'ready' : 'empty'
} catch {
message.error('获取图表数据失败')
chartState.value = 'idle'
} finally {
chartLoading.value = false
}

@ -2,57 +2,35 @@
<div class="device-ledger-layout">
<ContentWrap class="device-ledger-left">
<el-tree
v-loading="typeTreeLoading"
:data="typeTreeData"
node-key="id"
highlight-current
:props="typeTreeProps"
:default-expanded-keys="typeTreeExpandedKeys"
:expand-on-click-node="false"
@node-click="handleTypeNodeClick"
/>
v-loading="typeTreeLoading" :data="typeTreeData" node-key="id" highlight-current :props="typeTreeProps"
:default-expanded-keys="typeTreeExpandedKeys" :expand-on-click-node="false" @node-click="handleTypeNodeClick" />
</ContentWrap>
<div class="device-ledger-right">
<ContentWrap>
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="60px"
>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="60px">
<el-form-item label="编码" prop="deviceCode">
<el-input
v-model="queryParams.deviceCode"
placeholder="请输入编码"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
v-model="queryParams.deviceCode" placeholder="请输入编码" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="名称" prop="deviceName">
<el-input
v-model="queryParams.deviceName"
placeholder="请输入名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
v-model="queryParams.deviceName" placeholder="请输入名称" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="状态" prop="deviceStatus">
<el-select v-model="queryParams.deviceStatus" placeholder="请选择状态" clearable class="!w-240px">
<el-option
v-for="dict in tzStatusOptions"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-option v-for="dict in tzStatusOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</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 @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:device-ledger:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
@ -60,12 +38,8 @@
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['mes:device-ledger:export']"
>
type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['mes:device-ledger:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
@ -74,14 +48,8 @@
<ContentWrap>
<el-table
ref="tableRef"
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
@selection-change="handleSelectionChange"
>
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"
row-key="id" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column label="序号" align="center" width="80" fixed="left">
<template #default="scope">
@ -100,12 +68,9 @@
<el-table-column label="状态" align="center" prop="deviceStatus">
<template #default="scope">
<el-tag
:type="getTzStatusTagType(scope.row.deviceStatus)"
:type="getTzStatusTagType(scope.row.deviceStatus)"
:color="getTzStatusTagColor(scope.row.deviceStatus)"
:style="getTzStatusTagStyle(scope.row.deviceStatus)"
effect="light"
disable-transitions
>
:style="getTzStatusTagStyle(scope.row.deviceStatus)" effect="light" disable-transitions>
{{ getTzStatusLabel(scope.row.deviceStatus) }}
</el-tag>
</template>
@ -113,40 +78,40 @@
<el-table-column label="规格" align="center" prop="deviceSpec" />
<el-table-column label="型号" align="center" prop="deviceModel" />
<el-table-column label="品牌" align="center" prop="deviceBrand" />
<el-table-column label="生产日期" align="center" prop="productionDate" :formatter="dateFormatter2" width="140px" />
<el-table-column label="入厂日期" align="center" prop="factoryEntryDate" :formatter="dateFormatter2" width="140px" />
<el-table-column label="供应商" align="center" prop="supplier" width="110px"/>
<el-table-column label="所属车间" align="center" prop="workshop" width="110px"/>
<el-table-column
label="生产日期" align="center" prop="productionDate" :formatter="dateFormatter2"
width="140px" />
<el-table-column
label="入厂日期" align="center" prop="factoryEntryDate" :formatter="dateFormatter2"
width="140px" />
<el-table-column label="供应商" align="center" prop="supplier" width="110px" />
<el-table-column label="所属车间" align="center" prop="workshop" width="110px" />
<el-table-column label="位置" align="center" prop="deviceLocation" />
<el-table-column label="使用部门" align="center" prop="systemOrg" width="110px"/>
<el-table-column label="责任人" align="center" prop="deviceManagerName" width="110px"/>
<el-table-column label="使用部门" align="center" prop="systemOrg" width="110px" />
<el-table-column label="责任人" align="center" prop="deviceManagerName" width="110px" />
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="创建人" align="center" prop="creatorName" width="120px"/>
<el-table-column label="创建人" align="center" prop="creatorName" width="120px" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
<el-table-column label="更新时间" align="center" prop="updateTime" :formatter="dateFormatter" width="180px" />
<el-table-column label="操作" align="center" min-width="160px" fixed="right">
<template #default="scope">
<el-button link @click="handleDetail(scope.row.id)"></el-button>
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['mes:device-ledger:update']"
>
link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['mes:device-ledger:update']">
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['mes:device-ledger:delete']"
>
link type="danger" @click="handleDelete(scope.row.id)"
v-hasPermi="['mes:device-ledger:delete']">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<Pagination :total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize" @pagination="getList" />
<Pagination
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
<ContentWrap v-if="detailVisible" v-loading="detailLoading">
@ -166,7 +131,8 @@
<el-descriptions-item label="设备型号">{{ detailData?.deviceModel ?? '' }}</el-descriptions-item>
<el-descriptions-item label="设备规格">{{ detailData?.deviceSpec ?? '' }}</el-descriptions-item>
<el-descriptions-item label="设备类型">
<el-tag effect="light">{{ getDeviceTypeName(detailData?.deviceTypeName ?? detailData?.deviceType) }}</el-tag>
<el-tag effect="light">{{ getDeviceTypeName(detailData?.deviceTypeName ?? detailData?.deviceType)
}}</el-tag>
</el-descriptions-item>
<el-descriptions-item label="供应商">{{ detailData?.supplier ?? '' }}</el-descriptions-item>
<el-descriptions-item label="所属车间">{{ detailData?.workshop ?? '' }}</el-descriptions-item>
@ -174,19 +140,198 @@
<el-descriptions-item label="设备位置">{{ detailData?.deviceLocation ?? '' }}</el-descriptions-item>
<el-descriptions-item label="设备负责人">{{ detailData?.deviceManager ?? '' }}</el-descriptions-item>
<el-descriptions-item label="设备生产日期">{{ formatDetailDate(detailData?.productionDate) }}</el-descriptions-item>
<el-descriptions-item label="设备入厂日期">{{ formatDetailDate(detailData?.factoryEntryDate) }}</el-descriptions-item>
<el-descriptions-item label="备注">{{ detailData?.remark ?? detailData?.deviceRemark ?? '' }}</el-descriptions-item>
<el-descriptions-item label="设备入厂日期">{{ formatDetailDate(detailData?.factoryEntryDate)
}}</el-descriptions-item>
<el-descriptions-item label="备注">{{ detailData?.remark ?? detailData?.deviceRemark ?? ''
}}</el-descriptions-item>
</el-descriptions>
<el-tabs v-model="detailActiveTab" class="mt-12px">
<el-tab-pane label="点检履历" name="check">
<el-empty />
<el-empty v-if="!inspectionStepGroups.length" />
<el-steps v-else direction="vertical" :active="inspectionStepGroups.length" class="device-ledger-history-steps">
<el-step v-for="group in inspectionStepGroups" :key="group.key">
<template #title>
<div class="device-ledger-history-title">
<span class="device-ledger-history-time">[{{ group.time }}]</span>
<span class="device-ledger-history-operator">操作人: {{ group.operator }}</span>
</div>
</template>
<template #description>
<div class="device-ledger-history-items">
<div v-for="item in group.items" :key="item.key" class="device-ledger-history-item">
<div class="device-ledger-history-item-head">
<el-tag :type="getResultTagType(item.result)">{{ getResultLabel(item.result) }}</el-tag>
<span class="device-ledger-history-item-text">{{ item.name }}</span>
</div>
<div class="device-ledger-history-item-body">
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">点检方式</span>
<span class="device-ledger-history-item-value">{{ item.method ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">判定标准</span>
<span class="device-ledger-history-item-value">{{ item.criteria ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">点检时间</span>
<span class="device-ledger-history-item-value">{{ formatHistoryTime(item.inspectionTime) }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">创建时间</span>
<span class="device-ledger-history-item-value">{{ formatHistoryTime(item.createTime) }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">备注</span>
<span class="device-ledger-history-item-value">{{ item.remark ?? '-' }}</span>
</div>
<div v-if="item.images?.length" class="device-ledger-history-item-images">
<el-image
v-for="img in item.images"
:key="img"
:src="img"
:preview-src-list="item.images"
preview-teleported
fit="cover"
class="device-ledger-history-item-image"
>
<template #error>
<div class="device-ledger-history-image-error">图片加载失败</div>
</template>
</el-image>
</div>
</div>
</div>
</div>
</template>
</el-step>
</el-steps>
</el-tab-pane>
<el-tab-pane label="保养履历" name="maintain">
<el-empty />
<el-empty v-if="!maintainStepGroups.length" />
<el-steps v-else direction="vertical" class="device-ledger-history-steps" :active="maintainStepGroups.length">
<el-step v-for="group in maintainStepGroups" :key="group.key">
<template #title>
<div class="device-ledger-history-title">
<span class="device-ledger-history-time">[{{ group.time }}]</span>
<span class="device-ledger-history-operator">操作人: {{ group.operator }}</span>
</div>
</template>
<template #description>
<div class="device-ledger-history-items">
<div v-for="item in group.items" :key="item.key" class="device-ledger-history-item">
<div class="device-ledger-history-item-head">
<el-tag :type="getResultTagType(item.result)">{{ getResultLabel(item.result) }}</el-tag>
<span class="device-ledger-history-item-text">{{ item.name }}</span>
</div>
<div class="device-ledger-history-item-body">
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">保养方式</span>
<span class="device-ledger-history-item-value">{{ item.method ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">判定标准</span>
<span class="device-ledger-history-item-value">{{ item.criteria ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">保养时间</span>
<span class="device-ledger-history-item-value">{{ formatHistoryTime(item.inspectionTime) }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">创建时间</span>
<span class="device-ledger-history-item-value">{{ formatHistoryTime(item.createTime) }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">备注</span>
<span class="device-ledger-history-item-value">{{ item.remark ?? '-' }}</span>
</div>
<div v-if="item.images?.length" class="device-ledger-history-item-images">
<el-image
v-for="img in item.images"
:key="img"
:src="img"
:preview-src-list="item.images"
preview-teleported
fit="cover"
class="device-ledger-history-item-image"
>
<template #error>
<div class="device-ledger-history-image-error">图片加载失败</div>
</template>
</el-image>
</div>
</div>
</div>
</div>
</template>
</el-step>
</el-steps>
</el-tab-pane>
<el-tab-pane label="维修履历" name="repair">
<el-empty />
<el-empty v-if="!repairGroups.length" />
<el-collapse v-else v-model="repairActiveNames" class="device-ledger-repair-collapse">
<el-collapse-item v-for="group in repairGroups" :key="group.key" :name="group.key">
<template #title>
<div class="device-ledger-repair-title">
<span class="device-ledger-repair-name">{{ group.name }}</span>
<span class="device-ledger-repair-meta">{{ group.items.length }}</span>
</div>
</template>
<div class="device-ledger-history-items">
<div v-for="row in group.items" :key="String(row.id ?? row.subjectId ?? row.subjectCode)" class="device-ledger-history-item">
<div class="device-ledger-history-item-head">
<el-tag type="info" effect="light">{{ row.subjectCode ?? '-' }}</el-tag>
<span class="device-ledger-history-item-text">{{ row.subjectName ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-body">
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">维修单ID</span>
<span class="device-ledger-history-item-value">{{ row.repairId ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">项目内容</span>
<span class="device-ledger-history-item-value">{{ row.subjectContent ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">判定标准</span>
<span class="device-ledger-history-item-value">{{ row.subjectStandard ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">故障描述</span>
<span class="device-ledger-history-item-value">{{ row.malfunction ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">维修描述</span>
<span class="device-ledger-history-item-value">{{ row.repairDes ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">备注</span>
<span class="device-ledger-history-item-value">{{ row.remark ?? '-' }}</span>
</div>
<div class="device-ledger-history-item-row">
<span class="device-ledger-history-item-label">创建时间</span>
<span class="device-ledger-history-item-value">{{ formatHistoryTime(row.createTime) }}</span>
</div>
<div v-if="row.malfunctionImages?.length" class="device-ledger-history-item-images">
<el-image
v-for="img in row.malfunctionImages"
:key="img"
:src="img"
:preview-src-list="row.malfunctionImages"
preview-teleported
fit="cover"
class="device-ledger-history-item-image"
>
<template #error>
<div class="device-ledger-history-image-error">图片加载失败</div>
</template>
</el-image>
</div>
</div>
</div>
</div>
</el-collapse-item>
</el-collapse>
</el-tab-pane>
</el-tabs>
</ContentWrap>
@ -236,6 +381,151 @@ const handleSelectionChange = (rows: any[]) => {
const dictStore = useDictStoreWithOut()
const dictReady = ref(false)
const inspectionHistory = computed(() => {
return (detailData.value as any)?.inspectionList ?? []
})
const maintainHistory = computed(() => {
const list = (detailData.value as any)?.maintainList
return Array.isArray(list) ? list : []
})
const formatHistoryTime = (value: any) => {
const raw = value ?? '-'
if (Array.isArray(raw) && raw.length >= 3) {
const [y, m, d, hh, mm, ss] = raw
const pad = (n: any) => String(n).padStart(2, '0')
if (hh !== undefined) return `${y}-${pad(m)}-${pad(d)} ${pad(hh)}:${pad(mm)}:${pad(ss)}`
return `${y}-${pad(m)}-${pad(d)}`
}
return String(raw)
}
const getResultLabel = (value: any) => {
const v = value === '' || value === null || value === undefined ? undefined : String(value)
if (v === '0') return '待检测'
if (v === '1') return 'OK'
if (v === '2') return 'NG'
return '-'
}
const getResultTagType = (value: any) => {
const v = value === '' || value === null || value === undefined ? undefined : String(value)
if (v === '1') return 'success'
if (v === '2') return 'danger'
if (v === '0') return 'info'
return 'info'
}
type HistoryStepItem = {
key: string
name: string
result: any
method?: any
criteria?: any
images?: string[]
remark?: any
inspectionTime?: any
createTime?: any
}
type HistoryStepGroup = { key: string; time: string; operator: string; items: HistoryStepItem[] }
const buildStepGroups = (rows: any[], options: { timeField: string; nameFieldCandidates: string[]; resultFieldCandidates: string[] }) => {
const groups = new Map<string, HistoryStepGroup>()
for (const row of rows ?? []) {
const time = formatHistoryTime(row?.[options.timeField] ?? row?.createTime)
const operator = String(row?.creatorName ?? row?.creator ?? '-')
const groupKey = `${row?.managementId ?? ''}__${time}__${operator}`
const name =
options.nameFieldCandidates.map((k) => row?.[k]).find((v) => v !== undefined && v !== null && String(v).trim() !== '') ??
'-'
const result = options.resultFieldCandidates.map((k) => row?.[k]).find((v) => v !== undefined && v !== null) ?? undefined
const item: HistoryStepItem = {
key: String(row?.id ?? `${groupKey}__${String(name)}`),
name: String(name),
result,
method: row?.inspectionMethod,
criteria: row?.judgmentCriteria,
images: parseImages(row?.images),
remark: row?.remark,
inspectionTime: row?.inspectionTime,
createTime: row?.createTime
}
if (!groups.has(groupKey)) {
groups.set(groupKey, { key: groupKey, time, operator, items: [item] })
} else {
groups.get(groupKey)!.items.push(item)
}
}
return Array.from(groups.values()).sort((a, b) => String(b.time).localeCompare(String(a.time)))
}
const inspectionStepGroups = computed<HistoryStepGroup[]>(() => {
return buildStepGroups(inspectionHistory.value, {
timeField: 'inspectionTime',
nameFieldCandidates: ['inspectionItemName', 'name'],
resultFieldCandidates: ['inspectionResult']
})
})
const maintainStepGroups = computed<HistoryStepGroup[]>(() => {
return buildStepGroups(maintainHistory.value, {
timeField: 'inspectionTime',
nameFieldCandidates: ['maintainItemName', 'inspectionItemName', 'name'],
resultFieldCandidates: ['maintainResult', 'inspectionResult']
})
})
type RepairHistoryRow = {
id?: any
repairId?: any
subjectId?: any
subjectCode?: any
subjectName?: any
subjectContent?: any
subjectStandard?: any
malfunction?: any
malfunctionUrl?: any
repairDes?: any
remark?: any
createTime?: any
malfunctionImages?: string[]
}
type RepairHistoryGroup = { key: string; name: string; items: RepairHistoryRow[] }
const repairActiveNames = ref<string[]>([])
const repairGroups = computed<RepairHistoryGroup[]>(() => {
const raw = (detailData.value as any)?.repairList
if (!raw || typeof raw !== 'object') return []
const entries = Object.entries(raw as Record<string, any>)
const groups = entries
.map(([name, rows]) => {
const list = Array.isArray(rows) ? rows : []
return {
key: String(name),
name: String(name),
items: list.map((row: any) => ({
...row,
malfunctionImages: parseImages(row?.malfunctionUrl)
}))
} as RepairHistoryGroup
})
.filter((g) => g.items.length)
return groups.sort((a, b) => {
const at = formatHistoryTime(a.items?.[0]?.createTime)
const bt = formatHistoryTime(b.items?.[0]?.createTime)
return String(bt).localeCompare(String(at))
})
})
const tzStatusOptions = computed(() => {
if (!dictReady.value) return []
const options = getIntDictOptions('mes_tz_status')
@ -323,6 +613,20 @@ const formatDetailDate = (value: any) => {
return formatDate(new Date(value), 'YYYY-MM-DD')
}
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 parseFirstImage = (value: any): string => {
return parseImages(value)[0] || ''
}
const handleDetail = async (id: number) => {
if (detailVisible.value && selectedDetailId.value === id) {
closeDetail()
@ -334,6 +638,8 @@ const handleDetail = async (id: number) => {
detailLoading.value = true
try {
detailData.value = await DeviceLedgerApi.getDeviceLedger(id)
const keys = Object.keys(((detailData.value as any)?.repairList ?? {}) as any)
repairActiveNames.value = keys.length ? [keys[0]] : []
} finally {
detailLoading.value = false
}
@ -399,7 +705,7 @@ const handleDelete = async (ids: number | number[]) => {
tableRef.value?.clearSelection?.()
//
await getList()
} catch {}
} catch { }
}
const handleBatchDelete = async () => {
@ -465,4 +771,120 @@ onMounted(async () => {
font-size: 14px;
font-weight: 600;
}
.device-ledger-history-steps {
padding: 8px 8px 0;
}
.device-ledger-history-title {
display: flex;
align-items: center;
gap: 10px;
font-size: 13px;
}
.device-ledger-history-time {
font-weight: 600;
}
.device-ledger-history-operator {
color: var(--el-text-color-secondary);
}
.device-ledger-history-items {
display: flex;
flex-direction: column;
gap: 6px;
margin-top: 8px;
}
.device-ledger-history-item {
display: flex;
flex-direction: column;
gap: 8px;
padding: 10px;
border: 1px solid var(--el-border-color-lighter);
border-radius: 8px;
background: var(--el-fill-color-blank);
}
.device-ledger-history-item-head {
display: flex;
align-items: center;
gap: 10px;
}
.device-ledger-history-item-body {
display: flex;
flex-direction: column;
gap: 6px;
width: 100%;
}
.device-ledger-history-item-row {
display: flex;
gap: 10px;
}
.device-ledger-history-item-label {
width: 70px;
flex: 0 0 70px;
color: var(--el-text-color-secondary);
}
.device-ledger-history-item-value {
flex: 1;
color: var(--el-text-color-regular);
word-break: break-word;
}
.device-ledger-history-item-images {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 4px;
}
.device-ledger-history-item-image {
width: 76px;
height: 76px;
border-radius: 6px;
overflow: hidden;
}
.device-ledger-history-image-error {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
color: var(--el-text-color-secondary);
background: var(--el-fill-color);
}
.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 {
color: var(--el-text-color-secondary);
font-size: 12px;
}
.device-ledger-history-item-text {
color: var(--el-text-color-regular);
}
</style>

@ -1,102 +1,103 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="1200px">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="1200px" @closed="handleDialogClosed">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
<el-row>
<el-col :span="8">
<el-form-item label="维修单编号" prop="repairCode">
<el-input v-model="formData.repairCode" placeholder="请输入维修单编号" />
<el-input v-model="formData.repairCode" placeholder="请输入维修单编号" :disabled="isRepairMode" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="维修单" prop="repairName">
<el-input v-model="formData.repairName" placeholder="请输入维修单名称" />
<el-input v-model="formData.repairName" placeholder="请输入维修单名称" :disabled="isRepairMode" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="设备类型" prop="machineryTypeId">
<el-radio-group v-model="formData.machineryTypeId">
<el-radio
v-for="dict in getIntDictOptions(DICT_TYPE.MES_MACHINE_TYPE)"
:key="dict.value"
:label="dict.value"
>
{{ dict.label }}
</el-radio>
<el-radio-group v-model="formData.machineryTypeId" :disabled="isRepairMode">
<el-radio :label="1">设备</el-radio>
<el-radio :label="2">关键件</el-radio>
</el-radio-group>
</el-form-item>
<el-row>
<el-col :span="8">
<el-form-item label="设备ID" prop="machineryId">
<el-input v-model="formData.machineryId" placeholder="请输入设备ID" />
<el-form-item label="设备" prop="deviceId">
<el-select
v-model="formData.deviceId" filterable clearable :loading="deviceLoading"
:disabled="isRepairMode" placeholder="请选择设备" class="!w-full">
<el-option v-for="opt in deviceOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item label="设备编码" prop="machineryCode">
<el-input v-model="formData.machineryCode" placeholder="请输入设备编码" />
<el-form-item v-if="showComponentSelect" label="关键件" prop="componentId">
<el-select
v-model="formData.componentId" clearable :loading="componentLoading" :disabled="isRepairMode"
placeholder="请选择关键件" class="!w-full">
<el-option
v-for="opt in componentOptions" :key="String(opt.value)" :label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="设备名称" prop="machineryName">
<el-input v-model="formData.machineryName" placeholder="请输入设备名称" />
<el-form-item label="设备名称" prop="machineryName" :required="false">
<el-input v-model="formData.machineryName" placeholder="自动带出" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="规格型号" prop="machinerySpec">
<el-input v-model="formData.machinerySpec" placeholder="请输入规格型号" />
<el-form-item label="设备编码" prop="machineryCode" :required="false">
<el-input v-model="formData.machineryCode" placeholder="自动带出" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="维修人员" prop="acceptedBy">
<el-input v-model="formData.acceptedBy" placeholder="请输入维修人员" />
<el-form-item label="规格型号" prop="machinerySpec" :required="false">
<el-input v-model="formData.machinerySpec" placeholder="自动带出" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="验收人员" prop="confirmBy">
<el-input v-model="formData.confirmBy" placeholder="请输入验收人员" />
<el-form-item label="品牌" prop="machineryBrand" :required="false">
<el-input v-model="formData.machineryBrand" placeholder="自动带出" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="报修日期" prop="requireDate">
<el-date-picker
v-model="formData.requireDate"
type="date"
value-format="x"
placeholder="选择报修日期"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="完成日期" prop="finishDate">
<el-date-picker
v-model="formData.finishDate"
type="date"
value-format="x"
placeholder="选择完成日期"
/>
<el-form-item label="维修人员" prop="acceptedBy">
<el-select
v-model="formData.acceptedBy" filterable clearable placeholder="请选择维修人员" class="!w-full"
:disabled="isRepairMode">
<el-option v-for="item in users" :key="String(item.id)" :label="item.nickname" :value="String(item.id)" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="验收日期" prop="confirmDate">
<el-date-picker
v-model="formData.confirmDate"
type="date"
value-format="x"
placeholder="选择验收日期"
/>
<el-form-item label="验收人员" prop="confirmBy">
<el-select
v-model="formData.confirmBy" filterable clearable placeholder="请选择验收人员" class="!w-full"
:disabled="isRepairMode">
<el-option v-for="item in users" :key="String(item.id)" :label="item.nickname" :value="String(item.id)" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="维修结果" prop="repairResult">
<Editor v-model="formData.repairResult" height="150px" />
</el-form-item>
<template v-if="showRepairFields">
<el-row>
<el-col :span="8">
<el-form-item label="报修日期" prop="requireDate">
<el-date-picker v-model="formData.requireDate" type="date" value-format="x" placeholder="选择报修日期" class="!w-full" :disabled="repairFieldsDisabled" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="完成日期" prop="finishDate">
<el-date-picker v-model="formData.finishDate" type="date" value-format="x" placeholder="选择完成日期" class="!w-full" :disabled="repairFieldsDisabled" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="验收日期" prop="confirmDate">
<el-date-picker v-model="formData.confirmDate" type="date" value-format="x" placeholder="选择验收日期" class="!w-full" :disabled="repairFieldsDisabled" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="维修结果" prop="repairResult">
<Editor v-model="formData.repairResult" height="150px" :readonly="repairFieldsDisabled" />
</el-form-item>
</template>
</el-form>
<!-- 子表的表单 -->
<el-tabs v-model="subTabsName">
@ -111,9 +112,11 @@
</Dialog>
</template>
<script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, DICT_TYPE } from '@/utils/dict'
import { DvRepairApi, DvRepairVO } from '@/api/mes/dvrepair'
import DvRepairLineForm from './components/DvRepairLineForm.vue'
import { DeviceLedgerApi, DeviceLedgerVO } from '@/api/mes/deviceledger'
import { RepairItemsApi } from '@/api/mes/repairItems'
import { getSimpleUserList, UserVO } from '@/api/system/user'
/** 设备维修记录 表单 */
defineOptions({ name: 'DvRepairForm' })
@ -125,10 +128,17 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const isRepairMode = computed(() => formType.value === 'repair')
const showRepairFields = computed(() => formType.value === 'update' || formType.value === 'repair')
const repairFieldsDisabled = computed(() => formType.value !== 'repair')
const isHydrating = ref(false)
const emit = defineEmits(['success', 'closed']) // success
const formData = ref({
id: undefined,
repairCode: undefined,
repairName: undefined,
deviceId: undefined as number | undefined,
componentId: undefined as number | undefined,
machineryId: undefined,
machineryCode: undefined,
machineryName: undefined,
@ -144,6 +154,131 @@ const formData = ref({
status: undefined,
remark: undefined,
})
const showComponentSelect = computed(() => formData.value.machineryTypeId === 2)
const deviceLoading = ref(false)
const deviceOptions = ref<{ label: string; value: number; raw?: DeviceLedgerVO }[]>([])
const deviceOptionsLoaded = ref(false)
const componentLoading = ref(false)
const componentOptions = ref<{ label: string; value: number }[]>([])
const users = ref<UserVO[]>([])
const ensureUsersLoaded = async () => {
if (users.value.length) return
users.value = (await getSimpleUserList()) ?? []
}
const normalizeUserId = (value: any) => {
if (value === undefined || value === null || value === '') return undefined
const str = String(value)
if (/^\d+$/.test(str)) return str
const matched = users.value.find((u) => u.nickname === str)
return matched ? String(matched.id) : str
}
const upsertDeviceOption = (
options: { label: string; value: number; raw?: DeviceLedgerVO }[],
option: { label: string; value: number; raw?: DeviceLedgerVO }
) => {
const existed = options.some((o) => o.value === option.value)
return existed ? options : [option, ...options]
}
const toComponentOption = (item: any) => {
const id = typeof item?.id === 'number' ? item.id : Number(item?.id)
if (Number.isNaN(id)) return undefined
const code = item?.code ?? item?.componentCode ?? item?.subjectCode
const name = item?.name ?? item?.componentName ?? item?.subjectName
const label = `${code ?? ''} ${name ?? ''}`.trim() || String(id)
return { label, value: id }
}
const loadComponentOptionsByDeviceId = async (deviceId: number) => {
componentLoading.value = true
try {
const data = await RepairItemsApi.getComponentList(deviceId)
const rows = (Array.isArray(data) ? data : data?.list ?? data?.data ?? []) as any[]
componentOptions.value = rows.map(toComponentOption).filter(Boolean) as { label: string; value: number }[]
} finally {
componentLoading.value = false
}
}
const ensureDeviceOptionsLoaded = async () => {
if (deviceOptionsLoaded.value) return
deviceLoading.value = true
try {
const data = await DeviceLedgerApi.getDeviceLedgerPage({})
const rows = (data?.list ?? []) as DeviceLedgerVO[]
deviceOptions.value = rows
.filter((r) => typeof r?.id === 'number')
.map((r) => ({ label: `${r.deviceCode ?? ''} ${r.deviceName ?? ''}`.trim(), value: r.id, raw: r }))
deviceOptionsLoaded.value = true
} finally {
deviceLoading.value = false
}
}
watch(
() => formData.value.machineryTypeId,
(val) => {
if (isHydrating.value) return
formData.value.deviceId = undefined
formData.value.componentId = undefined
formData.value.machineryId = undefined
formData.value.machineryCode = undefined
formData.value.machineryName = undefined
formData.value.machineryBrand = undefined
formData.value.machinerySpec = undefined
componentOptions.value = []
setLineRows([])
}
)
watch(
() => formData.value.deviceId,
async (deviceId) => {
if (isHydrating.value) return
formData.value.componentId = undefined
componentOptions.value = []
if (typeof deviceId !== 'number') {
setLineRows([])
}
const option = deviceOptions.value.find((o) => o.value === deviceId)
if (option?.raw) {
formData.value.machineryCode = option.raw.deviceCode
formData.value.machineryName = option.raw.deviceName
formData.value.machinerySpec = option.raw.deviceSpec
formData.value.machineryBrand = option.raw.deviceBrand
}
if (formData.value.machineryTypeId === 2 && typeof deviceId === 'number') {
await loadComponentOptionsByDeviceId(deviceId)
}
if (formData.value.machineryTypeId === 1 && typeof deviceId === 'number') {
await prefillLinesByDeviceOrComponent({ deviceId, deviceType: 1 })
}
}
)
watch(
() => formData.value.componentId,
async (componentId) => {
if (isHydrating.value) return
if (formData.value.machineryTypeId !== 2) return
const deviceId = formData.value.deviceId
if (typeof deviceId !== 'number' || typeof componentId !== 'number') {
setLineRows([])
return
}
await prefillLinesByDeviceOrComponent({ deviceId, componentId, deviceType: 2 })
}
)
const formRules = reactive({
repairCode: [{ required: true, message: '维修单编号不能为空', trigger: 'blur' }],
machineryId: [{ required: true, message: '设备ID不能为空', trigger: 'blur' }],
@ -157,26 +292,106 @@ const formRef = ref() // 表单 Ref
const subTabsName = ref('dvRepairLine')
const dvRepairLineFormRef = ref()
const normalizeDeviceOrComponentList = (data: any) => {
const rows = (Array.isArray(data) ? data : data?.list ?? data?.data ?? []) as any[]
return rows
}
const toDvRepairLineRow = (item: any) => {
const subjectId = item?.subjectId ?? item?.id
return {
id: undefined,
repairId: formData.value.id,
subjectId,
subjectCode: item?.subjectCode ?? item?.subject_code ?? item?.code,
subjectName: item?.subjectName ?? item?.subject_name ?? item?.name,
subjectType: item?.subjectType ?? item?.subject_type ?? item?.type,
subjectContent: item?.subjectContent ?? item?.projectContent ?? item?.subject_content,
subjectStandard: item?.subjectStandard ?? item?.judgmentCriteria ?? item?.subject_standard,
malfunction: undefined,
malfunctionUrl: undefined,
repairDes: undefined,
remark: undefined
}
}
const setLineRows = (rows: any[]) => {
dvRepairLineFormRef.value?.setData(rows)
}
const prefillLinesByDeviceOrComponent = async (params: { deviceId: number; componentId?: number; deviceType: number }) => {
if (formType.value !== 'create') return
const data = await RepairItemsApi.getDeviceOrComponentList(params)
const list = normalizeDeviceOrComponentList(data)
setLineRows(list.map(toDvRepairLineRow))
}
let openRequestId = 0
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
const currentOpenId = ++openRequestId
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
dialogTitle.value = type === 'repair' ? '维修' : t('action.' + type)
formType.value = type
resetForm()
await ensureUsersLoaded()
await ensureDeviceOptionsLoaded()
if (currentOpenId !== openRequestId) return
//
if (id) {
formLoading.value = true
try {
isHydrating.value = true
formData.value = await DvRepairApi.getDvRepair(id)
if (currentOpenId !== openRequestId) return
;(formData.value as any).requireDate = (formData.value as any).requireDate ?? undefined
;(formData.value as any).finishDate = (formData.value as any).finishDate ?? undefined
;(formData.value as any).confirmDate = (formData.value as any).confirmDate ?? undefined
;(formData.value as any).repairResult = (formData.value as any).repairResult ?? ''
;(formData.value as any).acceptedBy = normalizeUserId((formData.value as any).acceptedBy)
;(formData.value as any).confirmBy = normalizeUserId((formData.value as any).confirmBy)
const typeId = typeof formData.value.machineryTypeId === 'number' ? formData.value.machineryTypeId : Number(formData.value.machineryTypeId)
formData.value.machineryTypeId = Number.isNaN(typeId) ? formData.value.machineryTypeId : typeId
const deviceId = (formData.value as any).deviceId
const resolvedDeviceId = typeof deviceId === 'number' ? deviceId : formData.value.machineryId
if (typeof resolvedDeviceId === 'number') {
formData.value.deviceId = resolvedDeviceId
const label = `${formData.value.machineryCode ?? ''} ${formData.value.machineryName ?? ''}`.trim() || `ID:${resolvedDeviceId}`
deviceOptions.value = upsertDeviceOption(deviceOptions.value, { label, value: resolvedDeviceId })
}
if (formData.value.machineryTypeId === 2 && typeof formData.value.deviceId === 'number') {
await loadComponentOptionsByDeviceId(formData.value.deviceId)
const componentId = (formData.value as any).componentId
const resolvedComponentId = typeof componentId === 'number' ? componentId : Number(componentId)
if (!Number.isNaN(resolvedComponentId)) {
formData.value.componentId = resolvedComponentId
}
}
} finally {
isHydrating.value = false
formLoading.value = false
}
}
}
defineExpose({ open }) // open
const handleDialogClosed = () => {
openRequestId++
emit('closed')
}
onBeforeUnmount(() => {
openRequestId++
})
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
@ -190,7 +405,17 @@ const submitForm = async () => {
//
formLoading.value = true
try {
const data = formData.value as unknown as DvRepairVO
const data = { ...(formData.value as any) } as DvRepairVO & { deviceId?: number; componentId?: number }
; (data as any).acceptedBy = normalizeUserId((data as any).acceptedBy)
; (data as any).confirmBy = normalizeUserId((data as any).confirmBy)
if (formType.value === 'repair') {
;(data as any).status = 1
}
if (typeof formData.value.deviceId === 'number') {
data.machineryId = formData.value.deviceId as any
}
; (data as any).deviceId = formData.value.deviceId
; (data as any).componentId = formData.value.machineryTypeId === 2 ? formData.value.componentId : undefined
//
data.dvRepairLines = dvRepairLineFormRef.value.getData()
if (formType.value === 'create') {
@ -214,21 +439,25 @@ const resetForm = () => {
id: undefined,
repairCode: undefined,
repairName: undefined,
deviceId: undefined,
componentId: undefined,
machineryId: undefined,
machineryCode: undefined,
machineryName: undefined,
machineryBrand: undefined,
machinerySpec: undefined,
machineryTypeId: undefined,
machineryTypeId: 1,
requireDate: undefined,
finishDate: undefined,
confirmDate: undefined,
repairResult: undefined,
repairResult: '',
acceptedBy: undefined,
confirmBy: undefined,
status: undefined,
remark: undefined,
}
deviceOptionsLoaded.value = false
componentOptions.value = []
formRef.value?.resetFields()
}
</script>

@ -9,13 +9,13 @@
>
<el-table :data="formData" class="-mt-10px">
<el-table-column label="序号" type="index" width="100" />
<el-table-column label="项目ID" min-width="150">
<!-- <el-table-column label="项目ID" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.subjectId`" :rules="formRules.subjectId" class="mb-0px!">
<el-input v-model="row.subjectId" placeholder="请输入项目ID" />
</el-form-item>
</template>
</el-table-column>
</el-table-column> -->
<el-table-column label="项目编码" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.subjectCode`" :rules="formRules.subjectCode" class="mb-0px!">
@ -30,13 +30,13 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column label="项目类型" min-width="150">
<!-- <el-table-column label="项目类型" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.subjectType`" :rules="formRules.subjectType" class="mb-0px!">
<el-input v-model="row.subjectType" placeholder="" />
</el-form-item>
</template>
</el-table-column>
</el-table-column> -->
<el-table-column label="项目内容" min-width="300">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.subjectContent`" :rules="formRules.subjectContent" class="mb-0px!">
@ -44,7 +44,7 @@
</el-form-item>
</template>
</el-table-column>
<el-table-column label="标准" min-width="150">
<!-- <el-table-column label="标准" min-width="150">
<template #default="{ row, $index }">
<el-form-item :prop="`${$index}.subjectStandard`" :rules="formRules.subjectStandard" class="mb-0px!">
<el-input v-model="row.subjectStandard" placeholder="" />
@ -78,12 +78,12 @@
<el-input v-model="row.remark" placeholder="" />
</el-form-item>
</template>
</el-table-column>
<el-table-column align="center" fixed="right" label="操作" width="60">
</el-table-column> -->
<!-- <el-table-column align="center" fixed="right" label="操作" width="60">
<template #default="{ $index }">
<el-button @click="handleDelete($index)" link></el-button>
</template>
</el-table-column>
</el-table-column> -->
</el-table>
</el-form>
<el-row justify="center" class="mt-3">
@ -161,5 +161,9 @@ const getData = () => {
return formData.value
}
defineExpose({ validate, getData })
const setData = (rows: any[]) => {
formData.value = Array.isArray(rows) ? rows : []
}
defineExpose({ validate, getData, setData })
</script>

@ -1,118 +1,69 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="维修单号" prop="repairCode">
<el-input
v-model="queryParams.repairCode"
placeholder="请输入维修单编号"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
v-model="queryParams.repairCode" placeholder="请输入维修单编号" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="维修单" prop="repairName">
<el-input
v-model="queryParams.repairName"
placeholder="请输入维修单名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
v-model="queryParams.repairName" placeholder="请输入维修单名称" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="设备名称" prop="machineryName">
<el-input
v-model="queryParams.machineryName"
placeholder="请输入设备名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
v-model="queryParams.machineryName" placeholder="请输入设备名称" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="报修日期" prop="requireDate">
<el-date-picker
v-model="queryParams.requireDate"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
v-model="queryParams.requireDate" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
start-placeholder="开始日期" end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item label="完成日期" prop="finishDate">
<el-date-picker
v-model="queryParams.finishDate"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
v-model="queryParams.finishDate" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
start-placeholder="开始日期" end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item label="验收日期" prop="confirmDate">
<el-date-picker
v-model="queryParams.confirmDate"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px"
/>
v-model="queryParams.confirmDate" value-format="YYYY-MM-DD HH:mm:ss" type="daterange"
start-placeholder="开始日期" end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" class="!w-240px" />
</el-form-item>
<el-form-item label="维修人员" prop="acceptedBy">
<el-input
v-model="queryParams.acceptedBy"
placeholder="请输入维修人员"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
v-model="queryParams.acceptedBy" placeholder="请输入维修人员" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="单据状态" prop="status">
<el-select
v-model="queryParams.status"
placeholder="请选择单据状态"
clearable
class="!w-240px"
>
<el-option
v-for="dict in getStrDictOptions(DICT_TYPE.MES_MOLD_RECORD_STATUS)"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
<el-select v-model="queryParams.status" placeholder="请选择单据状态" clearable class="!w-240px">
<el-option v-for="opt in statusOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</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:dv-repair:create']"
>
<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:dv-repair:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['mes:dv-repair:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['mes:dv-repair:export']"
>
type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['mes:dv-repair:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
@ -121,72 +72,49 @@
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column label="维修单号" align="center" prop="repairCode" />
<el-table-column label="维修单" align="center" prop="repairName" />
<el-table-column label="设备" align="center" prop="machineryName" />
<el-table-column label="设备编码" align="center" prop="machineryCode" />
<el-table-column label="品牌" align="center" prop="machineryBrand" />
<el-table-column label="规格型号" align="center" prop="machinerySpec" />
<el-table-column label="设备类型" align="center" prop="machineryTypeId">
<el-table-column label="设备类型" align="center" prop="machineryTypeId" width="100px">
<template #default="scope">
<dict-tag :type="DICT_TYPE.MES_MACHINE_TYPE" :value="scope.row.machineryTypeId" />
</template>
</el-table-column>
<el-table-column
label="报修日期"
align="center"
prop="requireDate"
:formatter="dateFormatter2"
width="180px"
/>
<el-table-column
label="完成日期"
align="center"
prop="finishDate"
:formatter="dateFormatter2"
width="180px"
/>
<el-table-column
label="验收日期"
align="center"
prop="confirmDate"
:formatter="dateFormatter2"
width="180px"
/>
<el-table-column label="报修日期" align="center" prop="requireDate" :formatter="dateFormatter2" width="110px" />
<el-table-column label="完成日期" align="center" prop="finishDate" :formatter="dateFormatter2" width="110px" />
<el-table-column label="验收日期" align="center" prop="confirmDate" :formatter="dateFormatter2" width="110px" />
<el-table-column label="维修结果" align="center" prop="repairResult" />
<el-table-column label="维修人员" align="center" prop="acceptedBy" />
<el-table-column label="验收人员" align="center" prop="confirmBy" />
<el-table-column label="单据状态" align="center" prop="status">
<el-table-column label="单据状态" align="center" prop="status" width="110px">
<template #default="scope">
<dict-tag :type="DICT_TYPE.MES_MOLD_RECORD_STATUS" :value="scope.row.status" />
<el-tag :type="getStatusTagType(scope.row.status)" effect="light">
{{ getStatusLabel(scope.row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<!-- <el-table-column label="备注" align="center" prop="remark" /> -->
<el-table-column
label="创建时间"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="170px"
fixed="right"
/>
<el-table-column label="操作" align="center" fixed="right">
label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="170px"
fixed="right" />
<el-table-column label="操作" align="center" fixed="right" width="200px">
<template #default="scope">
<el-button
link
type="primary"
@click="openForm('update', scope.row.id)"
v-hasPermi="['mes:dv-repair:update']"
>
link type="primary" @click="openForm('repair', scope.row.id)"
v-if="String(scope.row.status) !== '1'" v-hasPermi="['mes:dv-repair:update']">维修</el-button>
<el-button
link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['mes:dv-repair:update']">
编辑
</el-button>
<el-button
link
type="danger"
@click="handleDelete(scope.row.id)"
v-hasPermi="['mes:dv-repair:delete']"
>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:dv-repair:delete']">
删除
</el-button>
</template>
@ -194,20 +122,17 @@
</el-table>
<!-- 分页 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>
<!-- 表单弹窗添加/修改 -->
<DvRepairForm ref="formRef" @success="getList" />
<DvRepairForm v-if="formVisible" ref="formRef" @success="getList" @closed="formVisible = false" />
</template>
<script setup lang="ts">
import { getIntDictOptions, getStrDictOptions, DICT_TYPE } from '@/utils/dict'
import {dateFormatter, dateFormatter2} from '@/utils/formatTime'
import { DICT_TYPE } from '@/utils/dict'
import { dateFormatter, dateFormatter2 } from '@/utils/formatTime'
import download from '@/utils/download'
import { DvRepairApi, DvRepairVO } from '@/api/mes/dvrepair'
import DvRepairForm from './DvRepairForm.vue'
@ -245,6 +170,31 @@ const queryParams = reactive({
const queryFormRef = ref() //
const exportLoading = ref(false) //
const statusOptions = [
{ label: '待完成', value: '0' },
{ label: '已完成', value: '1' }
]
const getStatusLabel = (value: any) => {
const v = value === '' || value === null || value === undefined ? undefined : String(value)
if (v === '0') return '待完成'
if (v === '1') return '已完成'
return '-'
}
const getStatusTagType = (value: any) => {
const v = value === '' || value === null || value === undefined ? undefined : String(value)
if (v === '1') return 'success'
if (v === '0') return 'warning'
return 'info'
}
const tableRef = ref()
const selectedIds = ref<number[]>([])
const handleSelectionChange = (rows: any[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined) ?? []
}
/** 查询列表 */
const getList = async () => {
loading.value = true
@ -271,21 +221,40 @@ const resetQuery = () => {
/** 添加/修改操作 */
const formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
const formVisible = ref(false)
const openForm = async (type: string, id?: number) => {
formVisible.value = true
await nextTick()
formRef.value?.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
const buildIdsParam = (ids: number | number[]) => {
return Array.isArray(ids) ? ids.join(',') : String(ids)
}
const handleDelete = async (ids: number | number[]) => {
try {
//
await message.delConfirm()
//
await DvRepairApi.deleteDvRepair(id)
const idsParam = buildIdsParam(ids)
await DvRepairApi.deleteDvRepair(idsParam)
message.success(t('common.delSuccess'))
selectedIds.value = []
tableRef.value?.clearSelection?.()
//
await getList()
} catch {}
} catch { }
}
const handleBatchDelete = async () => {
if (!selectedIds.value.length) {
message.error('请选择需要删除的数据')
return
}
await handleDelete(selectedIds.value)
}
/** 导出按钮操作 */
@ -295,7 +264,13 @@ const handleExport = async () => {
await message.exportConfirm()
//
exportLoading.value = true
const data = await DvRepairApi.exportDvRepair(queryParams)
const data = await DvRepairApi.exportDvRepair(
selectedIds.value.length
? {
ids: selectedIds.value.join(',')
}
: queryParams
)
download.excel(data, '设备维修记录.xls')
} catch {
} finally {

@ -0,0 +1,307 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="900px">
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px" v-loading="formLoading">
<el-form-item label="项目编码" prop="subjectCode">
<el-input v-model="formData.subjectCode" placeholder="请输入项目编码" />
</el-form-item>
<el-form-item label="项目名称" prop="subjectName">
<el-input v-model="formData.subjectName" placeholder="请输入项目名称" />
</el-form-item>
<el-form-item label="设备类型" prop="deviceType">
<el-radio-group v-model="formData.deviceType">
<el-radio :label="1">设备</el-radio>
<el-radio :label="2">关键件</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="showDeviceSelect" label="设备" prop="deviceId">
<el-select
v-model="formData.deviceId"
filterable
remote
reserve-keyword
clearable
:remote-method="handleDeviceSearch"
:loading="deviceLoading"
placeholder="请选择设备"
class="!w-full"
>
<el-option v-for="opt in deviceOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item v-if="showComponentSelect" label="关键件" prop="componentId">
<el-select
v-model="formData.componentId"
clearable
:loading="componentLoading"
placeholder="请选择关键件"
class="!w-full"
>
<el-option v-for="opt in componentOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<!--
<el-form-item label="检验方式" prop="inspectionMethod">
<el-select v-model="formData.inspectionMethod" placeholder="请选择检验方式" clearable filterable class="!w-full">
<el-option v-for="dict in inspectionMethodOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="值类型" prop="valueType">
<el-select v-model="formData.valueType" placeholder="请选择值类型" clearable filterable class="!w-full">
<el-option v-for="dict in valueTypeOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="判定基准" prop="judgmentCriteria">
<el-input v-model="formData.judgmentCriteria" placeholder="请输入判定基准" type="textarea" />
</el-form-item>
-->
<el-form-item label="项目内容" prop="projectContent">
<el-input v-model="formData.projectContent" placeholder="请输入项目内容" type="textarea" />
</el-form-item>
<el-form-item label="是否启用" prop="isEnable">
<el-radio-group v-model="formData.isEnable">
<el-radio v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" :key="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 { getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
import { RepairItemsApi, RepairItemVO } from '@/api/mes/repairItems'
import { useDictStoreWithOut } from '@/store/modules/dict'
import { DeviceLedgerApi, DeviceLedgerVO } from '@/api/mes/deviceledger'
defineOptions({ name: 'RepairItemsForm' })
const { t } = useI18n()
const message = useMessage()
const dictStore = useDictStoreWithOut()
const dictReady = ref(false)
// const inspectionMethodOptions = computed(() => (dictReady.value ? getStrDictOptions('Inspection_method') : []))
// const valueTypeOptions = computed(() => (dictReady.value ? getStrDictOptions('value_types') : []))
const dialogVisible = ref(false)
const dialogTitle = ref('')
const formLoading = ref(false)
const formType = ref('')
const formRef = ref()
const formData = ref({
id: undefined as number | undefined,
subjectCode: undefined as string | undefined,
subjectName: undefined as string | undefined,
deviceType: undefined as number | undefined,
deviceId: undefined as number | undefined,
componentId: undefined as number | undefined,
inspectionMethod: undefined as string | undefined,
valueType: undefined as string | undefined,
judgmentCriteria: undefined as string | undefined,
projectContent: undefined as string | undefined,
isEnable: undefined as string | undefined
})
const showDeviceSelect = computed(() => formData.value.deviceType === 1 || formData.value.deviceType === 2)
const showComponentSelect = computed(() => formData.value.deviceType === 2)
const deviceLoading = ref(false)
const deviceOptions = ref<{ label: string; value: number }[]>([])
const componentLoading = ref(false)
const componentOptions = ref<{ label: string; value: number }[]>([])
const upsertOption = (options: { label: string; value: number }[], option: { label: string; value: number }) => {
const existed = options.some((o) => o.value === option.value)
return existed ? options : [option, ...options]
}
const handleDeviceSearch = async (keyword: string) => {
deviceLoading.value = true
try {
const data = await DeviceLedgerApi.getDeviceLedgerPage({
pageNo: 1,
pageSize: 50,
deviceCode: keyword || undefined,
deviceName: keyword || undefined
})
const rows = (data?.list ?? []) as DeviceLedgerVO[]
deviceOptions.value = rows
.filter((r) => typeof r?.id === 'number')
.map((r) => ({ label: `${r.deviceCode ?? ''} ${r.deviceName ?? ''}`.trim(), value: r.id }))
} finally {
deviceLoading.value = false
}
}
const toComponentOption = (item: any) => {
const id = typeof item?.id === 'number' ? item.id : Number(item?.id)
if (Number.isNaN(id)) return undefined
const code = item?.code ?? item?.componentCode ?? item?.subjectCode
const name = item?.name ?? item?.componentName ?? item?.subjectName
const label = `${code ?? ''} ${name ?? ''}`.trim() || String(id)
return { label, value: id }
}
const loadComponentOptionsByDeviceId = async (deviceId: number) => {
componentLoading.value = true
try {
const data = await RepairItemsApi.getComponentList(deviceId)
const rows = (Array.isArray(data) ? data : data?.list ?? data?.data ?? []) as any[]
componentOptions.value = rows.map(toComponentOption).filter(Boolean) as { label: string; value: number }[]
} finally {
componentLoading.value = false
}
}
watch(
() => formData.value.deviceType,
(val) => {
if (val === 1) {
formData.value.componentId = undefined
componentOptions.value = []
} else if (val !== 2) {
formData.value.deviceId = undefined
formData.value.componentId = undefined
componentOptions.value = []
}
}
)
watch(
() => formData.value.deviceId,
async (deviceId) => {
if (formData.value.deviceType !== 2) return
formData.value.componentId = undefined
componentOptions.value = []
if (typeof deviceId !== 'number') return
await loadComponentOptionsByDeviceId(deviceId)
}
)
const validateDeviceId = (_: any, value: any, callback: any) => {
const dt = formData.value.deviceType
if ((dt === 1 || dt === 2) && (value === undefined || value === null || value === '')) {
callback(new Error('设备不能为空'))
return
}
callback()
}
const validateComponentId = (_: any, value: any, callback: any) => {
const dt = formData.value.deviceType
if (dt === 2 && (value === undefined || value === null || value === '')) {
callback(new Error('关键件不能为空'))
return
}
callback()
}
const formRules = reactive({
subjectCode: [{ required: true, message: '项目编码不能为空', trigger: 'blur' }],
subjectName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
deviceType: [{ required: true, message: '设备类型不能为空', trigger: 'change' }],
deviceId: [{ validator: validateDeviceId, trigger: 'change' }],
componentId: [{ validator: validateComponentId, trigger: 'change' }],
isEnable: [{ required: true, message: '是否启用不能为空', trigger: 'change' }]
})
const open = async (type: string, row?: any) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
if (!dictReady.value) {
await dictStore.setDictMap()
dictReady.value = true
}
if (type === 'update' && row) {
formData.value = {
id: row.id,
subjectCode: row.subjectCode,
subjectName: row.subjectName,
deviceType: row.deviceType !== undefined && row.deviceType !== null ? Number(row.deviceType) : undefined,
deviceId: row.deviceId !== undefined && row.deviceId !== null ? Number(row.deviceId) : undefined,
componentId: row.componentId !== undefined && row.componentId !== null ? Number(row.componentId) : undefined,
inspectionMethod: row.inspectionMethod !== undefined && row.inspectionMethod !== null ? String(row.inspectionMethod) : undefined,
valueType: row.valueType !== undefined && row.valueType !== null ? String(row.valueType) : undefined,
judgmentCriteria: row.judgmentCriteria,
projectContent: row.projectContent,
isEnable: row.isEnable !== undefined && row.isEnable !== null ? String(row.isEnable) : undefined
}
if (typeof formData.value.deviceId === 'number') {
const label = row.deviceName ? String(row.deviceName) : `ID:${formData.value.deviceId}`
deviceOptions.value = upsertOption(deviceOptions.value, { label, value: formData.value.deviceId })
}
if (formData.value.deviceType === 2 && typeof formData.value.deviceId === 'number') {
await loadComponentOptionsByDeviceId(formData.value.deviceId)
if (typeof formData.value.componentId === 'number') {
const label = row.componentName ? String(row.componentName) : `ID:${formData.value.componentId}`
componentOptions.value = upsertOption(componentOptions.value, { label, value: formData.value.componentId })
}
}
}
}
defineExpose({ open })
const emit = defineEmits(['success'])
const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
try {
const data = {
id: formType.value === 'update' ? formData.value.id : undefined,
subjectCode: formData.value.subjectCode,
subjectName: formData.value.subjectName,
deviceType: formData.value.deviceType,
deviceId: formData.value.deviceId,
componentId: formData.value.componentId,
inspectionMethod: formData.value.inspectionMethod,
valueType: formData.value.valueType,
judgmentCriteria: formData.value.judgmentCriteria,
isEnable: formData.value.isEnable,
projectContent: formData.value.projectContent
} as unknown as RepairItemVO
if (formType.value === 'create') {
await RepairItemsApi.createRepairItem(data)
message.success(t('common.createSuccess'))
} else {
await RepairItemsApi.updateRepairItem(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
emit('success')
} finally {
formLoading.value = false
}
}
const resetForm = () => {
formData.value = {
id: undefined,
subjectCode: undefined,
subjectName: undefined,
deviceType: undefined,
deviceId: undefined,
componentId: undefined,
inspectionMethod: undefined,
valueType: undefined,
judgmentCriteria: undefined,
projectContent: undefined,
isEnable: undefined
}
deviceOptions.value = []
componentOptions.value = []
formRef.value?.resetFields()
}
</script>

@ -0,0 +1,251 @@
<template>
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="编码" prop="subjectCode">
<el-input v-model="queryParams.subjectCode" placeholder="请输入项目编码" clearable @keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item label="名称" prop="subjectName">
<el-input v-model="queryParams.subjectName" placeholder="请输入项目名称" clearable @keyup.enter="handleQuery" class="!w-240px" />
</el-form-item>
<el-form-item label="设备类型" prop="deviceType">
<el-select v-model="queryParams.deviceType" placeholder="请选择设备类型" clearable filterable class="!w-240px">
<el-option v-for="opt in deviceTypeOptions" :key="String(opt.value)" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<!--
<el-form-item label="检验方式" prop="inspectionMethod">
<el-select v-model="queryParams.inspectionMethod" placeholder="请选择检验方式" clearable filterable class="!w-240px">
<el-option v-for="dict in inspectionMethodOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="值类型" prop="valueType">
<el-select v-model="queryParams.valueType" placeholder="请选择值类型" clearable filterable class="!w-240px">
<el-option v-for="dict in valueTypeOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="判定基准" prop="judgmentCriteria">
<el-input
v-model="queryParams.judgmentCriteria"
placeholder="请输入判定基准"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
-->
<el-form-item label="项目内容" prop="projectContent">
<el-input
v-model="queryParams.projectContent"
placeholder="请输入项目内容"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
<el-date-picker
v-model="queryParams.createTime"
value-format="YYYY-MM-DD HH:mm:ss"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-220px"
/>
</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:repair-tems:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" :disabled="!selectedIds.length" v-hasPermi="['mes:repair-tems:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading" v-hasPermi="['mes:repair-tems:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<ContentWrap>
<el-table ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column label="编码" align="center" prop="subjectCode" min-width="130" :formatter="cellOrDash" />
<el-table-column label="名称" align="center" prop="subjectName" min-width="160" :formatter="cellOrDash" />
<el-table-column label="设备类型" align="center" prop="deviceType" min-width="140">
<template #default="scope">
<el-tag effect="light">{{ getDeviceTypeName(scope.row.deviceType) }}</el-tag>
</template>
</el-table-column>
<el-table-column label="设备名称" align="center" prop="deviceName" min-width="160" :formatter="cellOrDash" />
<el-table-column label="关键件名称" align="center" prop="componentName" min-width="160" :formatter="cellOrDash" />
<!--
<el-table-column label="检验方式" align="center" prop="inspectionMethod" width="120">
<template #default="scope">
<dict-tag type="Inspection_method" :value="scope.row.inspectionMethod" />
</template>
</el-table-column>
<el-table-column label="值类型" align="center" prop="valueType" width="120">
<template #default="scope">
<dict-tag type="value_types" :value="scope.row.valueType" />
</template>
</el-table-column>
<el-table-column label="判定基准" align="center" prop="judgmentCriteria" min-width="180" />
-->
<el-table-column label="项目内容" align="center" prop="projectContent" min-width="200" :formatter="cellOrDash" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateOrDash" width="180" />
<el-table-column label="操作" align="center" width="140" fixed="right">
<template #default="scope">
<el-button link type="primary" @click="openForm('update', scope.row)" v-hasPermi="['mes:repair-tems:update']"></el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:repair-tems: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>
<RepairItemsForm ref="formRef" @success="getList" />
</template>
<script setup lang="ts">
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { RepairItemsApi, RepairItemVO } from '@/api/mes/repairItems'
import RepairItemsForm from './RepairItemsForm.vue'
// import { getStrDictOptions } from '@/utils/dict'
// import { useDictStoreWithOut } from '@/store/modules/dict'
defineOptions({ name: 'RepairItems' })
const message = useMessage()
const { t } = useI18n()
// const dictStore = useDictStoreWithOut()
// const dictReady = ref(false)
// const inspectionMethodOptions = computed(() => (dictReady.value ? getStrDictOptions('Inspection_method') : []))
// const valueTypeOptions = computed(() => (dictReady.value ? getStrDictOptions('value_types') : []))
const loading = ref(true)
const list = ref<RepairItemVO[]>([])
const total = ref(0)
const exportLoading = ref(false)
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
subjectCode: undefined as string | undefined,
subjectName: undefined as string | undefined,
deviceType: undefined as number | undefined,
inspectionMethod: undefined as string | undefined,
valueType: undefined as string | undefined,
judgmentCriteria: undefined as string | undefined,
isEnable: undefined as string | undefined,
projectContent: undefined as string | undefined,
createTime: [] as string[]
})
const queryFormRef = ref()
const tableRef = ref()
const selectedIds = ref<number[]>([])
const formRef = ref()
const deviceTypeOptions = ref<{ label: string; value: number }[]>([
{ label: '设备', value: 1 },
{ label: '关键件', value: 2 }
])
const getDeviceTypeName = (value: any) => {
if (value === undefined || value === null || value === '') return '-'
const v = typeof value === 'number' ? value : Number(value)
if (v === 1) return '设备'
if (v === 2) return '关键件'
return String(value)
}
const cellOrDash = (_row: any, _column: any, cellValue: any) => {
if (cellValue === undefined || cellValue === null || cellValue === '') return '-'
return String(cellValue)
}
const dateOrDash = (row: any, column: any, cellValue: any) => {
const text = dateFormatter(row, column, cellValue)
if (text === undefined || text === null || text === '') return '-'
return String(text)
}
const getList = async () => {
loading.value = true
try {
const data = await RepairItemsApi.getRepairItemsPage(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: any[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined) ?? []
}
const openForm = (type: string, row?: any) => {
formRef.value.open(type, row)
}
const buildIdsParam = (ids: number | number[]) => {
return Array.isArray(ids) ? ids.join(',') : String(ids)
}
const handleDelete = async (ids: number | number[]) => {
try {
await message.delConfirm()
await RepairItemsApi.deleteRepairItems(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 () => {
try {
await message.exportConfirm()
exportLoading.value = true
const params = {
...queryParams,
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await RepairItemsApi.exportRepairItems(params)
download.excel(data, '维修项目.xls')
} catch {
} finally {
exportLoading.value = false
}
}
onMounted(async () => {
await getList()
})
</script>

@ -1,15 +1,13 @@
<template>
<Dialog v-model="dialogVisible" :title="dialogTitle" width="1100px">
<el-table
v-loading="loading"
:data="list"
:stripe="true"
:show-overflow-tooltip="true"
:row-key="getRowKey"
>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" :row-key="getRowKey">
<el-table-column type="index" label="序号" align="center" width="70" />
<el-table-column label="检验项名称" align="center" prop="inspectionItemName" min-width="180" />
<el-table-column label="检验方式" align="center" prop="inspectionMethod" min-width="140" />
<el-table-column label="检验方式" align="center" prop="inspectionMethod" min-width="140">
<template #default="scope">
<dict-tag type="Inspection_method" :value="scope.row.inspectionMethod" />
</template>
</el-table-column>
<el-table-column label="判定基准" align="center" prop="judgmentCriteria" min-width="160" />
<el-table-column label="检验结果" align="center" prop="inspectionResult" width="120">
<template #default="scope">
@ -21,24 +19,20 @@
</el-table-column>
<el-table-column label="图片" align="center" prop="images" width="160">
<template #default="scope">
<UploadImg
v-if="String(scope.row.inspectionResult) === '0'" v-model="imageMap[String(scope.row.id)]"
:drag="false" :show-btn-text="false" width="64px" height="64px" />
<el-image
v-if="scope.row.images"
:src="parseFirstImage(scope.row.images)"
:preview-src-list="parseImages(scope.row.images)"
preview-teleported
fit="cover"
style="width: 64px; height: 64px"
/>
v-else-if="scope.row.images" :src="parseFirstImage(scope.row.images)"
:preview-src-list="parseImages(scope.row.images)" preview-teleported fit="cover"
style="width: 64px; height: 64px" />
<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" width="200" fixed="right">
<template #default="scope">
<el-radio-group
v-if="String(scope.row.inspectionResult) === '0'"
v-model="decisionMap[String(scope.row.id)]"
>
<el-radio-group v-if="String(scope.row.inspectionResult) === '0'" v-model="decisionMap[String(scope.row.id)]">
<el-radio :label="'1'">通过</el-radio>
<el-radio :label="'2'">不通过</el-radio>
</el-radio-group>
@ -48,18 +42,10 @@
</el-table>
<el-pagination
v-show="total > 0"
v-model:current-page="queryParams.pageNo"
v-model:page-size="queryParams.pageSize"
:background="true"
:page-sizes="[10, 20, 30, 50, 100]"
:pager-count="7"
:total="total"
class="mt-15px mb-15px flex justify-end"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
v-show="total > 0" v-model:current-page="queryParams.pageNo" v-model:page-size="queryParams.pageSize"
:background="true" :page-sizes="[10, 20, 30, 50, 100]" :pager-count="7" :total="total"
class="mt-15px mb-15px flex justify-end" layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange" @current-change="handleCurrentChange" />
<template #footer>
<el-button @click="dialogVisible = false"> </el-button>
@ -84,6 +70,7 @@ const list = ref<TicketResultVO[]>([])
const total = ref(0)
const managementId = ref<number | undefined>(undefined)
const decisionMap = reactive<Record<string, '1' | '2' | undefined>>({})
const imageMap = reactive<Record<string, string>>({})
const queryParams = reactive({
pageNo: 1,
@ -94,6 +81,8 @@ const open = async (options: { managementId: number; title?: string }) => {
dialogVisible.value = true
dialogTitle.value = options.title || '检验结果'
managementId.value = options.managementId
for (const key of Object.keys(decisionMap)) delete decisionMap[key]
for (const key of Object.keys(imageMap)) delete imageMap[key]
queryParams.pageNo = 1
await getList()
}
@ -111,6 +100,14 @@ const getList = async () => {
})
list.value = data.list
total.value = data.total
for (const row of list.value) {
const id = row?.id
if (!id) continue
if (row.images && !imageMap[String(id)]) {
imageMap[String(id)] = parseFirstImage(row.images)
}
}
} finally {
loading.value = false
}
@ -132,7 +129,8 @@ const handleSave = async () => {
if (String(row.inspectionResult) !== '0') continue
const decision = decisionMap[String(row.id)]
if (!decision) continue
payload.push({ ...(row as any), inspectionResult: decision })
const img = imageMap[String(row.id)]
payload.push({ ...(row as any), inspectionResult: decision, images: img || row.images })
}
if (!payload.length) {
message.error('请先为待检测记录选择通过或不通过')
@ -142,7 +140,7 @@ const handleSave = async () => {
try {
await TicketManagementApi.batchUpdateTicketResults(payload)
message.success('更新成功')
await getList()
dialogVisible.value = false
} catch {
message.error('更新失败')
} finally {
@ -167,3 +165,9 @@ const parseFirstImage = (value: any): string => {
return parseImages(value)[0] || ''
}
</script>
<style scoped lang="scss">
:deep(.el-upload) {
margin: 0 auto;
}
</style>

@ -2,7 +2,8 @@
<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"
<el-input
v-model="queryParams.planNo" placeholder="请输入单号" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="类型" prop="planType">
@ -12,7 +13,8 @@
</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"
<el-option
v-for="opt in getStrDictOptions('job_status')" :key="String(opt.value)" :label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
@ -34,13 +36,15 @@
<ContentWrap>
<div class="mb-10px">
<el-button type="warning" plain @click="handleBatchCancel" :disabled="!selectedIds.length"
<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"
<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" />
@ -73,7 +77,8 @@
<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
:total="total" v-model:page="queryParams.pageNo" v-model:limit="queryParams.pageSize"
@pagination="getList" />
</ContentWrap>

@ -0,0 +1,151 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="800px">
<el-form
ref="formRef"
:model="formData"
:rules="formRules"
label-width="100px"
v-loading="formLoading"
>
<el-form-item label="项目编码" prop="subjectCode">
<el-input v-model="formData.subjectCode" placeholder="请输入项目编码" />
</el-form-item>
<el-form-item label="项目名称" prop="subjectName">
<el-input v-model="formData.subjectName" placeholder="请输入项目名称" />
</el-form-item>
<el-form-item label="检验方式" prop="inspectionMethod">
<el-select v-model="formData.inspectionMethod" placeholder="请选择检验方式" clearable filterable class="!w-full">
<el-option v-for="dict in inspectionMethodOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="值类型" prop="valueType">
<el-select v-model="formData.valueType" placeholder="请选择值类型" clearable filterable class="!w-full">
<el-option v-for="dict in valueTypeOptions" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item label="判定基准" prop="judgmentCriteria">
<el-input v-model="formData.judgmentCriteria" placeholder="请输入判定基准" type="textarea" />
</el-form-item>
<el-form-item label="是否启用" prop="isEnable">
<el-radio-group v-model="formData.isEnable">
<el-radio v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" :key="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 { getBoolDictOptions, getStrDictOptions, DICT_TYPE } from '@/utils/dict'
import { DvSubjectApi, DvSubjectVO } from '@/api/mes/dvsubject'
import { useDictStoreWithOut } from '@/store/modules/dict'
/** 维保项目 表单 */
defineOptions({ name: 'MoldInspectionItemsForm' })
const { t } = useI18n() //
const message = useMessage() //
const dictStore = useDictStoreWithOut()
const dictReady = ref(false)
const inspectionMethodOptions = computed(() => (dictReady.value ? getStrDictOptions('Inspection_method') : []))
const valueTypeOptions = computed(() => (dictReady.value ? getStrDictOptions('value_types') : []))
const dialogVisible = ref(false) //
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
id: undefined,
subjectCode: undefined,
subjectName: undefined,
isEnable: undefined,
inspectionMethod: undefined,
valueType: undefined,
judgmentCriteria: undefined,
})
const formRules = reactive({
subjectCode: [{ required: true, message: '项目编码不能为空', trigger: 'blur' }],
subjectName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
inspectionMethod: [{ required: true, message: '检验方式不能为空', trigger: 'change' }],
valueType: [{ required: true, message: '值类型不能为空', trigger: 'change' }],
judgmentCriteria: [{ required: true, message: '判定基准不能为空', trigger: 'blur' }],
isEnable: [{ required: true, message: '是否启用不能为空', trigger: 'change' }],
})
const formRef = ref() // Ref
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
if (!dictReady.value) {
await dictStore.setDictMap()
dictReady.value = true
}
//
if (id) {
formLoading.value = true
try {
formData.value = await DvSubjectApi.getDvSubject(id)
} finally {
formLoading.value = false
}
}
}
defineExpose({ open }) // open
/** 提交表单 */
const emit = defineEmits(['success']) // success
const submitForm = async () => {
//
await formRef.value.validate()
//
formLoading.value = true
try {
const data = {
id: formType.value === 'update' ? formData.value.id : undefined,
subjectCode: formData.value.subjectCode,
subjectName: formData.value.subjectName,
isEnable: formData.value.isEnable,
inspectionMethod: formData.value.inspectionMethod,
valueType: formData.value.valueType,
judgmentCriteria: formData.value.judgmentCriteria
} as unknown as DvSubjectVO
if (formType.value === 'create') {
await DvSubjectApi.createDvSubject(data)
message.success(t('common.createSuccess'))
} else {
await DvSubjectApi.updateDvSubject(data)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
//
emit('success')
} finally {
formLoading.value = false
}
}
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
subjectCode: undefined,
subjectName: undefined,
isEnable: undefined,
inspectionMethod: undefined,
valueType: undefined,
judgmentCriteria: undefined,
}
formRef.value?.resetFields()
}
</script>

@ -0,0 +1,252 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="编码" prop="subjectCode">
<el-input
v-model="queryParams.subjectCode" placeholder="请输入编码" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="名称" prop="subjectName">
<el-input
v-model="queryParams.subjectName" placeholder="请输入名称" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="判定基准" prop="judgmentCriteria">
<el-input
v-model="queryParams.judgmentCriteria" 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:dv-subject:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['mes:dv-subject:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
</el-button>
<el-button
type="success" plain @click="handleExport" :loading="exportLoading"
v-hasPermi="['mes:dv-subject:export']">
<Icon icon="ep:download" class="mr-5px" /> 导出
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<!-- 列表 -->
<ContentWrap>
<el-table
ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true" row-key="id"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" fixed="left" reserve-selection />
<el-table-column label="序号" align="center" width="80" fixed="left">
<template #default="scope">
{{ (queryParams.pageNo - 1) * queryParams.pageSize + scope.$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="120px">
<template #default="scope">
<el-tag
effect="light" :type="getTagType('Inspection_method', scope.row.inspectionMethod)"
:color="getTagColor('Inspection_method', scope.row.inspectionMethod)"
:style="getTagStyle('Inspection_method', scope.row.inspectionMethod)" disable-transitions>
{{ getTagLabel('Inspection_method', scope.row.inspectionMethod) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="值类型" align="center" prop="valueType" width="120px">
<template #default="scope">
<el-tag
effect="light" :type="getTagType('value_types', scope.row.valueType)"
:color="getTagColor('value_types', scope.row.valueType)"
:style="getTagStyle('value_types', scope.row.valueType)" disable-transitions>
{{ getTagLabel('value_types', scope.row.valueType) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="判定基准" align="center" prop="judgmentCriteria" />
<el-table-column label="创建人" align="center" prop="creatorName" />
<el-table-column label="创建时间" align="center" prop="createTime" :formatter="dateFormatter" width="180px" />
<el-table-column label="操作" align="center" fixed="right" width="160px">
<template #default="scope">
<el-button
link type="primary" @click="openForm('update', scope.row.id)"
v-hasPermi="['mes:dv-subject:update']">
编辑
</el-button>
<el-button link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:dv-subject: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>
<!-- 表单弹窗添加/修改 -->
<InspectionItemsForm 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 { DvSubjectApi, DvSubjectVO } from '@/api/mes/dvsubject'
import InspectionItemsForm from './InspectionItemsForm.vue'
import { isHexColor } from '@/utils/color'
import { useDictStoreWithOut } from '@/store/modules/dict'
/** 维保项目 列表 */
defineOptions({ name: 'MoldInspectionItems' })
const message = useMessage() //
const { t } = useI18n() //
const dictStore = useDictStoreWithOut()
const dictReady = ref(false)
const loading = ref(true) //
const list = ref<DvSubjectVO[]>([]) //
const total = ref(0) //
const tableRef = ref()
const selectedIds = ref<number[]>([])
const handleSelectionChange = (rows: any[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined) ?? []
}
const buildIdsParam = (ids: number | number[]) => {
return Array.isArray(ids) ? ids.join(',') : String(ids)
}
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
subjectCode: undefined,
subjectName: undefined,
judgmentCriteria: undefined,
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
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 getList = async () => {
loading.value = true
try {
const data = await DvSubjectApi.getDvSubjectPage(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 formRef = ref()
const openForm = (type: string, id?: number) => {
formRef.value.open(type, id)
}
/** 删除按钮操作 */
const handleDelete = async (ids: number | number[]) => {
try {
//
await message.delConfirm()
//
const idsParam = buildIdsParam(ids)
await DvSubjectApi.deleteDvSubject(idsParam)
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 DvSubjectApi.exportDvSubject({ 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,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…
Cancel
Save