kkk-ops 2 months ago
commit a455acdd33

@ -8,7 +8,8 @@ VITE_DEV=true
# 线上环境
# VITE_BASE_URL='https://besure.ngsk.tech:7001'
# 本地联调
VITE_BASE_URL='http://192.168.5.113:48081'
VITE_BASE_URL='http://192.168.5.107:48081'
# VITE_BASE_URL='http://192.168.5.135:48081'
# 文件上传类型server - 后端上传, client - 前端直连上传,仅支持 S3 服务

@ -177,6 +177,10 @@ export const RecipeConfigApi = {
return await request.get({ url: `/iot/recipe-device-attribute/page`, params })
},
updateRecipeDeviceAttribute: async (data: { recipeId: string | number; ids: number[] }) => {
return await request.put({ url: `/iot/recipe-device-attribute/update`, data })
},
saveRecipePointConfig: async (data: { recipeId: string | number; attributeIds: number[] }) => {
ensureMockSeeded()
await sleep(120)

@ -17,9 +17,8 @@ export interface DeviceLedgerVO {
deviceLocation: string // 设备位置
useDept?: string // 使用部门
deviceManager: string // 设备负责人
quantity?: number // 数量
productionDate: Date // 设备生产日期
factoryEntryDate: Date // 设备入厂日期
productionDate: string | number | Date // 设备生产日期
factoryEntryDate: string | number | Date // 设备入厂日期
deviceRemark: string // 设备备注
remark: string // 备注
creator?: string // 创建人
@ -51,8 +50,8 @@ export const DeviceLedgerApi = {
},
// 删除设备类型
deleteDeviceLedger: async (id: number) => {
return await request.delete({ url: `/mes/device-ledger/delete?id=` + id })
deleteDeviceLedger: async (ids: string) => {
return await request.delete({ url: `/mes/device-ledger/delete?ids=` + ids })
},
// 导出设备类型 Excel

@ -2,13 +2,18 @@ import request from '@/config/axios'
// 维保项目 VO
export interface DvSubjectVO {
id: number // ID
id?: number // ID
subjectCode: string // 项目编码
subjectName: string // 项目名称
subjectType: string // 项目类型
subjectContent: string // 项目内容
subjectStandard: string // 标准
isEnable: boolean // 是否启用
subjectType?: string // 项目类型
subjectContent?: string // 项目内容
subjectStandard?: string // 标准
isEnable: string // 是否启用
inspectionMethod: string // 检验方式
valueType: string // 值类型
judgmentCriteria: string // 判定基准
creator?: string // 创建人
createTime?: string | number | Date // 创建时间
}
// 维保项目 API
@ -34,8 +39,8 @@ export const DvSubjectApi = {
},
// 删除维保项目
deleteDvSubject: async (id: number) => {
return await request.delete({ url: `/mes/dv-subject/delete?id=` + id })
deleteDvSubject: async (ids: string) => {
return await request.delete({ url: `/mes/dv-subject/delete?ids=` + ids })
},
// 导出维保项目 Excel

@ -0,0 +1,47 @@
import request from '@/config/axios'
export interface PlanMaintenanceVO {
id?: number | string
planName: string
planType: number | string
description?: string
subjectIdS?: string
creator?: string
creatorName?: string
createTime?: string | number | Date
updateTime?: string | number | Date
}
export interface PlanMaintenanceSubjectVO {
id?: number | string
subjectCode?: string
subjectName?: string
inspectionMethod?: string
judgmentCriteria?: string
}
export const PlanMaintenanceApi = {
getPlanMaintenancePage: async (params: any) => {
return await request.get({ url: `/mes/plan-maintenance/page`, params })
},
getSubjectList: async (id: number | string) => {
return await request.get({ url: `/mes/plan-maintenance/getSubjectList`, params: { id } })
},
createPlanMaintenance: async (data: any) => {
return await request.post({ url: `/mes/plan-maintenance/create`, data })
},
updatePlanMaintenance: async (data: any) => {
return await request.put({ url: `/mes/plan-maintenance/update`, params: data })
},
deletePlanMaintenance: async (ids: string) => {
return await request.delete({ url: `/mes/plan-maintenance/delete?ids=` + ids })
},
exportPlanMaintenance: async (params: any) => {
return await request.download({ url: `/mes/plan-maintenance/export-excel`, params })
}
}

@ -0,0 +1,44 @@
import request from '@/config/axios'
export interface TaskManagementVO {
id?: number
name?: string
taskType?: number
deviceList?: string
projectForm?: string
startDate?: string
endDate?: string
cronExpression?: string
operableUsers?: string
enabled?: boolean
execFrequency?: string
frequencyValue?: string
time?: string
validMinutes?: number
creator?: string
createTime?: string
updateTime?: string
}
export const TaskManagementApi = {
getTaskManagementPage: async (params: any) => {
return await request.get({ url: `/mes/task-management/page`, params })
},
createTaskManagement: async (data: TaskManagementVO) => {
return await request.post({ url: `/mes/task-management/create`, data })
},
updateTaskManagement: async (data: TaskManagementVO) => {
return await request.put({ url: `/mes/task-management/update`, data })
},
deleteTaskManagement: async (ids: string) => {
return await request.delete({ url: `/mes/task-management/delete?ids=` + ids })
},
exportTaskManagement: async (params: any) => {
return await request.download({ url: `/mes/task-management/export-excel`, params })
}
}

@ -21,6 +21,9 @@ v-model="queryParams.productName" placeholder="请输入产品名称" clearable
<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="openDialog('create')">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
@ -49,7 +52,7 @@ ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-to
<el-table-column label="操作" align="center" width="240px" fixed="right">
<template #default="scope">
<el-button link type="primary" @click.stop="openDetail(scope.row)">配置</el-button>
<el-button link type="warning" @click.stop="openDialog('update', scope.row)">编辑</el-button>
<el-button link type="primary" @click.stop="openDialog('update', scope.row)">编辑</el-button>
<el-button link type="danger" @click.stop="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
@ -60,15 +63,9 @@ ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-to
</ContentWrap>
<RecipeDetailList
ref="detailRef"
:visible="detailVisible"
:recipe-id="detailMeta.recipeCode"
:manual-recipe-id="detailMeta.id"
:recipe-code="detailMeta.recipeCode"
:name="detailMeta.name"
@config="handleDetailConfig"
@close="closeDetail"
/>
ref="detailRef" :visible="detailVisible"
:recipe-id="detailMeta.id ? String(detailMeta.id) : undefined" :manual-recipe-id="detailMeta.id"
:recipe-code="detailMeta.recipeCode" :name="detailMeta.name" @config="handleDetailConfig" @close="closeDetail" />
<Dialog :title="dialogTitle" v-model="dialogVisible" width="720px">
<el-form ref="dialogFormRef" :model="dialogForm" :rules="dialogRules" label-width="100px" v-loading="dialogLoading">
@ -111,9 +108,59 @@ v-model="dialogForm.machineName" placeholder="请选择关联设备" clearable f
<Dialog title="配置" v-model="configVisible" width="920px">
<div v-loading="configLoading">
<el-transfer
class="formula-config-transfer" v-model="configSelectedKeys" :data="configCandidates" filterable
:titles="['来源', '目标']" />
<div class="formula-config-picklist">
<div class="formula-config-panel">
<div class="formula-config-panel__header">
<div>来源</div>
<div class="formula-config-panel__meta">{{ filteredSourceItems.length }}</div>
</div>
<div class="formula-config-panel__filter">
<el-input v-model="sourceKeyword" placeholder="筛选" clearable />
</div>
<el-table
class="formula-config-panel__table"
:data="filteredSourceItems"
height="440"
:show-header="false"
row-key="key"
@selection-change="handleSourceSelectionChange"
:row-class-name="getSourceRowClass"
>
<el-table-column type="selection" width="44" :selectable="isSourceSelectable" />
<el-table-column prop="label" />
</el-table>
</div>
<div class="formula-config-actions">
<el-button type="primary" :disabled="!sourceCheckedKeys.length" @click="addToTarget">
&gt;&gt;
</el-button>
<el-button :disabled="!targetCheckedKeys.length" @click="removeFromTarget">
&lt;&lt;
</el-button>
</div>
<div class="formula-config-panel">
<div class="formula-config-panel__header">
<div>目标</div>
<div class="formula-config-panel__meta">{{ filteredTargetItems.length }}</div>
</div>
<div class="formula-config-panel__filter">
<el-input v-model="targetKeyword" placeholder="筛选" clearable />
</div>
<el-table
class="formula-config-panel__table"
:data="filteredTargetItems"
height="440"
:show-header="false"
row-key="key"
@selection-change="handleTargetSelectionChange"
>
<el-table-column type="selection" width="44" />
<el-table-column prop="label" />
</el-table>
</div>
</div>
</div>
<template #footer>
<el-button @click="configVisible = false"> </el-button>
@ -138,6 +185,7 @@ const message = useMessage()
const { t } = useI18n()
const loading = ref(false)
const queryFormRef = ref()
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
@ -184,6 +232,11 @@ const handleQuery = () => {
getList()
}
const resetQuery = () => {
queryFormRef.value?.resetFields?.()
handleQuery()
}
const handlePagination = () => {
getList()
}
@ -342,19 +395,23 @@ const detailVisible = ref(false)
const detailMeta = reactive({
id: undefined as number | undefined,
recipeCode: '',
name: ''
name: '',
deviceId: undefined as number | undefined,
machineName: ''
})
const openDetail = async (row: RecipeConfigVO) => {
detailMeta.id = row.id
detailMeta.recipeCode = row.recipeCode
detailMeta.name = row.name ?? row.recipeName ?? ''
detailMeta.deviceId = row.deviceId
detailMeta.machineName = row.machineName ?? row.deviceName ?? ''
detailVisible.value = true
}
const handleDetailConfig = () => {
if (!detailMeta.recipeCode) return
openConfigDialog(detailMeta.recipeCode)
if (!detailMeta.id) return
openConfigDialog(detailMeta.id)
}
const handleRowClick = async (row: RecipeConfigVO, column: any) => {
@ -374,34 +431,136 @@ type TransferItem = { key: number; label: string; disabled?: boolean }
const configVisible = ref(false)
const configLoading = ref(false)
const configRecipeId = ref<string | undefined>(undefined)
const configRecipeId = ref<string | number | undefined>(undefined)
const configCandidates = ref<TransferItem[]>([])
const configSelectedKeys = ref<number[]>([])
const configSelectedItems = ref<TransferItem[]>([])
const sourceKeyword = ref('')
const targetKeyword = ref('')
const sourceCheckedKeys = ref<number[]>([])
const targetCheckedKeys = ref<number[]>([])
const configDeviceLabel = computed(() => {
const name = detailMeta.machineName?.trim()
if (name) return name
if (detailMeta.deviceId !== undefined && detailMeta.deviceId !== null) return String(detailMeta.deviceId)
return '-'
})
const normalizeKey = (value: any): number | undefined => {
if (value === null || value === undefined || value === '') return undefined
const n = Number(value)
if (Number.isNaN(n)) return undefined
return n
}
const selectedKeySet = computed(() => {
return new Set<number>(configSelectedKeys.value ?? [])
})
const contains = (text: string, keyword: string) => {
const k = (keyword ?? '').trim().toLowerCase()
if (!k) return true
return (text ?? '').toLowerCase().includes(k)
}
const filteredSourceItems = computed(() => {
return (configCandidates.value ?? []).filter((it) => contains(it.label, sourceKeyword.value))
})
const filteredTargetItems = computed(() => {
const set = selectedKeySet.value
return (configCandidates.value ?? [])
.filter((it) => set.has(it.key))
.filter((it) => contains(it.label, targetKeyword.value))
})
const isSourceSelectable = (row: TransferItem) => {
return !selectedKeySet.value.has(row.key)
}
const getSourceRowClass = ({ row }: { row: TransferItem }) => {
return selectedKeySet.value.has(row.key) ? 'formula-config-row--disabled' : ''
}
const openConfigDialog = async (recipeCode: string) => {
const handleSourceSelectionChange = (rows: TransferItem[]) => {
sourceCheckedKeys.value = (rows ?? []).map((r) => r.key)
}
const handleTargetSelectionChange = (rows: TransferItem[]) => {
targetCheckedKeys.value = (rows ?? []).map((r) => r.key)
}
const addToTarget = () => {
const next = new Set<number>(configSelectedKeys.value ?? [])
for (const key of sourceCheckedKeys.value ?? []) next.add(key)
configSelectedKeys.value = Array.from(next.values())
sourceCheckedKeys.value = []
}
const removeFromTarget = () => {
const toRemove = new Set<number>(targetCheckedKeys.value ?? [])
configSelectedKeys.value = (configSelectedKeys.value ?? []).filter((k) => !toRemove.has(k))
targetCheckedKeys.value = []
}
const buildTransferLabel = (item: any) => {
return `${item.attributeName ?? item.pointName ?? ''}${item.attributeType || item.pointType ? '' + (item.attributeType ?? item.pointType) : ''}${item.dataType ? '/' + item.dataType : ''}${item.dataUnit ? ' ' + item.dataUnit : ''}${item.attributeType || item.pointType ? '' : ''}`
}
const loadConfigCandidatesByDevice = async (deviceId: number) => {
const data = await DeviceApi.getDeviceAttributePage({ pageNo: 1, pageSize: 100, deviceId })
const list = (data?.list ?? data?.data ?? []) as any[]
const deviceItems = (list ?? [])
.map((item: any) => {
const key = normalizeKey(item?.attributeId ?? item?.id)
if (key === undefined) return undefined
return {
key,
label: buildTransferLabel(item)
} as TransferItem
})
.filter((it: any) => it && typeof it.key === 'number') as TransferItem[]
const merged = new Map<number, TransferItem>()
for (const it of deviceItems) merged.set(it.key, it)
for (const it of configSelectedItems.value) {
if (!merged.has(it.key)) merged.set(it.key, it)
}
configCandidates.value = Array.from(merged.values())
}
const openConfigDialog = async (recipeId: number | string) => {
configVisible.value = true
configRecipeId.value = recipeCode
configRecipeId.value = recipeId
configSelectedKeys.value = []
configCandidates.value = []
configSelectedItems.value = []
sourceKeyword.value = ''
targetKeyword.value = ''
sourceCheckedKeys.value = []
targetCheckedKeys.value = []
configLoading.value = true
try {
const [candidateRes, selectedRes] = await Promise.all([
DeviceApi.getDeviceContactModelPage(),
RecipeConfigApi.getRecipePointDetailPage({ pageNo: 1, pageSize: 100, recipeId: recipeCode })
])
const candidateList = Array.isArray(candidateRes)
? candidateRes
: ((candidateRes as any)?.list ?? (candidateRes as any)?.data ?? [])
configCandidates.value = (candidateList ?? []).map((item: any) => ({
key: item.id,
label: `${item.attributeName ?? item.pointName ?? ''}${item.attributeType || item.pointType ? '' + (item.attributeType ?? item.pointType) : ''}${item.dataType ? '/' + item.dataType : ''}${item.dataUnit ? ' ' + item.dataUnit : ''}${item.attributeType || item.pointType ? '' : ''}`
}))
configSelectedKeys.value = (selectedRes.list ?? [])
const selectedRes = await RecipeConfigApi.getRecipePointDetailPage({ recipeId, pageNo: 1, pageSize: 100 })
const selectedList = Array.isArray(selectedRes) ? selectedRes : selectedRes?.list ?? selectedRes?.data ?? []
const selectedKeys = (selectedList ?? [])
.map((item: any) => (item.attributeId !== undefined ? item.attributeId : item.id))
.map((id: any) => normalizeKey(id))
.filter((id: any) => typeof id === 'number')
configSelectedKeys.value = selectedKeys
configSelectedItems.value = (selectedList ?? [])
.map((item: any) => ({
key: normalizeKey(item.attributeId !== undefined ? item.attributeId : item.id),
label: buildTransferLabel(item)
}))
.filter((it: any) => typeof it.key === 'number')
const deviceId = detailMeta.deviceId
if (deviceId !== undefined && deviceId !== null) {
await loadConfigCandidatesByDevice(deviceId)
} else {
configCandidates.value = configSelectedItems.value
}
} finally {
configLoading.value = false
}
@ -411,13 +570,10 @@ const submitConfig = async () => {
if (!configRecipeId.value) return
configLoading.value = true
try {
await RecipeConfigApi.saveRecipePointConfig({
recipeId: configRecipeId.value,
attributeIds: configSelectedKeys.value
})
await RecipeConfigApi.updateRecipeDeviceAttribute({ recipeId: configRecipeId.value, ids: configSelectedKeys.value })
message.success(t('common.updateSuccess'))
configVisible.value = false
if (detailVisible.value && detailMeta.recipeCode === configRecipeId.value) {
if (detailVisible.value && String(detailMeta.id) === String(configRecipeId.value)) {
await detailRef.value?.refresh?.()
}
} finally {
@ -432,20 +588,51 @@ onMounted(() => {
</script>
<style scoped>
:deep(.formula-config-transfer.el-transfer) {
--el-transfer-panel-body-height: 440px;
.formula-config-picklist {
display: flex;
width: 100%;
}
:deep(.formula-config-transfer .el-transfer-panel) {
.formula-config-panel {
width: calc((100% - 96px) / 2);
border: 1px solid var(--el-border-color);
border-radius: 4px;
overflow: hidden;
background: var(--el-bg-color);
}
:deep(.el-transfer__buttons) {
.formula-config-panel__header {
display: flex;
text-align: center;
justify-content: space-between;
padding: 10px 12px;
border-bottom: 1px solid var(--el-border-color);
font-weight: 600;
}
.formula-config-panel__meta {
color: var(--el-text-color-secondary);
font-weight: 400;
}
.formula-config-panel__filter {
padding: 10px 12px;
border-bottom: 1px solid var(--el-border-color);
}
.formula-config-panel__table {
width: 100%;
}
.formula-config-actions {
width: 96px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 12px;
}
:deep(.formula-config-row--disabled) {
opacity: 0.55;
}
</style>

@ -57,21 +57,20 @@
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="数量" prop="quantity">
<el-input-number v-model="formData.quantity" :min="1" controls-position="right" class="!w-full" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="供应商" prop="supplier">
<el-input v-model="formData.supplier" placeholder="请输入供应商" />
<!--
<el-select v-model="formData.supplier" placeholder="请选择供应商" clearable filterable class="!w-full">
<el-option v-for="item in supplierOptions" :key="item" :label="item" :value="item" />
</el-select>
-->
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属车间" prop="workshop">
<el-input v-model="formData.workshop" placeholder="请输入所属车间" />
<!--
<el-tree-select
v-model="formData.workshop"
:data="deptTree"
@ -82,18 +81,19 @@
placeholder="请选择所属车间"
class="!w-full"
/>
-->
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="生产日期" prop="productionDate" required>
<el-date-picker v-model="formData.productionDate" type="date" value-format="x" placeholder="请选择生产日期" class="!w-full" />
<el-date-picker v-model="formData.productionDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择生产日期" class="!w-full" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="入厂日期" prop="factoryEntryDate" required>
<el-date-picker v-model="formData.factoryEntryDate" type="date" value-format="x" placeholder="请选择入厂日期" class="!w-full" />
<el-date-picker v-model="formData.factoryEntryDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择入厂日期" class="!w-full" />
</el-form-item>
</el-col>
@ -104,9 +104,11 @@
</el-col>
<el-col :span="24">
<el-form-item label="部门" prop="useDept">
<el-form-item label="所属系统组织" prop="systemOrg">
<el-input v-model="formData.systemOrg" placeholder="请输入所属系统组织" />
<!--
<el-tree-select
v-model="formData.useDept"
v-model="formData.systemOrg"
:data="deptTree"
:props="treeSelectProps"
check-strictly
@ -115,15 +117,22 @@
placeholder="请选择部门"
class="!w-full"
/>
-->
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="责任人" prop="deviceManager">
<div class="device-ledger-manager">
<el-input v-model="formData.deviceManager" placeholder="请选择数据" readonly />
<el-button type="primary" plain @click="openUserPicker"></el-button>
</div>
<el-form-item label="责任人" prop="deviceManagerIds">
<el-select
v-model="formData.deviceManagerIds"
multiple
filterable
clearable
placeholder="请选择责任人"
class="!w-full"
>
<el-option v-for="item in users" :key="item.id" :label="item.nickname" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
@ -140,27 +149,12 @@
</template>
</Dialog>
<Dialog title="选择责任人" v-model="userPickerVisible" width="720px">
<el-input v-model="userKeyword" placeholder="搜索用户" clearable class="mb-12px" />
<el-table :data="filteredUsers" height="420">
<el-table-column label="账号" prop="username" />
<el-table-column label="姓名" prop="nickname" />
<el-table-column label="操作" width="120">
<template #default="scope">
<el-button link type="primary" @click="selectUser(scope.row)"></el-button>
</template>
</el-table-column>
</el-table>
</Dialog>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { DeviceLedgerApi, DeviceLedgerVO } from '@/api/mes/deviceledger'
import { DeviceTypeApi, DeviceTypeTreeVO } from '@/api/mes/devicetype'
import { SupplierApi } from '@/api/erp/purchase/supplier'
import { getSimpleDeptList } from '@/api/system/dept'
import { getSimpleUserList, UserVO } from '@/api/system/user'
import { handleTree } from '@/utils/tree'
import { formatDate } from '@/utils/formatTime'
import type { FormRules } from 'element-plus'
/** 设备类型 表单 */
@ -173,7 +167,32 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
const parseIdsValue = (value: any): number[] => {
if (!value) return []
if (Array.isArray(value)) return value.map((v) => Number(v)).filter((v) => !Number.isNaN(v))
return String(value)
.split(',')
.map((v) => Number(v.trim()))
.filter((v) => !Number.isNaN(v))
}
const normalizeYmd = (value: any): string | undefined => {
if (value === null || value === undefined || value === '') return undefined
if (typeof value === 'string') {
const trimmed = value.trim()
const matched = trimmed.match(/^(\d{4}-\d{2}-\d{2})/)
if (matched?.[1]) return matched[1]
const parsed = Date.parse(trimmed)
if (!Number.isNaN(parsed)) return formatDate(new Date(parsed), 'YYYY-MM-DD')
return trimmed
}
if (typeof value === 'number') return formatDate(new Date(value), 'YYYY-MM-DD')
if (value instanceof Date) return formatDate(value, 'YYYY-MM-DD')
return formatDate(new Date(value), 'YYYY-MM-DD')
}
const initFormData = () => ({
id: undefined,
deviceCode: undefined,
deviceName: undefined,
@ -185,14 +204,17 @@ const formData = ref({
supplier: undefined,
workshop: undefined,
deviceLocation: undefined,
useDept: undefined,
deviceManager: undefined,
quantity: 1,
systemOrg: undefined,
deviceManagerIds: [] as number[],
productionDate: undefined,
factoryEntryDate: undefined,
remark: undefined,
sort: undefined
})
const formData = ref({
...initFormData()
})
const formRules = reactive<FormRules>({
deviceCode: [{ required: true, message: '编码不能为空', trigger: 'blur' }],
deviceName: [{ required: true, message: '名称不能为空', trigger: 'blur' }],
@ -204,53 +226,14 @@ const formRef = ref() // 表单 Ref
const treeSelectProps = { label: 'name', children: 'children' }
const deviceTypeTree = ref<DeviceTypeTreeVO[]>([])
const deptTree = ref<any[]>([])
const supplierOptions = ref<string[]>([])
const deptNameMap = ref<Record<number, string>>({})
const userPickerVisible = ref(false)
const userKeyword = ref('')
const users = ref<UserVO[]>([])
const filteredUsers = computed(() => {
const keyword = userKeyword.value?.trim().toLowerCase()
if (!keyword) return users.value
return users.value.filter((u) =>
[u.username, u.nickname].some((v) => (v ?? '').toString().toLowerCase().includes(keyword))
)
})
const openUserPicker = () => {
userPickerVisible.value = true
}
const selectUser = (user: UserVO) => {
formData.value.deviceManager = user.nickname
userPickerVisible.value = false
}
const buildDeptNameMap = (nodes: any[]) => {
const map: Record<number, string> = {}
const stack = [...nodes]
while (stack.length) {
const node = stack.pop()!
if (typeof node.id === 'number') map[node.id] = node.name
if (Array.isArray(node.children) && node.children.length) stack.push(...node.children)
}
deptNameMap.value = map
}
const ensureOptionsLoaded = async () => {
const [deviceTypeRes, supplierRes, deptRes, userRes] = await Promise.all([
const [deviceTypeRes, userRes] = await Promise.all([
DeviceTypeApi.getDeviceTypeTree({ pageNo: 1, pageSize: 10 }),
SupplierApi.getSupplierSimpleList(),
getSimpleDeptList(),
getSimpleUserList()
])
deviceTypeTree.value = deviceTypeRes
supplierOptions.value = (supplierRes ?? []).map((item: any) => item.name).filter((v: any) => typeof v === 'string')
const tree = handleTree(deptRes, 'id', 'parentId')
deptTree.value = tree
buildDeptNameMap(tree)
users.value = userRes ?? []
}
@ -269,7 +252,14 @@ const open = async (type: string, id?: number, defaultDeviceTypeId?: number) =>
if (id) {
formLoading.value = true
try {
formData.value = await DeviceLedgerApi.getDeviceLedger(id)
const detail = await DeviceLedgerApi.getDeviceLedger(id)
formData.value = {
...initFormData(),
...(detail as any),
deviceManagerIds: parseIdsValue((detail as any)?.deviceManager),
productionDate: normalizeYmd((detail as any)?.productionDate),
factoryEntryDate: normalizeYmd((detail as any)?.factoryEntryDate)
}
} finally {
formLoading.value = false
}
@ -285,13 +275,13 @@ const submitForm = async () => {
//
formLoading.value = true
try {
const workshopId = formData.value.workshop
const useDeptId = formData.value.useDept
const data = {
...(formData.value as any),
workshop: typeof workshopId === 'number' ? deptNameMap.value[workshopId] : undefined,
useDept: typeof useDeptId === 'number' ? deptNameMap.value[useDeptId] : undefined
productionDate: normalizeYmd(formData.value.productionDate),
factoryEntryDate: normalizeYmd(formData.value.factoryEntryDate),
deviceManager: formData.value.deviceManagerIds?.length ? formData.value.deviceManagerIds.join(',') : undefined
} as unknown as DeviceLedgerVO
delete (data as any).deviceManagerIds
if (formType.value === 'create') {
await DeviceLedgerApi.createDeviceLedger(data)
message.success(t('common.createSuccess'))
@ -309,26 +299,7 @@ const submitForm = async () => {
/** 重置表单 */
const resetForm = () => {
formData.value = {
id: undefined,
deviceCode: undefined,
deviceName: undefined,
deviceStatus: undefined,
deviceBrand: undefined,
deviceModel: undefined,
deviceSpec: undefined,
deviceType: undefined,
supplier: undefined,
workshop: undefined,
deviceLocation: undefined,
useDept: undefined,
deviceManager: undefined,
quantity: 1,
productionDate: undefined,
factoryEntryDate: undefined,
remark: undefined,
sort: undefined
}
formData.value = initFormData()
formRef.value?.resetFields()
}
</script>

@ -20,7 +20,7 @@
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="90px"
label-width="60px"
>
<el-form-item label="编码" prop="deviceCode">
<el-input
@ -56,6 +56,9 @@
<el-button type="primary" plain @click="openForm('create')" v-hasPermi="['mes:device-ledger:create']">
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button type="danger" plain @click="handleBatchDelete" v-hasPermi="['mes:device-ledger:delete']">
<Icon icon="ep:delete" class="mr-5px" /> 批量删除
</el-button>
<el-button
type="success"
plain
@ -70,7 +73,16 @@
</ContentWrap>
<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" width="80" fixed="left">
<template #default="scope">
{{ (queryParams.pageNo - 1) * queryParams.pageSize + scope.$index + 1 }}
@ -101,16 +113,15 @@
<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="quantity" />
<el-table-column label="生产日期" align="center" prop="productionDate" :formatter="dateFormatter" width="180px" />
<el-table-column label="入厂日期" align="center" prop="factoryEntryDate" :formatter="dateFormatter" width="180px" />
<el-table-column label="供应商" align="center" prop="supplier" />
<el-table-column label="所属车间" align="center" prop="workshop" />
<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="useDept" />
<el-table-column label="责任人" align="center" prop="deviceManager" />
<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="creator" />
<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">
@ -187,7 +198,7 @@
</template>
<script setup lang="ts">
import { dateFormatter, formatDate } from '@/utils/formatTime'
import { dateFormatter, dateFormatter2, formatDate } from '@/utils/formatTime'
import download from '@/utils/download'
import { DeviceLedgerApi, DeviceLedgerVO } from '@/api/mes/deviceledger'
import { DeviceTypeApi, DeviceTypeTreeVO } from '@/api/mes/devicetype'
@ -216,6 +227,12 @@ const queryParams = reactive({
const queryFormRef = ref() //
const exportLoading = ref(false) //
const tableRef = ref()
const selectedIds = ref<number[]>([])
const handleSelectionChange = (rows: any[]) => {
selectedIds.value = rows?.map((row) => row.id).filter((id) => id !== undefined) ?? []
}
const dictStore = useDictStoreWithOut()
const dictReady = ref(false)
@ -366,31 +383,45 @@ const openForm = (type: string, id?: number) => {
}
/** 删除按钮操作 */
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 DeviceLedgerApi.deleteDeviceLedger(id)
const idsParam = buildIdsParam(ids)
await DeviceLedgerApi.deleteDeviceLedger(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 DeviceLedgerApi.exportDeviceLedger({
deviceCode: queryParams.deviceCode,
deviceName: queryParams.deviceName,
deviceStatus: queryParams.deviceStatus,
deviceType: queryParams.deviceType
})
const data = await DeviceLedgerApi.exportDeviceLedger({ ids: selectedIds.value.join(',') })
download.excel(data, '设备台账.xls')
} catch {
} finally {

@ -13,26 +13,26 @@
<el-form-item label="项目名称" prop="subjectName">
<el-input v-model="formData.subjectName" placeholder="请输入项目名称" />
</el-form-item>
<el-form-item label="项目类型" prop="subjectType">
<el-input v-model="formData.subjectType" placeholder="请输入项目类型" />
<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="subjectStandard">
<el-input v-model="formData.subjectStandard" placeholder="请输入标准" />
<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"
>
<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-item label="项目内容" prop="subjectContent">
<Editor v-model="formData.subjectContent" height="150px" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="submitForm" type="primary" :disabled="formLoading"> </el-button>
@ -41,8 +41,9 @@
</Dialog>
</template>
<script setup lang="ts">
import { getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
import { getBoolDictOptions, getStrDictOptions, DICT_TYPE } from '@/utils/dict'
import { DvSubjectApi, DvSubjectVO } from '@/api/mes/dvsubject'
import { useDictStoreWithOut } from '@/store/modules/dict'
/** 维保项目 表单 */
defineOptions({ name: 'DvSubjectForm' })
@ -50,6 +51,12 @@ defineOptions({ name: 'DvSubjectForm' })
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
@ -58,16 +65,18 @@ const formData = ref({
id: undefined,
subjectCode: undefined,
subjectName: undefined,
subjectType: undefined,
subjectContent: undefined,
subjectStandard: undefined,
isEnable: undefined,
inspectionMethod: undefined,
valueType: undefined,
judgmentCriteria: undefined,
})
const formRules = reactive({
subjectCode: [{ required: true, message: '项目编码不能为空', trigger: 'blur' }],
subjectName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
subjectContent: [{ required: true, message: '项目内容不能为空', trigger: 'blur' }],
isEnable: [{ 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
@ -77,6 +86,10 @@ const open = async (type: string, id?: number) => {
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
if (!dictReady.value) {
await dictStore.setDictMap()
dictReady.value = true
}
//
if (id) {
formLoading.value = true
@ -97,7 +110,15 @@ const submitForm = async () => {
//
formLoading.value = true
try {
const data = formData.value as unknown as DvSubjectVO
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'))
@ -119,10 +140,10 @@ const resetForm = () => {
id: undefined,
subjectCode: undefined,
subjectName: undefined,
subjectType: undefined,
subjectContent: undefined,
subjectStandard: undefined,
isEnable: undefined,
inspectionMethod: undefined,
valueType: undefined,
judgmentCriteria: undefined,
}
formRef.value?.resetFields()
}

@ -1,60 +1,38 @@
<template>
<ContentWrap>
<!-- 搜索工作栏 -->
<el-form
class="-mb-15px"
:model="queryParams"
ref="queryFormRef"
:inline="true"
label-width="68px"
>
<el-form-item label="项目名称" prop="subjectName">
<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.subjectName"
placeholder="请输入项目名称"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
v-model="queryParams.subjectCode" placeholder="请输入编码" clearable @keyup.enter="handleQuery"
class="!w-240px" />
</el-form-item>
<el-form-item label="项目类型" prop="subjectType">
<el-form-item label="名称" prop="subjectName">
<el-input
v-model="queryParams.subjectType"
placeholder="请输入项目类型"
clearable
@keyup.enter="handleQuery"
class="!w-240px"
/>
v-model="queryParams.subjectName" 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-240px"
/>
<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']"
>
<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']"
>
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>
@ -63,40 +41,48 @@
<!-- 列表 -->
<ContentWrap>
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="项目编码" align="center" prop="subjectCode" />
<el-table-column label="项目名称" align="center" prop="subjectName" />
<el-table-column label="项目类型" align="center" prop="subjectType" />
<el-table-column label="项目内容" align="center" prop="subjectContent" />
<el-table-column label="标准" align="center" prop="subjectStandard" />
<el-table-column label="是否启用" align="center" prop="isEnable">
<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">
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.isEnable" />
<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="createTime"
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="操作" align="center">
<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']"
>
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 link type="danger" @click="handleDelete(scope.row.id)" v-hasPermi="['mes:dv-subject:delete']">
删除
</el-button>
</template>
@ -104,11 +90,8 @@
</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>
<!-- 表单弹窗添加/修改 -->
@ -116,11 +99,13 @@
</template>
<script setup lang="ts">
import { getBoolDictOptions, DICT_TYPE } from '@/utils/dict'
import { getStrDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { DvSubjectApi, DvSubjectVO } from '@/api/mes/dvsubject'
import DvSubjectForm from './DvSubjectForm.vue'
import { isHexColor } from '@/utils/color'
import { useDictStoreWithOut } from '@/store/modules/dict'
/** 维保项目 列表 */
defineOptions({ name: 'DvSubject' })
@ -128,23 +113,63 @@ defineOptions({ name: 'DvSubject' })
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,
subjectType: undefined,
subjectContent: undefined,
subjectStandard: undefined,
isEnable: undefined,
createTime: [],
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
@ -176,26 +201,41 @@ const openForm = (type: string, id?: number) => {
}
/** 删除按钮操作 */
const handleDelete = async (id: number) => {
const handleDelete = async (ids: number | number[]) => {
try {
//
await message.delConfirm()
//
await DvSubjectApi.deleteDvSubject(id)
const idsParam = buildIdsParam(ids)
await DvSubjectApi.deleteDvSubject(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)
}
/** 导出按钮操作 */
const handleExport = async () => {
if (!selectedIds.value.length) {
message.error('请选择需要导出的数据')
return
}
try {
//
await message.exportConfirm()
//
exportLoading.value = true
const data = await DvSubjectApi.exportDvSubject(queryParams)
const data = await DvSubjectApi.exportDvSubject({ ids: selectedIds.value.join(',') })
download.excel(data, '维保项目.xls')
} catch {
} finally {
@ -204,7 +244,9 @@ const handleExport = async () => {
}
/** 初始化 **/
onMounted(() => {
onMounted(async () => {
await dictStore.setDictMap()
dictReady.value = true
getList()
})
</script>

@ -0,0 +1,150 @@
<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: 'PlanMaintenanceForm' })
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,327 @@
<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>
<PlanMaintenanceForm 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 PlanMaintenanceForm from './PlanMaintenanceForm.vue'
import { isHexColor } from '@/utils/color'
import { useDictStoreWithOut } from '@/store/modules/dict'
defineOptions({ name: 'PlanMaintenance' })
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>

@ -169,7 +169,7 @@ const dialogVisible = ref(false) // 弹窗的是否展示
const dialogTitle = ref('') //
const formLoading = ref(false) // 12
const formType = ref('') // create - update -
const formData = ref({
const formData = ref<any>({
id: undefined,
reportId: undefined,
planId: undefined,

@ -0,0 +1,159 @@
<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-input v-model="formData.deviceList" placeholder="请输入设备列表" />
</el-form-item>
<el-form-item label="项目表单" prop="projectForm">
<el-input v-model="formData.projectForm" placeholder="请输入项目表单" />
</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">
<el-input v-model="formData.cronExpression" placeholder="请输入 cron 表达式" />
</el-form-item>
<el-form-item label="可操作人" prop="operableUsers">
<el-input v-model="formData.operableUsers" placeholder="请输入可操作人" />
</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'
defineOptions({ name: 'TaskManagementForm' })
const { t } = useI18n()
const message = useMessage()
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,
name: undefined as string | undefined,
taskType: undefined as number | undefined,
deviceList: undefined as string | undefined,
projectForm: undefined as string | undefined,
dateRange: [] as string[],
cronExpression: undefined as string | undefined,
operableUsers: undefined as string | undefined,
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: undefined,
projectForm: undefined,
dateRange: [],
cronExpression: undefined,
operableUsers: undefined,
enabled: true
}
formRef.value?.resetFields()
}
const open = async (type: string, row?: TaskManagementVO) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
if (type === 'update' && row) {
formData.value.id = row.id
formData.value.name = row.name
formData.value.taskType = row.taskType
formData.value.deviceList = row.deviceList
formData.value.projectForm = row.projectForm
formData.value.dateRange = [row.startDate, row.endDate].filter(Boolean) as string[]
formData.value.cronExpression = row.cronExpression
formData.value.operableUsers = row.operableUsers
formData.value.enabled = typeof row.enabled === 'boolean' ? row.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: formData.value.deviceList,
projectForm: formData.value.projectForm,
startDate: startDate || undefined,
endDate: endDate || undefined,
cronExpression: formData.value.cronExpression,
operableUsers: formData.value.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,202 @@
<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="执行频率" align="center" prop="execFrequency" width="100" />
<el-table-column label="频率值" align="center" prop="frequencyValue" min-width="120" />
<el-table-column label="时间" align="center" prop="time" min-width="140" />
<el-table-column label="有效期(分钟)" align="center" prop="validMinutes" width="120" />
<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="140">
<template #default="scope">
<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>
<TaskManagementForm 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 TaskManagementForm from './TaskManagementForm.vue'
defineOptions({ name: 'TaskManagement' })
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 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>
Loading…
Cancel
Save