| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544 |
- <template>
- <el-dialog
- v-model="dialogVisible"
- :title="dialogTitle"
- width="1000px"
- destroy-on-close
- @close="handleClose"
- >
- <ContentWrap>
- <!-- 设备清单 -->
- <div class="mb-4">
- <!-- 部分报告模式:只显示单个设备信息 -->
- <template v-if="props.isPartReport">
- <div class="flex justify-between items-center mb-2">
- <h4>设备信息</h4>
- </div>
-
- <el-table
- :data="partReportEquipmentList"
- size="small"
- border
- >
- <el-table-column label="设备注册代码" prop="equipCode" min-width="150px" />
- <el-table-column label="使用证编号" prop="useRegisterNo" min-width="120px" />
- <el-table-column label="设备名称" prop="equipName" min-width="120px" />
- <el-table-column label="出具报告状态" width="120px" align="center">
- <template #default="scope">
- {{ getReportStatusText(scope.row) }}
- </template>
- </el-table-column>
- </el-table>
- </template>
-
- <!-- 完整报告模式:显示所有设备和操作功能 -->
- <template v-else>
- <div class="flex justify-between items-center mb-2">
- <h4>设备清单</h4>
- <div class="flex items-center gap-4">
- <el-input
- v-model="searchKeyword"
- placeholder="搜索设备注册代码、使用证编号或设备名称"
- size="small"
- style="width: 300px"
- clearable
- prefix-icon="Search"
- />
- <div class="text-sm text-gray-600">
- {{ searchResultText }}
- </div>
- </div>
- </div>
-
- <!-- 批量操作按钮 -->
- <div class="flex items-center gap-2 mb-3">
- <el-button
- size="small"
- type="success"
- :disabled="tableSelectedRows.length === 0"
- @click="batchAddEquipments"
- >
- 批量添加 ({{ tableSelectedRows.length }})
- </el-button>
- <el-button
- size="small"
- type="warning"
- :disabled="tableSelectedRows.length === 0"
- @click="batchRemoveEquipments"
- >
- 批量移除 ({{ tableSelectedRows.length }})
- </el-button>
- <el-divider direction="vertical" />
- <el-button
- size="small"
- link
- @click="selectAllRows"
- >
- 全选
- </el-button>
- <el-button
- size="small"
- link
- @click="clearSelection"
- >
- 全不选
- </el-button>
- <el-button
- size="small"
- link
- @click="toggleSelection"
- >
- 反选
- </el-button>
- </div>
-
- <el-table
- ref="tableRef"
- :data="filteredEquipmentList"
- size="small"
- border
- :row-class-name="getRowClassName"
- v-loading="equipmentLoading"
- @selection-change="handleSelectionChange"
- >
- <el-table-column type="selection" width="50" />
- <el-table-column label="设备注册代码" prop="equipCode" min-width="150px" />
- <el-table-column label="使用证编号" prop="useRegisterNo" min-width="120px" />
- <el-table-column label="设备名称" prop="equipName" min-width="120px" />
- <el-table-column label="出具报告状态" width="120px" align="center">
- <template #default="scope">
- {{ getReportStatusText(scope.row) }}
- </template>
- </el-table-column>
- <el-table-column label="操作" width="120px" align="center">
- <template #default="scope">
- <el-button
- v-if="scope.row.selected"
- link
- type="danger"
- size="small"
- @click="toggleEquipmentSelection(scope.row, false)"
- >
- 移除
- </el-button>
- <el-button
- v-else
- link
- type="primary"
- size="small"
- @click="toggleEquipmentSelection(scope.row, true)"
- >
- 添加
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- </template>
- </div>
- <!-- 动态表单区域 -->
- <div class="form-section">
- <!-- 实体报告表单 -->
- <EntityReportForm
- v-if="props.reportType === PressureIssueReportType.ENTITY"
- ref="entityFormRef"
- v-model="formData.entityForm"
- :is-part-report="props.isPartReport"
- @validate-change="handleFormValidateChange"
- />
-
- <!-- 电子报告表单 -->
- <ElectronicReportForm
- v-if="props.reportType === PressureIssueReportType.ELECTRONIC"
- ref="electronicFormRef"
- v-model="formData.electronicForm"
- :is-part-report="props.isPartReport"
- @validate-change="handleFormValidateChange"
- />
- </div>
- </ContentWrap>
- <template #footer>
- <div class="dialog-footer">
- <el-button @click="handleClose">取消</el-button>
- <el-button type="primary" @click="handleConfirm" :loading="submitting">
- 确定
- </el-button>
- </div>
- </template>
- </el-dialog>
- </template>
- <script setup lang="ts">
- import { ref, computed, watch, onMounted } from 'vue'
- import { ElMessage } from 'element-plus'
- import EntityReportForm from './EntityReportForm.vue'
- import ElectronicReportForm from './ElectronicReportForm.vue'
- import { BoilerTaskOrderApi } from '@/api/pressure2/boilertaskorder'
- import { PressureIssueReportType, PressureIssueReportChecklistType } from '@/utils/constants'
- export interface IssueReportDialogProps {
- visible: boolean
- taskOrderId: string
- reportType: number // 实体报告 | 电子报告
- defaultReportScope?: number // 默认报告清单类型
- defaultSelectedEquipments?: any[] // 默认选中的设备
- isPartReport?: boolean // 是否部分报告
- }
- const props = withDefaults(defineProps<IssueReportDialogProps>(), {
- visible: false,
- taskOrderId: '',
- reportType: PressureIssueReportType.ENTITY,
- defaultReportScope: PressureIssueReportChecklistType.ALL,
- defaultSelectedEquipments: () => [],
- isPartReport: false
- })
- const emit = defineEmits<{
- 'update:visible': [value: boolean]
- 'confirm': [data: any]
- }>()
- // 对话框状态
- const dialogVisible = ref(false)
- const submitting = ref(false)
- const equipmentLoading = ref(false)
- // 表单数据
- const formData = ref({
- entityForm: {},
- electronicForm: {}
- })
- // 设备清单数据
- const equipmentList = ref<any[]>([])
- const taskOrderDetail = ref<any>(null)
- // 表格选择状态
- const tableSelectedRows = ref<any[]>([])
- const tableRef = ref()
- // 搜索状态
- const searchKeyword = ref('')
- // 表单验证状态
- const isFormValid = ref(true)
- // 子组件引用
- const entityFormRef = ref()
- const electronicFormRef = ref()
- // 计算属性
- const dialogTitle = computed(() => {
- return props.reportType === PressureIssueReportType.ENTITY ? '出具实体报告' : '出具电子报告'
- })
- // 选中设备数量
- const selectedCount = computed(() => {
- if (props.isPartReport) {
- return partReportEquipmentList.value.length
- }
- return equipmentList.value.filter(item => item.selected).length
- })
- // 总设备数量
- const totalCount = computed(() => {
- if (props.isPartReport) {
- return partReportEquipmentList.value.length
- }
- return equipmentList.value.length
- })
- // 部分报告的设备列表
- const partReportEquipmentList = computed(() => {
- if (props.isPartReport && props.defaultSelectedEquipments?.length > 0) {
- return props.defaultSelectedEquipments.map(item => ({
- ...item,
- selected: true
- }))
- }
- return []
- })
- // 过滤后的设备列表
- const filteredEquipmentList = computed(() => {
- if (!searchKeyword.value.trim()) {
- return equipmentList.value
- }
-
- const keyword = searchKeyword.value.toLowerCase().trim()
- return equipmentList.value.filter(item => {
- const equipCode = (item.equipCode || '').toLowerCase()
- const useRegisterNo = (item.useRegisterNo || '').toLowerCase()
- const equipName = (item.equipName || '').toLowerCase()
-
- return equipCode.includes(keyword) ||
- useRegisterNo.includes(keyword) ||
- equipName.includes(keyword)
- })
- })
- // 搜索结果文本
- const searchResultText = computed(() => {
- const filteredCount = filteredEquipmentList.value.length
- const selectedInFilteredCount = filteredEquipmentList.value.filter(item => item.selected).length
-
- if (searchKeyword.value.trim()) {
- return `搜索到 ${filteredCount} 台设备,已选择 ${selectedInFilteredCount} 台`
- } else {
- return `已选择 ${selectedCount.value} / ${totalCount.value} 台设备`
- }
- })
- // 报告状态文本
- const getReportStatusText = (row: any) => {
- if (row.isIssueReport === 1) return '已出具'
- if (row.isIssueReport === 0) return '未出具'
- return '-'
- }
- // 监听visible变化
- watch(() => props.visible, (newVal) => {
- dialogVisible.value = newVal
- if (newVal) {
- resetForm()
- if (!props.isPartReport) {
- loadTaskOrderDetail()
- }
- }
- }, { immediate: true })
- // 监听dialogVisible变化
- watch(dialogVisible, (newVal) => {
- emit('update:visible', newVal)
- })
- // 加载任务单详情
- const loadTaskOrderDetail = async () => {
- if (!props.taskOrderId) return
-
- try {
- equipmentLoading.value = true
- const response = await TaskOrderApi.getTaskOrder(props.taskOrderId)
- taskOrderDetail.value = response
-
- // 设置设备清单,默认全部选中
- equipmentList.value = (response.orderItems || []).map(item => ({
- ...item,
- selected: true
- }))
- } catch (error) {
- console.error('加载任务单详情失败:', error)
- ElMessage.error('加载任务单详情失败')
- } finally {
- equipmentLoading.value = false
- }
- }
- // 切换设备选择状态
- const toggleEquipmentSelection = (equipment: any, selected: boolean) => {
- const index = equipmentList.value.findIndex(item => item.id === equipment.id)
- if (index > -1) {
- equipmentList.value[index].selected = selected
- }
- }
- // 表格选择变化
- const handleSelectionChange = (selection: any[]) => {
- tableSelectedRows.value = selection
- }
- // 批量添加设备
- const batchAddEquipments = () => {
- tableSelectedRows.value.forEach(equipment => {
- const index = equipmentList.value.findIndex(item => item.id === equipment.id)
- if (index > -1) {
- equipmentList.value[index].selected = true
- }
- })
- ElMessage.success(`已添加 ${tableSelectedRows.value.length} 台设备`)
- clearSelection()
- }
- // 批量移除设备
- const batchRemoveEquipments = () => {
- tableSelectedRows.value.forEach(equipment => {
- const index = equipmentList.value.findIndex(item => item.id === equipment.id)
- if (index > -1) {
- equipmentList.value[index].selected = false
- }
- })
- ElMessage.success(`已移除 ${tableSelectedRows.value.length} 台设备`)
- clearSelection()
- }
- // 全选
- const selectAllRows = () => {
- if (tableRef.value) {
- tableRef.value.toggleAllSelection()
- }
- }
- // 清除选择
- const clearSelection = () => {
- if (tableRef.value) {
- tableRef.value.clearSelection()
- }
- }
- // 反选
- const toggleSelection = () => {
- if (tableRef.value) {
- filteredEquipmentList.value.forEach(row => {
- tableRef.value.toggleRowSelection(row, !tableSelectedRows.value.includes(row))
- })
- }
- }
- // 表格行样式
- const getRowClassName = ({ row }: { row: any }) => {
- return row.selected ? '' : 'disabled-row'
- }
- // 表单验证状态变化
- const handleFormValidateChange = (valid: boolean) => {
- isFormValid.value = valid
- }
- // 重置表单
- const resetForm = () => {
- formData.value = {
- entityForm: {} as any,
- electronicForm: {} as any
- }
- equipmentList.value = []
- tableSelectedRows.value = []
- searchKeyword.value = ''
- isFormValid.value = true
- }
- // 确认提交
- const handleConfirm = async () => {
- // 验证基础表单
- const selectedEquipments = props.isPartReport
- ? partReportEquipmentList.value
- : equipmentList.value.filter(item => item.selected)
-
- if (selectedEquipments.length === 0) {
- ElMessage.warning('请选择需要出具报告的设备')
- return
- }
- // 验证子表单
- let subFormValid = false
- if (props.reportType === PressureIssueReportType.ENTITY && entityFormRef.value) {
- subFormValid = await entityFormRef.value.validate()
- } else if (props.reportType === PressureIssueReportType.ELECTRONIC && electronicFormRef.value) {
- subFormValid = await electronicFormRef.value.validate()
- }
- if (!subFormValid) {
- ElMessage.warning('请填写完整的表单信息')
- return
- }
- try {
- submitting.value = true
-
- const entityForm: any = formData.value.entityForm || {}
- const electronicForm: any = formData.value.electronicForm || {}
-
- // 判断报告类型:全部设备选中为全部报告,否则为部分报告
- const checklistType = selectedEquipments.length === totalCount.value ?
- PressureIssueReportChecklistType.ALL : PressureIssueReportChecklistType.PART
-
- // 构建提交数据,按照API文档格式
- const itemList = selectedEquipments.map(item => item.id)
-
- const submitData = {
- orderId: props.taskOrderId,
- checklistType: checklistType,
- reportType: props.reportType,
-
- // 实体报告字段
- issueMethod: props.reportType === PressureIssueReportType.ENTITY ? entityForm.deliveryType : null,
- recipient: entityForm.recipient || entityForm.pickupPerson || '',
- recipientPhone: entityForm.recipientPhone || entityForm.pickupPhone || '',
- recipientAddress: entityForm.recipientAddress || '',
- trackingNumber: entityForm.expressNo || '',
- trackingCompany: entityForm.expressCompany || '',
- remark: entityForm.remark || '',
- copyNumber: parseInt(entityForm.printCount) || 1,
- businessMan: entityForm.salesperson || '',
- otherMethod: entityForm.otherDescription || '',
-
- // 电子报告字段
- miniProgramPush: props.reportType === PressureIssueReportType.ELECTRONIC ? electronicForm.deliveryType?.includes('miniprogram') : false,
- emailPush: props.reportType === PressureIssueReportType.ELECTRONIC ? electronicForm.deliveryType?.includes('email') : false,
- email: electronicForm.emailAddress || '',
- miniProgramAdmin: props.reportType === PressureIssueReportType.ELECTRONIC ? electronicForm.miniprogramTarget?.includes('main') : false,
- miniProgramSubAccount: props.reportType === PressureIssueReportType.ELECTRONIC ? electronicForm.miniprogramTarget?.includes('sub') : false,
-
- // 设备列表
- itemList: itemList
- }
-
- // 调用API
- await TaskOrderApi.issueReport(submitData)
-
- emit('confirm', submitData)
- ElMessage.success('出具报告成功')
- handleClose()
-
- } catch (error) {
- console.error('出具报告失败:', error)
- ElMessage.error('出具报告失败')
- } finally {
- submitting.value = false
- }
- }
- // 关闭对话框
- const handleClose = () => {
- dialogVisible.value = false
- }
- // 暴露方法
- defineExpose({
- resetForm
- })
- </script>
- <style lang="scss" scoped>
- .form-section {
- margin-top: 16px;
- }
- .dialog-footer {
- text-align: right;
- }
- :deep(.el-badge__content) {
- background-color: var(--el-color-primary);
- }
- // 禁用行样式
- :deep(.disabled-row) {
- background-color: var(--el-fill-color-light);
- color: var(--el-text-color-disabled);
-
- td {
- background-color: var(--el-fill-color-light) !important;
- }
- }
- // 设备清单表格样式
- :deep(.el-table) {
- .el-table__row {
- transition: background-color 0.2s ease;
- }
- }
- </style>
|