Merge remote-tracking branch 'origin/main'

# Conflicts:
#	src/views/mold/taskConfiguration/index.vue
main
黄伟杰 2 days ago
commit fbe414d563

@ -54,6 +54,10 @@ export const TicketManagementApi = {
return await request.put({ url: `/mes/mold-ticket-results/batchUpdate`, data })
},
exportTicketManagement: async (params: any) => {
return await request.download({ url: `/mes/mold-ticket-management/export-excel`, params })
},
getInspectionByMoldId: async (params: { moldId: number; startTime?: string; endTime?: string }) => {
return await request.get({ url: `/mes/mold-ticket-management/getInspectionByMoldId`, params })
},

@ -3830,6 +3830,7 @@ export default {
operatorName: 'Operator',
taskTime: 'Job Time',
taskEndTime: 'Planned End Time',
taskTimeRange: 'Job Time',
createTime: 'Create Time',
index: 'Index',
remark: 'Remark',
@ -3839,10 +3840,16 @@ export default {
placeholderPlanType: 'Please select type',
placeholderJobStatus: 'Please select job status',
placeholderJobResult: 'Please select result',
placeholderOperatorName: 'Please select operator',
placeholderTaskTime: 'Please select job start time',
placeholderTaskEndTime: 'Please select job end time',
query: 'Query',
reset: 'Reset',
cancelConfirm: 'Confirm cancel selected tasks?',
cancelSuccess: 'Cancel task successful',
cancelOnlyUnworkedTip: 'Only unworked tickets can be canceled',
export: 'Export',
exportFilename: 'Mold Work Order Inquiry.xls',
inspectResultTitlePrefix: 'Inspection Result-',
inspectResultTitle: 'Inspection Result'
},

@ -2198,6 +2198,7 @@ export default {
cancelReason: '取消原因',
cancelConfirm: '确认取消选中的任务吗?',
cancelSuccess: '取消任务成功',
cancelOnlyUnworkedTip: '只有未作业状态的工单才能取消任务',
cancelFail: '取消任务失败',
cancelOnlyUnworkedTip: '只有未作业状态的工单才能取消任务',
selectAllDecisionError: '请先为所有待检测记录选择通过或不通过',
@ -3300,6 +3301,7 @@ export default {
operatorName: '作业人',
taskTime: '作业时间',
taskEndTime: '计划结束作业时间',
taskTimeRange: '作业时间',
createTime: '创建时间',
index: '序号',
remark: '备注',
@ -3309,10 +3311,16 @@ export default {
placeholderPlanType: '请选择类型',
placeholderJobStatus: '请选择作业状态',
placeholderJobResult: '请选择结果',
placeholderOperatorName: '请选择作业人',
placeholderTaskTime: '请选择作业开始时间',
placeholderTaskEndTime: '请选择作业结束时间',
query: '查询',
reset: '重置',
cancelConfirm: '确认取消选中的任务吗?',
cancelSuccess: '取消任务成功',
cancelOnlyUnworkedTip: '只有未作业状态的工单才能取消任务',
export: '导出',
exportFilename: '模具工单查询.xls',
inspectResultTitlePrefix: '检验结果-',
inspectResultTitle: '检验结果'
},

@ -129,7 +129,7 @@
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.image')" align="center" prop="images" min-width="260">
<el-table-column :label="t('MoldManagement.MoldBrandPage.image')" align="center" prop="images" min-width="180">
<template #default="scope">
<div
v-if="ticketResultEditable"
@ -1099,13 +1099,15 @@ defineExpose({ open })
}
.mold-maintain-page__sidebar {
width: 20vw;
width: 260px;
flex-shrink: 0;
display: flex;
}
.mold-maintain-page__form {
flex: 1;
min-width: 0;
overflow: hidden;
background: #fff;
border-radius: 12px;
padding: 24px 32px;

@ -214,7 +214,7 @@ const planPaginationRef = ref<HTMLElement>()
const updatePlanTableMaxHeight = async () => {
await nextTick()
const tableTop = tableRef.value?.$el?.getBoundingClientRect().top ?? 0
const paginationHeight = planPaginationRef.value?.getBoundingClientRect().height ?? 72
const paginationHeight = planPaginationRef.value?.$el?.getBoundingClientRect().height ?? 72
const pageBottomGap = 56
const availableHeight = window.innerHeight - tableTop - paginationHeight - pageBottomGap
planTableMaxHeight.value = Math.min(window.innerHeight, Math.max(240, Math.floor(availableHeight)))

@ -166,7 +166,7 @@ const planPaginationRef = ref<HTMLElement>()
const updatePlanTableMaxHeight = async () => {
await nextTick()
const tableTop = tableRef.value?.$el?.getBoundingClientRect().top ?? 0
const paginationHeight = planPaginationRef.value?.getBoundingClientRect().height ?? 72
const paginationHeight = planPaginationRef.value?.$el?.getBoundingClientRect().height ?? 72
const pageBottomGap = 56
const availableHeight = window.innerHeight - tableTop - paginationHeight - pageBottomGap
planTableMaxHeight.value = Math.min(window.innerHeight, Math.max(240, Math.floor(availableHeight)))

@ -196,7 +196,7 @@ const planPaginationRef = ref<HTMLElement>()
const updatePlanTableMaxHeight = async () => {
await nextTick()
const tableTop = tableRef.value?.$el?.getBoundingClientRect().top ?? 0
const paginationHeight = planPaginationRef.value?.getBoundingClientRect().height ?? 72
const paginationHeight = planPaginationRef.value?.$el?.getBoundingClientRect().height ?? 72
const pageBottomGap = 56
const availableHeight = window.innerHeight - tableTop - paginationHeight - pageBottomGap
planTableMaxHeight.value = Math.min(window.innerHeight, Math.max(240, Math.floor(availableHeight)))

@ -21,10 +21,24 @@
/>
</el-form-item>
<el-form-item :label="t('EnergyManagement.EnergyType.dialogUnitLabel')" prop="unit">
<el-input
v-model="formData.unit"
:placeholder="t('EnergyManagement.EnergyType.dialogUnitPlaceholder')"
/>
<el-select v-model="formData.unit" clearable
:placeholder="t('EnergyManagement.EnergyType.dialogUnitPlaceholder')" class="!w-full">
<el-option v-for="item in unitList" :key="item.id" :label="item.name" :value="item.name" />
<template #footer>
<div v-if="!isAddingUnit" class="px-10px py-6px">
<el-button text bg size="small" @click.stop="onAddUnit">
+ 新增单位
</el-button>
</div>
<div v-else class="px-10px py-6px">
<el-input v-model="unitInputName" size="small" placeholder="请输入单位名称" class="mb-6px" />
<div class="flex gap-6px">
<el-button type="primary" size="small" @click.stop="onConfirmAddUnit">确定</el-button>
<el-button size="small" @click.stop="clearAddUnit">取消</el-button>
</div>
</div>
</template>
</el-select>
</el-form-item>
<el-form-item :label="t('EnergyManagement.EnergyType.dialogIsEnableLabel')" prop="isEnable">
<el-radio-group v-model="formData.isEnable">
@ -57,6 +71,8 @@
<script setup lang="ts">
import {DICT_TYPE, getBoolDictOptions} from '@/utils/dict'
import { EnergyTypeApi, EnergyTypeVO } from '@/api/mes/energytype'
import { ProductUnitApi, ProductUnitVO } from '@/api/erp/product/unit'
import { CommonStatusEnum } from '@/utils/constants'
/** 能耗类型 表单 */
defineOptions({ name: 'EnergyTypeForm' })
@ -84,12 +100,58 @@ const formRules = reactive({
})
const formRef = ref() // Ref
//
const unitList = ref<ProductUnitVO[]>([])
const isAddingUnit = ref(false)
const unitInputName = ref('')
const onAddUnit = () => {
isAddingUnit.value = true
}
const onConfirmAddUnit = async () => {
if (!unitInputName.value.trim()) {
message.warning('请输入单位名称')
return
}
formLoading.value = true
try {
await ProductUnitApi.createProductUnit({
name: unitInputName.value.trim(),
status: CommonStatusEnum.ENABLE,
primaryFlag: 'Y'
} as ProductUnitVO)
//
const newList = await ProductUnitApi.getProductUnitSimpleList()
unitList.value = newList
const newUnit = newList.find((u: any) => u.name === unitInputName.value.trim())
if (newUnit) {
formData.value.unit = newUnit.name
}
clearAddUnit()
message.success('新增单位成功')
} finally {
formLoading.value = false
}
}
const clearAddUnit = () => {
unitInputName.value = ''
isAddingUnit.value = false
}
/** 打开弹窗 */
const open = async (type: string, id?: number) => {
dialogVisible.value = true
dialogTitle.value = t('action.' + type)
formType.value = type
resetForm()
//
try {
unitList.value = await ProductUnitApi.getProductUnitSimpleList()
} catch {
unitList.value = []
}
//
if (id) {
formLoading.value = true

@ -19,13 +19,12 @@
@click="openCriticalComponentDialog" />
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.productionLine')" prop="lineId" v-if="formData.operateType != null">
<el-input :model-value="displayLineName" readonly />
<el-input :model-value="displayLineName" disabled />
</el-form-item>
<!-- 上模手动选择模具 -->
<el-form-item
:label="t('MoldManagement.MoldOperate.mold')"
prop="moldId"
:required="String(formData.operateType) === '1'"
v-if="formData.operateType == 1"
>
<el-input
@ -37,7 +36,7 @@
</el-form-item>
<!-- 下模自动带出该设备的在机模具 -->
<el-form-item label="在机模具" v-if="formData.operateType == 2">
<el-input :model-value="currentDeviceMoldText" readonly />
<el-input :model-value="currentDeviceMoldText" disabled />
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldOperate.operateTime')" prop="operateTime">
<el-date-picker
@ -215,26 +214,13 @@ const formData = ref<MoldOperateFormData>({
remark: undefined,
})
const validateMoldId = (_rule: any, value: any, callback: (error?: Error) => void) => {
if (String(formData.value.operateType) !== '1') {
callback()
return
}
const hasValue = value !== undefined && value !== null && value !== ''
if (!hasValue) {
callback(new Error(t('MoldManagement.MoldOperate.validatorMoldRequired')))
} else {
callback()
}
}
const formRules = reactive({
const formRules = computed(() => ({
operateType: [{ required: true, message: t('MoldManagement.MoldOperate.validatorOperateTypeRequired'), trigger: 'blur' }],
deviceId: [{ required: true, message: t('MoldManagement.MoldOperate.validatorDeviceRequired'), trigger: 'change' }],
moldId: [{ validator: validateMoldId, trigger: 'change' }],
moldId: [{ required: true, message: formType.value === 'create' ? '关联模具不能为空' : t('MoldManagement.MoldOperate.validatorMoldRequired'), trigger: 'change' }],
operateTime: [{ required: true, message: t('MoldManagement.MoldOperate.validatorOperateTimeRequired'), trigger: 'blur' }],
operatorId: [{ required: true, message: t('MoldManagement.MoldOperate.validatorOperatorRequired'), trigger: 'change' }],
})
}))
const formRef = ref() // Ref
/** 打开弹窗 */
@ -409,11 +395,13 @@ watch(
return
}
formData.value.deviceId = undefined as any
formData.value.lineId = undefined as any
formData.value.moldId = undefined as any
ids.value = []
moldIds.value = []
selectedDeviceRows.value = []
selectedMoldRows.value = []
displayTopCategory.value = ''
if (!val) {
return
}
@ -599,7 +587,9 @@ const handleDeviceSelectConfirm = async (payload: { ids: (number | string)[]; ro
} else {
selectedDeviceRows.value = []
formData.value.deviceId = undefined
formData.value.lineId = undefined
ids.value = []
displayTopCategory.value = ''
}
nextTick(() => {
formRef.value?.clearValidate?.('deviceId')
@ -792,8 +782,12 @@ const openCriticalComponentDialog = async () => {
}
const openMoldSelectDialog = () => {
searchMoldParams.code=''
searchMoldParams.name=''
if (!formData.value.deviceId) {
message.warning('请先选择设备')
return
}
searchMoldParams.code = ''
searchMoldParams.name = ''
const rows = selectedMoldRows.value.map((item) => ({ ...item, id: Number(item.id) }))
moldSelectDialogRef.value?.open(rows)
}

@ -11,28 +11,38 @@
</el-radio-group>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.TaskManagement.moldList')" prop="moldList">
<el-select
v-model="formData.moldList"
multiple
filterable
<el-input
:model-value="selectedMoldText"
readonly
clearable
:placeholder="t('EquipmentManagement.TaskManagement.placeholderMoldList')"
class="!w-full"
@clear="clearMoldSelection"
>
<el-option v-for="item in deviceOptions" :key="String(item.id)" :label="item.name" :value="String(item.id)" />
</el-select>
<template #append>
<el-button @click="openMoldDialog">
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.select') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.TaskManagement.projectForm')" prop="projectForm">
<el-select
v-model="formData.projectForm"
multiple
filterable
<el-input
:model-value="selectedPlanText"
readonly
clearable
:placeholder="t('EquipmentManagement.TaskManagement.placeholderProjectForm')"
class="!w-full"
@clear="clearPlanSelection"
>
<el-option v-for="item in planOptions" :key="String(item.id)" :label="item.planName" :value="String(item.id)" />
</el-select>
<template #append>
<el-button @click="openPlanDialog">
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.select') }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.TaskManagement.planEndDate')" prop="endDate">
<el-date-picker
@ -79,13 +89,190 @@ v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" :key="String(
<el-button @click="dialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
<Dialog
title="选择模具"
v-model="moldDialogVisible"
:appendToBody="true"
width="1080px"
>
<el-form
ref="moldDialogQueryFormRef"
:model="moldDialogQueryParams"
:inline="true"
class="-mb-15px"
>
<el-form-item label="编码/名称/型号" prop="keyword">
<el-input
v-model="moldDialogQueryParams.keyword"
placeholder="请输入编码/名称/产品型号"
clearable
class="!w-280px"
@keyup.enter="handleMoldDialogQuery"
/>
</el-form-item>
<el-form-item>
<el-button @click="handleMoldDialogQuery">
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.query') }}
</el-button>
<el-button @click="resetMoldDialogQuery">
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('common.reset') }}
</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="moldDialogLoading"
:data="moldDialogList"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
max-height="420"
@row-click="toggleMoldDialogRow"
>
<el-table-column width="55" align="center">
<template #header>
<el-checkbox
:model-value="isMoldCurrentPageAllSelected"
:indeterminate="isMoldCurrentPageIndeterminate"
@change="toggleMoldCurrentPageSelection"
/>
</template>
<template #default="{ row }">
<el-checkbox
:model-value="isMoldDialogSelected(row)"
@click.stop
@change="(checked) => toggleMoldDialogSelection(row, checked)"
/>
</template>
</el-table-column>
<el-table-column :label="t('MoldManagement.MoldBrandPage.code')" prop="code" min-width="150" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.name')" prop="name" min-width="160" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.productName')" prop="productName" min-width="140" />
<el-table-column :label="t('MoldManagement.MoldBrandPage.status')" prop="status" width="100">
<template #default="{ row }">
<dict-tag :type="DICT_TYPE.ERP_MOLD_STATUS" :value="row.status" />
</template>
</el-table-column>
</el-table>
<div class="task-selector-pagination flex items-center justify-between mt-15px">
<div class="task-selector-selected">
已选择 {{ moldDialogSelectedIds.length }} 个模具
</div>
<Pagination
:total="moldDialogTotal"
v-model:page="moldDialogQueryParams.pageNo"
v-model:limit="moldDialogQueryParams.pageSize"
@pagination="getMoldDialogList"
/>
</div>
<template #footer>
<el-button type="primary" @click="confirmMoldSelection">{{ t('common.ok') }}</el-button>
<el-button @click="moldDialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
<Dialog
:title="t('EquipmentManagement.TaskManagement.selectPlanDialogTitle')"
v-model="planDialogVisible"
:appendToBody="true"
width="960px"
>
<el-form
ref="planDialogQueryFormRef"
:model="planDialogQueryParams"
:inline="true"
class="-mb-15px"
>
<el-form-item :label="t('EquipmentManagement.PlanMaintenance.planName')" prop="planName">
<el-input
v-model="planDialogQueryParams.planName"
:placeholder="t('EquipmentManagement.PlanMaintenance.placeholderPlanName')"
clearable
class="!w-220px"
@keyup.enter="handlePlanDialogQuery"
/>
</el-form-item>
<el-form-item :label="t('EquipmentManagement.PlanMaintenance.planType')" prop="planType">
<el-select
v-model="planDialogQueryParams.planType"
:placeholder="t('EquipmentManagement.PlanMaintenance.placeholderPlanType')"
clearable
class="!w-220px"
>
<el-option :value="1" :label="t('EquipmentManagement.PlanMaintenance.planTypeMaintain')" />
<el-option :value="2" :label="t('EquipmentManagement.PlanMaintenance.planTypeInspect')" />
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handlePlanDialogQuery">
<Icon icon="ep:search" class="mr-5px" />
{{ t('common.query') }}
</el-button>
<el-button @click="resetPlanDialogQuery">
<Icon icon="ep:refresh" class="mr-5px" />
{{ t('common.reset') }}
</el-button>
</el-form-item>
</el-form>
<el-table
v-loading="planDialogLoading"
:data="planDialogList"
:stripe="true"
:show-overflow-tooltip="true"
row-key="id"
max-height="420"
@row-click="handlePlanDialogRowClick"
@row-dblclick="confirmPlanSelection"
>
<el-table-column width="55" align="center">
<template #default="{ row }">
<el-radio
v-model="planDialogSelectedId"
:label="String(row.id)"
@click.stop
@change="handlePlanDialogRadioChange(row)"
>
&nbsp;
</el-radio>
</template>
</el-table-column>
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.planName')" prop="planName" min-width="180" />
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.planType')" prop="planType" width="120">
<template #default="{ row }">
{{ getPlanTypeLabel(row.planType) }}
</template>
</el-table-column>
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.description')" prop="description" min-width="220" />
<el-table-column :label="t('EquipmentManagement.PlanMaintenance.creatorName')" prop="creatorName" width="140" />
</el-table>
<div class="flex justify-end mt-15px">
<Pagination
:total="planDialogTotal"
v-model:page="planDialogQueryParams.pageNo"
v-model:limit="planDialogQueryParams.pageSize"
@pagination="getPlanDialogList"
/>
</div>
<template #footer>
<el-button type="primary" @click="confirmPlanSelection">{{ t('common.ok') }}</el-button>
<el-button @click="planDialogVisible = false">{{ t('common.cancel') }}</el-button>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { DICT_TYPE, getBoolDictOptions } from '@/utils/dict'
import { TaskManagementApi, TaskManagementVO } from '@/api/mold/taskManagement'
import { MoldBrandApi } from '@/api/erp/mold'
import { PlanMaintenanceApi } from '@/api/mold/planmaintenance'
import { MoldBrandApi, type MoldBrandVO } from '@/api/erp/mold'
import { PlanMaintenanceApi, PlanMaintenanceVO } from '@/api/mold/planmaintenance'
import { getSimpleUserList, UserVO } from '@/api/system/user'
defineOptions({ name: 'MoldTaskConfigurationForm' })
@ -99,19 +286,46 @@ const formLoading = ref(false)
const formType = ref('')
const formRef = ref()
type DeviceOption = {
type MoldOption = MoldBrandVO & {
id: number | string
code: string
name: string
}
type PlanOption = {
type PlanOption = PlanMaintenanceVO & {
id: number | string
planName: string
}
const deviceOptions = ref<DeviceOption[]>([])
const planOptions = ref<PlanOption[]>([])
const users = ref<UserVO[]>([])
const moldSelectionCache = ref<Record<string, MoldOption>>({})
const planSelectionCache = ref<Record<string, PlanOption>>({})
const moldDialogVisible = ref(false)
const moldDialogLoading = ref(false)
const moldDialogList = ref<MoldOption[]>([])
const moldDialogTotal = ref(0)
const moldDialogSelectedIds = ref<string[]>([])
const moldDialogQueryFormRef = ref()
const moldDialogQueryParams = reactive({
pageNo: 1,
pageSize: 10,
keyword: undefined as string | undefined
})
const planDialogVisible = ref(false)
const planDialogLoading = ref(false)
const planDialogList = ref<PlanOption[]>([])
const planDialogTotal = ref(0)
const planDialogSelectedId = ref('')
const planDialogSelectedRow = ref<PlanOption>()
const planDialogQueryFormRef = ref()
const planDialogQueryParams = reactive({
pageNo: 1,
pageSize: 10,
planName: undefined as string | undefined,
planType: undefined as number | undefined
})
const parseIdsValue = (value: any): string[] => {
if (!value) return []
@ -127,23 +341,75 @@ const toCommaSeparatedIds = (value: any): string | undefined => {
return ids.length ? ids.join(',') : undefined
}
const normalizePageData = <T = any>(res: any): { list: T[]; total: number } => {
const pageResult = res?.pageResult ?? res
const list = Array.isArray(pageResult) ? pageResult : pageResult?.list ?? res?.list ?? res?.data?.list ?? []
const total = Array.isArray(pageResult) ? pageResult.length : pageResult?.total ?? res?.total ?? res?.data?.total ?? list.length
return { list: (Array.isArray(list) ? list : []) as T[], total: Number(total || 0) }
}
const cacheMoldRows = (rows: MoldOption[]) => {
const next = { ...moldSelectionCache.value }
rows.forEach((row) => {
if (row?.id !== undefined && row?.id !== null) {
next[String(row.id)] = row
}
})
moldSelectionCache.value = next
}
const cachePlanRows = (rows: PlanOption[]) => {
const next = { ...planSelectionCache.value }
rows.forEach((row) => {
if (row?.id !== undefined && row?.id !== null) {
next[String(row.id)] = row
}
})
planSelectionCache.value = next
}
const getMoldLabel = (id: string) => {
const row = moldSelectionCache.value[id]
return row ? `${row.code ?? ''} ${row.name ?? ''}`.trim() || id : id
}
const getPlanLabel = (id?: number | string) => {
if (id === undefined || id === null) return ''
const key = String(id)
const row = planSelectionCache.value[key]
return row?.planName || key
}
const ensureOptionsLoaded = async () => {
const [deviceRes, planRes, userRes] = await Promise.all([
MoldBrandApi.getBrandList(),
PlanMaintenanceApi.getPlanMaintenancePage({}),
getSimpleUserList()
])
deviceOptions.value = (deviceRes ?? []) as DeviceOption[]
planOptions.value = (planRes?.list ?? []) as PlanOption[]
const userRes = await getSimpleUserList()
users.value = userRes ?? []
}
const selectedMoldText = computed(() => {
const ids = parseIdsValue(formData.value.moldList)
return ids.map((id) => getMoldLabel(id)).join(', ')
})
const selectedPlanText = computed(() => getPlanLabel(formData.value.projectForm))
const isMoldCurrentPageAllSelected = computed(() => {
if (!moldDialogList.value.length) return false
return moldDialogList.value.every((row) => moldDialogSelectedIds.value.includes(String(row.id)))
})
const isMoldCurrentPageIndeterminate = computed(() => {
const selectedCount = moldDialogList.value.filter((row) =>
moldDialogSelectedIds.value.includes(String(row.id))
).length
return selectedCount > 0 && selectedCount < moldDialogList.value.length
})
const formData = ref({
id: undefined as number | undefined,
name: undefined as string | undefined,
taskType: undefined as number | undefined,
moldList: [] as string[],
projectForm: [] as string[],
projectForm: undefined as number | undefined,
endDate: undefined as string | undefined,
cronExpression: undefined as string | undefined,
operableUsers: [] as string[],
@ -165,7 +431,7 @@ const resetForm = () => {
name: undefined,
taskType: undefined,
moldList: [],
projectForm: [],
projectForm: undefined,
endDate: undefined,
cronExpression: undefined,
operableUsers: [],
@ -188,14 +454,28 @@ const open = async (type: string, row?: TaskManagementVO) => {
formData.value.moldList = parseIdsValue((row as any).moldList)
const projectFormIds = parseIdsValue((row as any).projectForm)
if (projectFormIds.length) {
formData.value.projectForm = projectFormIds
const n = Number(projectFormIds[0])
formData.value.projectForm = Number.isFinite(n) ? n : undefined
const projectFormName = String((row as any).projectFormName ?? '').trim()
if (formData.value.projectForm !== undefined && projectFormName) {
planSelectionCache.value[String(formData.value.projectForm)] = {
id: formData.value.projectForm,
planName: projectFormName,
planType: '' as any
}
}
} else {
const projectFormNames = parseIdsValue((row as any).projectFormName)
const mappedIds = projectFormNames
.map((name) => planOptions.value.find((p) => p.planName === name)?.id)
// try finding from cached plan dialog list
const mapped = projectFormNames
.map((name) => {
const found = Object.values(planSelectionCache.value).find((p) => p.planName === name)
return found?.id
})
.filter((id) => id !== undefined && id !== null)
.map((id) => String(id))
formData.value.projectForm = mappedIds
.map((id) => Number(id))
const firstId = mapped[0]
formData.value.projectForm = typeof firstId === 'number' && Number.isFinite(firstId) ? firstId : undefined
}
formData.value.endDate = row.endDate || undefined
formData.value.cronExpression = row.cronExpression
@ -214,6 +494,164 @@ defineExpose({ open })
const emit = defineEmits(['success'])
// ---- ----
const getMoldDialogList = async () => {
moldDialogLoading.value = true
try {
const data = await MoldBrandApi.getMoldBrandPage(moldDialogQueryParams)
const normalized = normalizePageData<MoldOption>(data)
moldDialogList.value = normalized.list
moldDialogTotal.value = normalized.total
cacheMoldRows(normalized.list)
} finally {
moldDialogLoading.value = false
}
}
const openMoldDialog = async () => {
moldDialogVisible.value = true
moldDialogSelectedIds.value = parseIdsValue(formData.value.moldList)
moldDialogQueryParams.pageNo = 1
moldDialogQueryParams.keyword = undefined
await getMoldDialogList()
}
const handleMoldDialogQuery = () => {
moldDialogQueryParams.pageNo = 1
getMoldDialogList()
}
const resetMoldDialogQuery = () => {
moldDialogQueryFormRef.value?.resetFields?.()
handleMoldDialogQuery()
}
const isMoldDialogSelected = (row: MoldOption) => {
return moldDialogSelectedIds.value.includes(String(row.id))
}
const toggleMoldDialogSelection = (row: MoldOption, checked: boolean) => {
const id = String(row.id)
const next = new Set(moldDialogSelectedIds.value)
checked ? next.add(id) : next.delete(id)
moldDialogSelectedIds.value = Array.from(next)
cacheMoldRows([row])
}
const toggleMoldDialogRow = (row: MoldOption) => {
toggleMoldDialogSelection(row, !isMoldDialogSelected(row))
}
const toggleMoldCurrentPageSelection = (checked: boolean) => {
const next = new Set(moldDialogSelectedIds.value)
moldDialogList.value.forEach((row) => {
const id = String(row.id)
checked ? next.add(id) : next.delete(id)
})
moldDialogSelectedIds.value = Array.from(next)
cacheMoldRows(moldDialogList.value)
}
const confirmMoldSelection = () => {
if (!moldDialogSelectedIds.value.length) {
message.warning(t('EquipmentManagement.TaskManagement.placeholderDeviceList'))
return
}
formData.value.moldList = [...moldDialogSelectedIds.value]
moldDialogVisible.value = false
formRef.value?.clearValidate?.('moldList')
}
const clearMoldSelection = () => {
formData.value.moldList = []
moldDialogSelectedIds.value = []
formRef.value?.clearValidate?.('moldList')
}
// ---- ----
const getPlanDialogList = async () => {
planDialogLoading.value = true
try {
const data = await PlanMaintenanceApi.getPlanMaintenancePage(planDialogQueryParams)
const normalized = normalizePageData<PlanOption>(data)
planDialogList.value = normalized.list
planDialogTotal.value = normalized.total
cachePlanRows(normalized.list)
} finally {
planDialogLoading.value = false
}
}
const openPlanDialog = async () => {
planDialogVisible.value = true
planDialogSelectedId.value =
formData.value.projectForm === undefined || formData.value.projectForm === null
? ''
: String(formData.value.projectForm)
planDialogSelectedRow.value = planDialogSelectedId.value
? planSelectionCache.value[planDialogSelectedId.value]
: undefined
planDialogQueryParams.pageNo = 1
planDialogQueryParams.planName = undefined
planDialogQueryParams.planType = undefined
await getPlanDialogList()
}
const handlePlanDialogQuery = () => {
planDialogQueryParams.pageNo = 1
getPlanDialogList()
}
const resetPlanDialogQuery = () => {
planDialogQueryFormRef.value?.resetFields?.()
handlePlanDialogQuery()
}
const handlePlanDialogRowClick = (row: PlanOption) => {
planDialogSelectedId.value = String(row.id)
planDialogSelectedRow.value = row
cachePlanRows([row])
}
const handlePlanDialogRadioChange = (row: PlanOption) => {
planDialogSelectedRow.value = row
cachePlanRows([row])
}
const getPlanTypeLabel = (value: any) => {
const normalized = Number(value)
if (normalized === 1) return t('EquipmentManagement.PlanMaintenance.planTypeMaintain')
if (normalized === 2) return t('EquipmentManagement.PlanMaintenance.planTypeInspect')
return value ?? '-'
}
const confirmPlanSelection = (row?: PlanOption) => {
const selected =
row?.id !== undefined && row?.id !== null
? row
: planDialogSelectedRow.value ||
planDialogList.value.find((item) => String(item.id) === planDialogSelectedId.value) ||
planSelectionCache.value[planDialogSelectedId.value]
if (!selected?.id) {
message.warning(t('EquipmentManagement.TaskManagement.placeholderProjectForm'))
return
}
const id = Number(selected.id)
formData.value.projectForm = Number.isFinite(id) ? id : undefined
cachePlanRows([selected])
planDialogVisible.value = false
formRef.value?.clearValidate?.('projectForm')
}
const clearPlanSelection = () => {
formData.value.projectForm = undefined
planDialogSelectedId.value = ''
planDialogSelectedRow.value = undefined
formRef.value?.clearValidate?.('projectForm')
}
const submitForm = async () => {
await formRef.value.validate()
formLoading.value = true
@ -223,7 +661,7 @@ const submitForm = async () => {
name: formData.value.name,
taskType: formData.value.taskType,
moldList: toCommaSeparatedIds((formData.value as any).moldList),
projectForm: toCommaSeparatedIds((formData.value as any).projectForm),
projectForm: formData.value.projectForm,
endDate: formData.value.endDate || undefined,
cronExpression: formData.value.cronExpression,
operableUsers: toCommaSeparatedIds((formData.value as any).operableUsers),
@ -244,3 +682,10 @@ const submitForm = async () => {
}
}
</script>
<style lang="scss" scoped>
.task-selector-pagination :deep(.pagination-container) {
margin: 0;
padding: 0;
}
</style>

@ -143,7 +143,7 @@
</template>
<script setup lang="ts">
import { ElMessageBox } from 'element-plus'
import { DICT_TYPE } from '@/utils/dict'
import { dateFormatter, dateFormatter2 } from '@/utils/formatTime'
import download from '@/utils/download'
import { TaskManagementApi, TaskManagementVO } from '@/api/mold/taskManagement'
@ -170,7 +170,7 @@ const planPaginationRef = ref<HTMLElement>()
const updatePlanTableMaxHeight = async () => {
await nextTick()
const tableTop = tableRef.value?.$el?.getBoundingClientRect().top ?? 0
const paginationHeight = planPaginationRef.value?.getBoundingClientRect().height ?? 72
const paginationHeight = planPaginationRef.value?.$el?.getBoundingClientRect().height ?? 72
const pageBottomGap = 56
const availableHeight = window.innerHeight - tableTop - paginationHeight - pageBottomGap
planTableMaxHeight.value = Math.min(window.innerHeight, Math.max(240, Math.floor(availableHeight)))
@ -259,12 +259,7 @@ const openForm = (type: string, row?: TaskManagementVO) => {
formRef.value.open(type, row)
}
const isTaskEnabled = (row: TaskManagementVO) => {
const value = (row as any)?.enabled
if (typeof value === 'boolean') return value
const text = String(value ?? '').toLowerCase().trim()
return text === 'true' || text === '1' || text === 'yes'
}
const isTaskEnabled = (row: TaskManagementVO) => row.enabled === true || (row.enabled as any) === 'true'
const handleDelete = async (id?: number) => {
if (!id) return
@ -284,6 +279,15 @@ const handleCreateTicket = async (row?: TaskManagementVO) => {
return
}
try {
await message.confirm(
t('EquipmentManagement.TaskManagement.createTicketConfirm'),
t('common.reminder')
)
} catch {
return
}
ticketLoadingId.value = row.id
try {
await TaskManagementApi.createTaskManagementTicket(row.id)

@ -4,6 +4,17 @@
<div class="ticket-result-header">
<el-button @click="handleClose">{{ t('common.back') }}</el-button>
<span class="ticket-result-title">{{ pageTitle }}</span>
<div class="ticket-result-actions">
<el-button
v-if="String(jobStatus) === '0'"
type="primary"
@click="handleSave"
:loading="submitLoading"
:disabled="hasImageUploading"
>
{{ t('MoldManagement.TicketResultDialog.save') }}
</el-button>
</div>
</div>
<el-descriptions :title="t('MoldManagement.MoldWorkOrderInquiry.basicInfo')" :column="4" border>
@ -141,14 +152,8 @@
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" />
<div class="ticket-result-footer">
<el-button v-if="String(jobStatus) === '0'" type="primary" @click="handleSave" :loading="submitLoading"
:disabled="hasImageUploading">
{{ t('MoldManagement.TicketResultDialog.save') }}
</el-button>
</div>
</ContentWrap>
</div>
</template>
@ -386,9 +391,9 @@ const parseImages = (value: any): string[] => {
color: var(--el-text-color-primary);
}
.ticket-result-footer {
.ticket-result-actions {
margin-left: auto;
display: flex;
justify-content: flex-end;
gap: 12px;
}
</style>

@ -41,6 +41,27 @@
<el-option v-for="opt in jobResultOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
</el-select>
</el-form-item>
<el-form-item :label="t('MoldManagement.MoldWorkOrderInquiry.operatorName')" prop="operator" v-show="showAllFilters">
<el-select
v-model="queryParams.operator"
filterable
:placeholder="t('MoldManagement.MoldWorkOrderInquiry.placeholderOperatorName')"
clearable
class="!w-240px"
>
<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="t('MoldManagement.MoldWorkOrderInquiry.taskTimeRange')" prop="taskTimeRange" v-show="showAllFilters">
<el-date-picker
v-model="queryParams.taskTimeRange"
value-format="YYYY-MM-DD HH:mm:ss"
type="datetimerange"
:start-placeholder="t('MoldManagement.MoldWorkOrderInquiry.placeholderTaskTime')"
:end-placeholder="t('MoldManagement.MoldWorkOrderInquiry.placeholderTaskEndTime')"
:default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
class="!w-240px" />
</el-form-item>
<el-form-item v-if="filterCount > 3">
<el-button type="text" class="text-primary" @click="toggleFilters">
<Icon :icon="showAllFilters ? 'ep:arrow-up' : 'ep:arrow-down'" class="mr-5px" />
@ -54,13 +75,16 @@
<el-button type="primary" @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> {{ t('MoldManagement.MoldWorkOrderInquiry.query') }}
</el-button>
<el-button type="success" plain @click="handleExport" :loading="exportLoading">
<Icon icon="ep:download" class="mr-5px" /> {{ t('MoldManagement.MoldWorkOrderInquiry.export') }}
</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 type="warning" plain @click="handleBatchCancel" :disabled="isCancelDisabled" :loading="cancelLoading">
{{ t('MoldManagement.MoldWorkOrderInquiry.cancelTask') }}
</el-button>
</div>
@ -125,6 +149,7 @@ import { dateFormatter } from '@/utils/formatTime'
import { getStrDictOptions } from '@/utils/dict'
import { useDictStoreWithOut } from '@/store/modules/dict'
import { TicketManagementApi, TicketManagementVO } from '@/api/mold/ticketManagement'
import { getSimpleUserList, UserVO } from '@/api/system/user'
import TicketResultDialog from '@/views/mold/workOrderInquiry/components/TicketResultDialog.vue'
const { t } = useI18n()
@ -139,8 +164,8 @@ const planTypeOptions = [
{ label: t('MoldManagement.MoldWorkOrderInquiry.planTypeMaintain'), value: '2' }
]
const jobResultOptions = [
{ label: t('MoldManagement.MoldWorkOrderInquiry.jobResultOk'), value: 'OK' },
{ label: t('MoldManagement.MoldWorkOrderInquiry.jobResultNg'), value: 'NG' }
{ label: t('MoldManagement.MoldWorkOrderInquiry.jobResultOk'), value: '1' },
{ label: t('MoldManagement.MoldWorkOrderInquiry.jobResultNg'), value: '2' }
]
const loading = ref(true)
@ -159,7 +184,10 @@ const updatePlanTableMaxHeight = async () => {
planTableMaxHeight.value = Math.min(window.innerHeight, Math.max(240, Math.floor(availableHeight)))
}
const selectedIds = ref<number[]>([])
const selectedRows = ref<TicketManagementVO[]>([])
const cancelLoading = ref(false)
const exportLoading = ref(false)
const users = ref<UserVO[]>([])
const resultVisible = ref(false)
const selectedResultRow = ref<TicketManagementVO>()
const resultTitle = computed(() => {
@ -175,22 +203,36 @@ const queryParams = reactive({
pageSize: 10,
planNo: undefined as string | undefined,
planType: undefined as string | undefined,
jobStatus: undefined as string | undefined,
jobResult: undefined as string | undefined
jobStatus: '0' as string | undefined,
jobResult: undefined as string | undefined,
operator: undefined as string | undefined,
taskTimeRange: [] as string[]
})
const queryFormRef = ref()
const showAllFilters = ref(false)
const filterCount = 4
const filterCount = 6
const UNWORKED_JOB_STATUS = '0'
const CANCELED_JOB_STATUS = '4'
const toggleFilters = () => {
showAllFilters.value = !showAllFilters.value
updatePlanTableMaxHeight()
}
const buildQueryParams = () => {
const { taskTimeRange, ...params } = queryParams
return {
...params,
taskTime: taskTimeRange?.[0],
taskEndTime: taskTimeRange?.[1]
}
}
const getList = async () => {
loading.value = true
try {
const data = await TicketManagementApi.getTicketManagementPage(queryParams)
const data = await TicketManagementApi.getTicketManagementPage(buildQueryParams())
list.value = data.list
total.value = data.total
} finally {
@ -210,13 +252,22 @@ const resetQuery = () => {
}
const handleSelectionChange = (rows: TicketManagementVO[]) => {
selectedRows.value = rows
selectedIds.value = rows
.map((r) => r.id)
.filter((id): id is number => typeof id === 'number')
}
const isUnworkedTicket = (row?: TicketManagementVO) => String(row?.jobStatus ?? '') === UNWORKED_JOB_STATUS
const hasUncancelableSelection = computed(() => selectedRows.value.some((row) => !isUnworkedTicket(row)))
const isCancelDisabled = computed(() => !selectedIds.value.length || hasUncancelableSelection.value)
const handleBatchCancel = async () => {
if (!selectedIds.value.length) return
if (hasUncancelableSelection.value) {
message.warning(t('MoldManagement.MoldWorkOrderInquiry.cancelOnlyUnworkedTip'))
return
}
try {
const { value } = await ElMessageBox.prompt('请输入取消原因', t('MoldManagement.MoldWorkOrderInquiry.cancelTask'), {
confirmButtonText: t('common.ok'),
@ -227,11 +278,12 @@ const handleBatchCancel = async () => {
cancelLoading.value = true
await TicketManagementApi.batchUpdateTicketStatus({
ids: selectedIds.value.join(','),
jobStatus: '4',
jobStatus: CANCELED_JOB_STATUS,
cancelReason: value
})
message.success(t('MoldManagement.MoldWorkOrderInquiry.cancelSuccess'))
selectedIds.value = []
selectedRows.value = []
await getList()
} catch {
} finally {
@ -239,6 +291,23 @@ const handleBatchCancel = async () => {
}
}
const handleExport = async () => {
try {
await message.exportConfirm()
exportLoading.value = true
const params: any = {
...buildQueryParams(),
ids: selectedIds.value.length ? selectedIds.value.join(',') : undefined
}
const data = await TicketManagementApi.exportTicketManagement(params)
const download = (await import('@/utils/download')).default
download.excel(data, t('MoldManagement.MoldWorkOrderInquiry.exportFilename'))
} catch {
} finally {
exportLoading.value = false
}
}
const handleRowClick = (row: TicketManagementVO, column: any) => {
if (column?.type === 'selection') return
if (!row?.id) return
@ -259,6 +328,7 @@ const handleResultSuccess = async () => {
onMounted(async () => {
await dictStore.setDictMap()
users.value = await getSimpleUserList()
await getList()
updatePlanTableMaxHeight()
window.addEventListener("resize", updatePlanTableMaxHeight)
@ -268,3 +338,4 @@ onBeforeUnmount(() => {
window.removeEventListener("resize", updatePlanTableMaxHeight)
})
</script>

Loading…
Cancel
Save