Industrial-image-management.../src/views/system-resource/device-management/approval/components/ApprovalActionModal.vue

355 lines
9.1 KiB
Vue
Raw Normal View History

<template>
<a-modal
v-model:visible="visible"
:title="modalTitle"
width="600px"
@ok="handleSubmit"
@cancel="handleCancel"
:confirm-loading="loading"
>
<div class="approval-action" v-if="approvalData">
<!-- 审批信息预览 -->
<div class="preview-section">
<h4 class="preview-title">
<IconInfoCircle style="margin-right: 8px; color: var(--color-primary);" />
审批信息预览
</h4>
<a-descriptions :column="1" bordered size="small">
<a-descriptions-item label="设备名称">
{{ approvalData.equipmentName }}
</a-descriptions-item>
<a-descriptions-item label="设备类型">
{{ approvalData.equipmentType }}
</a-descriptions-item>
<a-descriptions-item label="设备型号">
{{ approvalData.equipmentModel }}
</a-descriptions-item>
<a-descriptions-item label="申请人">
{{ approvalData.applicantName }}
</a-descriptions-item>
<a-descriptions-item label="申请时间">
{{ formatDateTime(approvalData.applyTime) }}
</a-descriptions-item>
<a-descriptions-item label="总价">
<span v-if="approvalData.totalPrice" class="price-text">
¥{{ formatPrice(approvalData.totalPrice) }}
</span>
<span v-else class="no-data">-</span>
</a-descriptions-item>
</a-descriptions>
</div>
<!-- 审批表单 -->
<div class="form-section">
<h4 class="form-title">
<IconEdit style="margin-right: 8px; color: var(--color-warning);" />
审批意见
</h4>
<a-form
ref="formRef"
:model="formData"
:rules="rules"
layout="vertical"
>
<a-form-item field="approvalComment" label="审批意见" class="form-item">
<a-textarea
v-model="formData.approvalComment"
:placeholder="actionType === 'approve' ? '请输入审批通过的意见(可选)' : '请输入审批拒绝的原因(必填)'"
:rows="4"
class="form-textarea"
allow-clear
/>
</a-form-item>
</a-form>
</div>
<!-- 确认提示 -->
<div class="confirm-section">
<a-alert
:type="actionType === 'approve' ? 'success' : 'error'"
:title="actionType === 'approve' ? '审批通过确认' : '审批拒绝确认'"
:description="actionType === 'approve' ? '确认通过此设备采购申请吗?通过后该申请将进入采购流程。' : '确认拒绝此设备采购申请吗?拒绝后申请人将收到通知。'"
show-icon
/>
</div>
</div>
</a-modal>
</template>
<script lang="ts" setup>
import { computed, reactive, ref, watch } from 'vue'
import { IconInfoCircle, IconEdit } from '@arco-design/web-vue/es/icon'
import message from '@arco-design/web-vue/es/message'
import type { EquipmentApprovalResp, EquipmentApprovalReq } from '@/apis/equipment/type'
import { equipmentApprovalApi } from '@/apis/equipment/approval'
import notificationService from '@/services/notificationService'
defineOptions({ name: 'ApprovalActionModal' })
// Props
interface Props {
visible: boolean
approvalData: EquipmentApprovalResp | null
actionType: 'approve' | 'reject'
}
const props = defineProps<Props>()
// Emits
const emit = defineEmits<{
'update:visible': [value: boolean]
success: []
}>()
// 计算属性
const visible = computed({
get: () => props.visible,
set: (value) => emit('update:visible', value)
})
const modalTitle = computed(() => {
return props.actionType === 'approve' ? '审批通过' : '审批拒绝'
})
// 表单相关
const formRef = ref()
const loading = ref(false)
const formData = reactive<EquipmentApprovalReq>({
approvalComment: '',
approvalResult: props.actionType === 'approve' ? 'APPROVED' : 'REJECTED',
approverName: '当前用户', // 这里应该从用户认证系统获取
approverId: 'current-user-id' // 这里应该从用户认证系统获取
})
// 表单验证规则
const rules = computed(() => ({
approvalComment: props.actionType === 'reject' ? [
{ required: true, message: '请输入审批拒绝的原因' }
] : []
}))
// 格式化价格
const formatPrice = (price: number) => {
return price.toLocaleString('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})
}
// 格式化日期时间
const formatDateTime = (dateTime: string) => {
if (!dateTime) return '-'
const date = new Date(dateTime)
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
})
}
// 提交审批
const handleSubmit = async () => {
try {
await formRef.value.validate()
if (!props.approvalData) {
message.error('审批数据不存在')
return
}
loading.value = true
const approvalId = props.approvalData.approvalId
const submitData: EquipmentApprovalReq = {
approvalComment: formData.approvalComment,
approvalResult: props.actionType === 'approve' ? 'APPROVED' : 'REJECTED',
approverName: formData.approverName,
approverId: formData.approverId
}
console.log('提交审批数据:', submitData)
if (props.actionType === 'approve') {
await equipmentApprovalApi.approve(approvalId, submitData)
message.success('审批通过成功')
// 添加审批通过通知
notificationService.addApprovalNotification(
props.approvalData.equipmentName,
'APPROVED',
formData.approverName || '审批人'
)
} else {
await equipmentApprovalApi.reject(approvalId, submitData)
message.success('审批拒绝成功')
// 添加审批拒绝通知
notificationService.addApprovalNotification(
props.approvalData.equipmentName,
'REJECTED',
formData.approverName || '审批人'
)
}
emit('success')
visible.value = false
resetForm()
} catch (error: any) {
console.error('审批操作失败:', error)
message.error(error?.message || '审批操作失败')
} finally {
loading.value = false
}
}
// 取消
const handleCancel = () => {
visible.value = false
resetForm()
}
// 重置表单
const resetForm = () => {
Object.assign(formData, {
approvalComment: '',
approvalResult: props.actionType === 'approve' ? 'APPROVED' : 'REJECTED',
approverName: '当前用户',
approverId: 'current-user-id'
})
formRef.value?.resetFields()
}
// 监听弹窗显示状态,重置表单
watch(() => props.visible, (newVal) => {
if (newVal) {
resetForm()
}
})
</script>
<style scoped lang="scss">
.approval-action {
.preview-section {
margin-bottom: 24px;
.preview-title {
display: flex;
align-items: center;
margin-bottom: 16px;
font-size: 14px;
font-weight: 600;
color: var(--color-text-1);
}
.arco-descriptions {
.arco-descriptions-item-label {
font-weight: 500;
color: var(--color-text-1);
background-color: var(--color-fill-1);
}
.arco-descriptions-item-value {
color: var(--color-text-2);
}
}
}
.form-section {
margin-bottom: 24px;
.form-title {
display: flex;
align-items: center;
margin-bottom: 16px;
font-size: 14px;
font-weight: 600;
color: var(--color-text-1);
}
.form-item {
.arco-form-item-label {
font-weight: 500;
color: var(--color-text-1);
margin-bottom: 8px;
}
.form-textarea {
border-radius: 6px;
border: 1px solid var(--color-border);
transition: all 0.2s ease;
&:hover {
border-color: var(--color-primary-light-3);
}
&:focus,
&.arco-textarea-focus {
border-color: var(--color-primary);
box-shadow: 0 0 0 2px rgba(var(--primary-6), 0.1);
}
.arco-textarea-inner {
padding: 12px;
font-size: 14px;
line-height: 1.6;
}
}
}
}
.confirm-section {
.arco-alert {
border-radius: 6px;
.arco-alert-title {
font-weight: 600;
}
.arco-alert-description {
color: var(--color-text-2);
line-height: 1.5;
}
}
}
.price-text {
color: #f56c6c;
font-weight: 500;
}
.no-data {
color: var(--color-text-4);
font-style: italic;
}
}
// 响应式设计
@media (max-width: 768px) {
.approval-action {
.preview-section,
.form-section {
.arco-descriptions {
.arco-descriptions-item {
display: block;
.arco-descriptions-item-label {
display: block;
width: 100%;
text-align: left;
padding: 8px 12px;
}
.arco-descriptions-item-value {
display: block;
width: 100%;
padding: 8px 12px;
}
}
}
}
}
}
</style>