You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

450 lines
10 KiB

<template>
<Drawer
v-model:open="visible"
title="修改合同法规"
width="80%"
:destroyOnClose="true"
class="edit-regulation-drawer"
placement="right"
>
<template #extra>
<Space>
<Button @click="handleCancel">取消</Button>
<Button type="primary" @click="handleSubmit" :loading="loading">保存</Button>
</Space>
</template>
<div class="edit-container">
<!-- 左侧PDF预览 -->
<div class="pdf-preview-section">
<div class="section-title">
<FileTextOutlined />
<span>法规文档预览</span>
<Button type="link" size="small" @click="refreshPdf" :loading="pdfLoading">
<ReloadOutlined />
</Button>
</div>
<div class="pdf-container">
<div v-if="pdfLoading" class="loading-container">
<Spin size="large" tip="正在加载文档..." />
</div>
<div v-else-if="pdfError" class="error-container">
<Result
status="error"
:title="pdfError"
sub-title="请检查网络连接或联系管理员"
>
<template #extra>
<Button type="primary" @click="refreshPdf">重新加载</Button>
</template>
</Result>
</div>
<div v-else-if="pdfUrl" class="pdf-embed-container">
<embed
:src="pdfUrl"
type="application/pdf"
width="100%"
height="100%"
style="border: none; display: block;"
/>
</div>
<div v-else class="no-pdf-container">
<Empty description="暂无PDF文档" />
</div>
</div>
</div>
<!-- 右侧修改表单 -->
<div class="edit-form-section">
<div class="section-title">
<EditOutlined />
<span>修改信息</span>
</div>
<div class="form-container">
<Form
ref="formRef"
:model="formData"
:rules="rules"
layout="vertical"
class="edit-form"
>
<!-- 法规名称 -->
<FormItem label="法规名称" name="regulationName" required>
<Input
v-model:value="formData.regulationName"
placeholder="请输入法规名称"
size="large"
/>
</FormItem>
<!-- 法规描述 -->
<FormItem label="法规描述" name="regulationDescription" required>
<TextArea
v-model:value="formData.regulationDescription"
placeholder="请输入法规描述"
:rows="6"
show-count
:maxlength="500"
size="large"
/>
</FormItem>
<!-- 发布日期 -->
<FormItem label="发布日期" name="publishDate" required>
<DatePicker
v-model:value="formData.publishDate"
format="YYYY-MM-DD"
valueFormat="YYYY-MM-DD"
style="width: 100%"
size="large"
/>
</FormItem>
<!-- 是否有效 -->
<FormItem label="是否有效" name="isEffective">
<Select
v-model:value="formData.isEffective"
:options="effectiveOptions"
size="large"
/>
</FormItem>
</Form>
</div>
</div>
</div>
</Drawer>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch, onUnmounted } from 'vue';
import {
Drawer,
Form,
FormItem,
Input,
DatePicker,
Select,
Button,
Space,
Spin,
Result,
Empty,
message
} from 'ant-design-vue';
import {
FileTextOutlined,
EditOutlined,
ReloadOutlined
} from '@ant-design/icons-vue';
import {
ContractualRegulationNamesInfo,
ContractualRegulationNamesUpdate,
ContractualRegulationNamesViewPdf
} from '@/api/contractReview/ContractualRegulationNames';
import { getDictOptions } from '@/utils/dict';
import dayjs from 'dayjs';
const { TextArea } = Input;
interface Props {
visible: boolean;
regulationId?: number | string;
}
const props = withDefaults(defineProps<Props>(), {
visible: false,
regulationId: undefined
});
const emit = defineEmits<{
'update:visible': [value: boolean];
'success': [];
}>();
// 状态变量
const loading = ref(false);
const pdfLoading = ref(false);
const pdfError = ref('');
const pdfUrl = ref('');
const formRef = ref();
// 表单数据
const formData = reactive({
id: undefined as string | number | undefined,
regulationName: '',
regulationDescription: '',
publishDate: '',
isEffective: 'Y'
});
// 计算属性
const visible = computed({
get: () => props.visible,
set: (value) => emit('update:visible', value)
});
// 表单验证规则
const rules = computed(() => ({
regulationName: [{ required: true, message: '请输入法规名称', trigger: 'blur' }],
regulationDescription: [{ required: true, message: '请输入法规描述', trigger: 'blur' }],
publishDate: [{ required: true, message: '请选择发布日期', trigger: 'change' }],
}));
// 字典选项
const effectiveOptions = getDictOptions('sys_yes_no');
// 监听弹窗显示
watch(() => props.visible, (newVisible) => {
if (newVisible && props.regulationId) {
loadRegulationData();
loadPdf();
} else if (!newVisible) {
resetForm();
cleanupPdfUrl();
}
});
// 加载法规数据
async function loadRegulationData() {
if (!props.regulationId) return;
try {
const result = await ContractualRegulationNamesInfo(props.regulationId);
if (result) {
formData.id = result.id;
formData.regulationName = result.regulationName || '';
formData.regulationDescription = result.regulationDescription || '';
formData.publishDate = result.publishDate || '';
formData.isEffective = result.isEffective || 'Y';
}
} catch (error: any) {
message.error('加载法规信息失败: ' + (error.message || '未知错误'));
}
}
// 加载PDF
async function loadPdf() {
if (!props.regulationId) return;
pdfLoading.value = true;
pdfError.value = '';
try {
const pdfResponse = await ContractualRegulationNamesViewPdf(props.regulationId);
if (pdfResponse?.data) {
// 清理之前的URL
cleanupPdfUrl();
// 创建新的Blob URL
const blob = new Blob([pdfResponse.data], { type: 'application/pdf' });
pdfUrl.value = URL.createObjectURL(blob);
} else {
pdfError.value = 'PDF数据格式错误';
}
} catch (err: any) {
pdfError.value = err.message || '加载PDF失败';
console.error('加载PDF失败:', err);
} finally {
pdfLoading.value = false;
}
}
// 刷新PDF
function refreshPdf() {
loadPdf();
}
// 提交表单
async function handleSubmit() {
try {
await formRef.value?.validate();
} catch (error) {
return;
}
loading.value = true;
try {
const submitData = {
...formData,
publishDate: formData.publishDate ? dayjs(formData.publishDate).format('YYYY-MM-DD') : ''
};
await ContractualRegulationNamesUpdate(submitData);
message.success('修改成功');
emit('update:visible', false);
emit('success');
} catch (error: any) {
message.error('修改失败: ' + (error.message || '未知错误'));
} finally {
loading.value = false;
}
}
// 取消
function handleCancel() {
emit('update:visible', false);
}
// 重置表单
function resetForm() {
Object.assign(formData, {
id: undefined,
regulationName: '',
regulationDescription: '',
publishDate: '',
isEffective: 'Y'
});
formRef.value?.clearValidate();
pdfError.value = '';
}
// 清理Blob URL
function cleanupPdfUrl() {
if (pdfUrl.value && pdfUrl.value.startsWith('blob:')) {
URL.revokeObjectURL(pdfUrl.value);
pdfUrl.value = '';
}
}
// 组件销毁时清理
onUnmounted(() => {
cleanupPdfUrl();
});
</script>
<style scoped>
.edit-regulation-drawer {
:deep(.ant-drawer-content) {
height: 100vh;
}
:deep(.ant-drawer-body) {
padding: 0;
height: calc(100vh - 55px);
}
}
.edit-container {
display: flex;
height: 100%;
gap: 1px;
background: #f0f2f5;
}
.pdf-preview-section {
flex: 1;
background: #fff;
display: flex;
flex-direction: column;
}
.edit-form-section {
width: 400px;
background: #fff;
display: flex;
flex-direction: column;
border-left: 1px solid #e8e8e8;
}
.section-title {
padding: 16px 20px;
font-size: 16px;
font-weight: 500;
color: #262626;
border-bottom: 1px solid #e8e8e8;
display: flex;
align-items: center;
gap: 8px;
background: #fafafa;
span {
flex: 1;
}
}
.pdf-container {
flex: 1;
position: relative;
background: #f5f5f5;
.loading-container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.error-container {
padding: 40px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.pdf-embed-container {
height: 100%;
padding: 16px;
embed {
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
}
.no-pdf-container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
}
.form-container {
flex: 1;
padding: 20px;
overflow-y: auto;
}
.edit-form {
.ant-form-item {
margin-bottom: 24px;
}
.ant-form-item-label > label {
font-weight: 500;
color: #262626;
}
}
/* 响应式设计 */
@media (max-width: 1400px) {
.edit-form-section {
width: 380px;
}
}
@media (max-width: 1200px) {
.edit-container {
flex-direction: column;
}
.pdf-preview-section {
height: 50%;
}
.edit-form-section {
width: 100%;
height: 50%;
border-left: none;
border-top: 1px solid #e8e8e8;
}
}
</style>