|
|
|
@ -11,14 +11,15 @@ |
|
|
|
:width="1000" |
|
|
|
:open="visibleFlag" |
|
|
|
@cancel="onClose" |
|
|
|
@afterClose="resetAfterClose" |
|
|
|
:maskClosable="false" |
|
|
|
:destroyOnClose="true" |
|
|
|
> |
|
|
|
<a-form ref="formRef" :model="form" :rules="rules" layout="vertical" > |
|
|
|
<a-form ref="formRef" :model="form" :rules="rules" layout="vertical"> |
|
|
|
<!-- 基本信息 --> |
|
|
|
<a-row :gutter="16"> |
|
|
|
<a-col :span="24"> |
|
|
|
<div style="font-weight: bold; font-size: 16px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 1px solid #d9d9d9;"> |
|
|
|
<div style="font-weight: bold; font-size: 16px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 1px solid #d9d9d9"> |
|
|
|
一、基础信息 |
|
|
|
</div> |
|
|
|
</a-col> |
|
|
|
@ -51,13 +52,12 @@ |
|
|
|
<!-- 服务信息 --> |
|
|
|
<a-row :gutter="16"> |
|
|
|
<a-col :span="24"> |
|
|
|
<div style="font-weight: bold; font-size: 16px; margin: 24px 0 16px 0; padding-bottom: 8px; border-bottom: 1px solid #d9d9d9;"> |
|
|
|
<div style="font-weight: bold; font-size: 16px; margin: 24px 0 16px 0; padding-bottom: 8px; border-bottom: 1px solid #d9d9d9"> |
|
|
|
二、服务信息 |
|
|
|
</div> |
|
|
|
</a-col> |
|
|
|
</a-row> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 活动信息 --> |
|
|
|
<a-row :gutter="16"> |
|
|
|
<a-col :span="8"> |
|
|
|
@ -87,25 +87,80 @@ |
|
|
|
</a-col> |
|
|
|
</a-row> |
|
|
|
|
|
|
|
<!-- 本所同行人代报律师选择 (当所选类目允许本所同行人代报时呈现) --> |
|
|
|
<a-row |
|
|
|
:gutter="16" |
|
|
|
v-if=" |
|
|
|
showBatchSelect && |
|
|
|
(!form.applicationId || form.firmAuditStatus == null || form.firmAuditStatus === 0) |
|
|
|
" |
|
|
|
> |
|
|
|
<a-col :span="24"> |
|
|
|
<a-form-item label="本所同行人代报(选填)" name="participantLawyerIds"> |
|
|
|
<a-select |
|
|
|
v-model:value="form.participantLawyerIds" |
|
|
|
mode="multiple" |
|
|
|
placeholder="不选择则仅申报本人;需要代报时可选择多名本所同行人" |
|
|
|
style="width: 100%" |
|
|
|
:disabled="readonlyMode" |
|
|
|
:options="sameFirmLawyerOptions" |
|
|
|
:filter-option="filterSameFirmLawyerOption" |
|
|
|
allow-clear |
|
|
|
/> |
|
|
|
<div style="color: #ff4d4f; font-size: 12px; margin-top: 4px"> |
|
|
|
注:仅显示本所已签署有效申报承诺书的律师;不选择则仅申报本人。 |
|
|
|
</div> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
</a-row> |
|
|
|
|
|
|
|
<!-- 已提交主记录的多人代报信息:选择控件隐藏后仍需在详情中可见。 --> |
|
|
|
<a-row :gutter="16" v-if="readonlyMode && Number(form.isBatch) === 1"> |
|
|
|
<a-col :span="24"> |
|
|
|
<a-form-item v-if="!form.parentApplicationId" label="同所同行人"> |
|
|
|
<a-input :value="peerParticipantNames" readonly /> |
|
|
|
</a-form-item> |
|
|
|
<a-form-item v-else label="代报人"> |
|
|
|
<a-input :value="form.declarerName || '-'" readonly /> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
</a-row> |
|
|
|
|
|
|
|
<!-- 根据活动类型显示不同字段 --> |
|
|
|
<template v-if="currentActivityType === 'DICT' || !currentActivityType"> |
|
|
|
<!-- dict类型:显示服务时长、服务开始时间和服务结束时间 --> |
|
|
|
<a-row :gutter="24"> |
|
|
|
<a-col :span="8"> |
|
|
|
<a-form-item label="服务开始时间" name="serviceStart" label-align="left"> |
|
|
|
<a-date-picker show-time format="YYYY-MM-DD HH:mm" valueFormat="YYYY-MM-DD HH:mm:ss" v-model:value="form.serviceStart" style="width: 100%" placeholder="服务开始时间" :disabled="readonlyMode" /> |
|
|
|
<a-date-picker |
|
|
|
show-time |
|
|
|
format="YYYY-MM-DD HH:mm" |
|
|
|
valueFormat="YYYY-MM-DD HH:mm:ss" |
|
|
|
v-model:value="form.serviceStart" |
|
|
|
style="width: 100%" |
|
|
|
placeholder="服务开始时间" |
|
|
|
:disabled="readonlyMode" |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
<a-col :span="8"> |
|
|
|
<a-form-item label="服务结束时间" name="serviceEnd" label-align="left"> |
|
|
|
<a-date-picker show-time format="YYYY-MM-DD HH:mm" valueFormat="YYYY-MM-DD HH:mm:ss" v-model:value="form.serviceEnd" style="width: 100%" placeholder="服务结束时间" :disabled="readonlyMode" /> |
|
|
|
<a-date-picker |
|
|
|
show-time |
|
|
|
format="YYYY-MM-DD HH:mm" |
|
|
|
valueFormat="YYYY-MM-DD HH:mm:ss" |
|
|
|
v-model:value="form.serviceEnd" |
|
|
|
style="width: 100%" |
|
|
|
placeholder="服务结束时间" |
|
|
|
:disabled="readonlyMode" |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
<a-col :span="8"> |
|
|
|
<a-form-item name="serviceDuration"> |
|
|
|
<template #label> |
|
|
|
<span>服务时长(小时)</span> |
|
|
|
<span style="color: #999; font-size: 12px; margin-left: 4px;">可通过时间选择也可手动填写</span> |
|
|
|
<span style="color: #999; font-size: 12px; margin-left: 4px">可通过时间选择也可手动填写</span> |
|
|
|
</template> |
|
|
|
<a-input-number |
|
|
|
style="width: 100%" |
|
|
|
@ -114,21 +169,35 @@ |
|
|
|
:disabled="readonlyMode" |
|
|
|
:min="0" |
|
|
|
:precision="1" |
|
|
|
:parser="value => value.replace(/[^\d.]/g, '')" |
|
|
|
:parser="(value) => value.replace(/[^\d.]/g, '')" |
|
|
|
@blur="handleServiceDurationBlur" |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
<div style="font-size: 12px; color: #f00d0dff; margin-top: -12px; margin-bottom: 12px;">注:不足30分钟(含30分钟)的,按照0.5小时填报,超过30分钟不足1小时的(含1小时),按照1小时填报。</div> |
|
|
|
<div style="font-size: 12px; color: #f00d0dff; margin-top: -12px; margin-bottom: 12px"> |
|
|
|
注:不足30分钟(含30分钟)的,按照0.5小时填报,超过30分钟不足1小时的(含1小时),按照1小时填报。 |
|
|
|
</div> |
|
|
|
</a-col> |
|
|
|
</a-row> |
|
|
|
</template> |
|
|
|
|
|
|
|
<template v-else-if="currentActivityType === 'TIME'"> |
|
|
|
<!-- time类型:显示案件编号和服务时长在一行 --> |
|
|
|
<!-- time类型:活动完成日期用于确定履职和成本季度 --> |
|
|
|
<a-row :gutter="16"> |
|
|
|
<a-col :span="8"> |
|
|
|
<a-form-item label="案件编号" name="recordNo" required> |
|
|
|
<a-input style="width: 100%" v-model:value="form.recordNo" placeholder="请输入案件编号" :disabled="readonlyMode" /> |
|
|
|
<a-form-item label="活动完成时间" name="serviceEnd" required> |
|
|
|
<a-date-picker |
|
|
|
format="YYYY-MM-DD" |
|
|
|
valueFormat="YYYY-MM-DD HH:mm:ss" |
|
|
|
v-model:value="form.serviceEnd" |
|
|
|
style="width: 100%" |
|
|
|
placeholder="请选择活动完成时间" |
|
|
|
:disabled="readonlyMode" |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
<a-col :span="8"> |
|
|
|
<a-form-item label="备案/案件编号" name="recordNo" required> |
|
|
|
<a-input style="width: 100%" v-model:value="form.recordNo" placeholder="请输入备案/案件编号" :disabled="readonlyMode" /> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
|
|
|
|
@ -137,7 +206,7 @@ |
|
|
|
<a-form-item name="serviceDuration"> |
|
|
|
<template #label> |
|
|
|
<span>服务时长(小时)</span> |
|
|
|
<span style="color: #999; font-size: 12px; margin-left: 4px;">请在{{ currentActivity.price }}范围内填写</span> |
|
|
|
<span style="color: #999; font-size: 12px; margin-left: 4px">请在{{ currentActivity.price }}范围内填写</span> |
|
|
|
</template> |
|
|
|
<a-input-number |
|
|
|
style="width: 100%" |
|
|
|
@ -146,7 +215,7 @@ |
|
|
|
:disabled="readonlyMode" |
|
|
|
:min="0" |
|
|
|
:precision="2" |
|
|
|
:parser="value => value.replace(/[^\d.]/g, '')" |
|
|
|
:parser="(value) => value.replace(/[^\d.]/g, '')" |
|
|
|
@blur="handleServiceDurationBlur" |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
@ -168,12 +237,32 @@ |
|
|
|
</a-row> |
|
|
|
</template> |
|
|
|
|
|
|
|
<template v-else-if="currentActivityType === 'AMOUT'"> |
|
|
|
<template v-else-if="['AMOUNT', 'AMOUT'].includes(currentActivityType)"> |
|
|
|
<!-- amount类型:显示金额输入框 --> |
|
|
|
<a-row :gutter="16"> |
|
|
|
<a-col :span="8"> |
|
|
|
<a-form-item label="费用发生时间" name="serviceEnd" required> |
|
|
|
<a-date-picker |
|
|
|
show-time |
|
|
|
format="YYYY-MM-DD HH:mm" |
|
|
|
valueFormat="YYYY-MM-DD HH:mm:ss" |
|
|
|
v-model:value="form.serviceEnd" |
|
|
|
style="width: 100%" |
|
|
|
placeholder="请选择费用发生时间" |
|
|
|
:disabled="readonlyMode" |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
<a-col :span="8"> |
|
|
|
<a-form-item label="金额" name="workloadScore"> |
|
|
|
<a-input-number style="width: 100%" v-model:value="form.workloadScore" placeholder="请输入金额" :disabled="readonlyMode" :min="0" :precision="2" /> |
|
|
|
<a-input-number |
|
|
|
style="width: 100%" |
|
|
|
v-model:value="form.workloadScore" |
|
|
|
placeholder="请输入金额" |
|
|
|
:disabled="readonlyMode" |
|
|
|
:min="0" |
|
|
|
:precision="2" |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
</a-row> |
|
|
|
@ -201,7 +290,12 @@ |
|
|
|
</a-col> |
|
|
|
<a-col :span="16"> |
|
|
|
<a-form-item label="联系方式" name="organizerPhone"> |
|
|
|
<a-input style="width: 100%" v-model:value="form.organizerPhone" placeholder="联系电话或邮箱" :disabled="readonlyMode" /> |
|
|
|
<a-input |
|
|
|
style="width: 100%" |
|
|
|
v-model:value="form.organizerPhone" |
|
|
|
placeholder="手机号、座机或邮箱(如 0571-12345678)" |
|
|
|
:disabled="readonlyMode" |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
</a-row> |
|
|
|
@ -210,18 +304,15 @@ |
|
|
|
<a-form-item name="serviceContent"> |
|
|
|
<template #label> |
|
|
|
<span>服务内容描述</span> |
|
|
|
<span style="color: #f00d0dff; font-size: 12px; margin-left: 4px;">注:内容描述需要包括的内容主要是时间、地点、主题、参与人员、服务内容、活动效果等</span> |
|
|
|
<span style="color: #f00d0dff; font-size: 12px; margin-left: 4px" |
|
|
|
>注:内容描述需要包括的内容主要是时间、地点、主题、参与人员、服务内容、活动效果等</span |
|
|
|
> |
|
|
|
</template> |
|
|
|
<SmartWangeditor ref="serviceContentRef" v-model="form.serviceContent" :height="200" :readonly="readonlyMode" /> |
|
|
|
</a-form-item> |
|
|
|
<!-- 备案信息(仅详情模式且已备案时展示) --> |
|
|
|
<a-row :gutter="16" v-if="readonlyMode && form.recordStatus === 1"> |
|
|
|
<a-col :span="12"> |
|
|
|
<a-form-item label="备案编号"> |
|
|
|
<a-input :value="form.filingNo" :disabled="true" /> |
|
|
|
</a-form-item> |
|
|
|
</a-col> |
|
|
|
<a-col :span="12"> |
|
|
|
<a-col :span="24"> |
|
|
|
<a-form-item label="备案时间"> |
|
|
|
<a-input :value="form.recordTime" :disabled="true" /> |
|
|
|
</a-form-item> |
|
|
|
@ -231,7 +322,9 @@ |
|
|
|
<a-form-item name="proofMaterials" required> |
|
|
|
<template #label> |
|
|
|
<span class="ant-form-item-required">证明材料</span> |
|
|
|
<span style="font-size: 12px; color: #f00d0dff;"> 注:(请上传活动方案、活动记录、照片、新闻报道等材料)支持图片(JPG/PNG)、文档(PDF/Word/PPT)格式,单文件最大10MB,最多上传5个文件</span> |
|
|
|
<span style="font-size: 12px; color: #f00d0dff"> |
|
|
|
注:(请上传活动方案、活动记录、照片、新闻报道等材料)支持图片(JPG/PNG)、文档(PDF/Word/PPT)格式,单文件最大10MB,最多上传5个文件</span |
|
|
|
> |
|
|
|
</template> |
|
|
|
<template v-if="readonlyMode"> |
|
|
|
<div v-if="defaultFileList.length > 0"> |
|
|
|
@ -251,8 +344,8 @@ |
|
|
|
<div v-else>无证明材料</div> |
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
|
|
<Upload |
|
|
|
:key="uploadRenderKey" |
|
|
|
v-else |
|
|
|
:defaultFileList="defaultFileList" |
|
|
|
:maxUploadSize="5" |
|
|
|
@ -266,7 +359,6 @@ |
|
|
|
@change="changeAttachment" |
|
|
|
/> |
|
|
|
</a-form-item> |
|
|
|
|
|
|
|
</a-form> |
|
|
|
|
|
|
|
<template #footer> |
|
|
|
@ -278,7 +370,7 @@ |
|
|
|
</a-modal> |
|
|
|
</template> |
|
|
|
<script setup> |
|
|
|
import { reactive, ref, nextTick, watch, onMounted } from 'vue'; |
|
|
|
import { computed, reactive, ref, nextTick, watch, onMounted } from 'vue'; |
|
|
|
import _ from 'lodash'; |
|
|
|
import { message } from 'ant-design-vue'; |
|
|
|
import dayjs from 'dayjs'; |
|
|
|
@ -331,7 +423,25 @@ |
|
|
|
// 当前选中的活动和活动类型 |
|
|
|
const currentActivity = ref({}); |
|
|
|
const currentActivityType = ref(''); |
|
|
|
|
|
|
|
const initializingForm = ref(false); |
|
|
|
const showBatchSelect = computed(() => { |
|
|
|
// 新增只认当前活动开关;编辑草稿才允许用已保存人员兜底回显。 |
|
|
|
if (!form.applicationId) { |
|
|
|
return canBatchSelectActivity.value; |
|
|
|
} |
|
|
|
return canBatchSelectActivity.value || form.participantLawyerIds?.length > 0 || !!form.draftParticipantIds; |
|
|
|
}); |
|
|
|
// 兼容历史数据:旧记录的 participantNames 可能包含申报人本人。 |
|
|
|
const peerParticipantNames = computed(() => { |
|
|
|
const selfName = String(form.actualName || '').trim(); |
|
|
|
const names = String(form.participantNames || '') |
|
|
|
.split('、') |
|
|
|
.map((name) => name.trim()) |
|
|
|
.filter((name) => name && name !== selfName); |
|
|
|
return names.join('、') || '-'; |
|
|
|
}); |
|
|
|
// 每次打开不同记录时重新初始化上传组件,确保已有材料稳定回显。 |
|
|
|
const uploadRenderKey = ref(0); |
|
|
|
|
|
|
|
// 活动类型变化处理 |
|
|
|
async function onActivityCategoryChange(categoryId) { |
|
|
|
@ -360,10 +470,18 @@ |
|
|
|
|
|
|
|
if (!categoryId) { |
|
|
|
activityList.value = []; |
|
|
|
canBatchSelectActivity.value = false; |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
try { |
|
|
|
canBatchSelectActivity.value = false; |
|
|
|
// 编辑时必须保留草稿中已保存的同行人;仅新增切换分类时清空。 |
|
|
|
if (isNewMode) { |
|
|
|
form.participantLawyerIds = []; |
|
|
|
form.draftParticipantIds = ''; |
|
|
|
} |
|
|
|
|
|
|
|
// 根据分类ID查询活动列表 |
|
|
|
const queryParams = { |
|
|
|
categoryId: categoryId, |
|
|
|
@ -376,12 +494,12 @@ |
|
|
|
|
|
|
|
if (result.data && result.data.list) { |
|
|
|
// 将活动列表转换为下拉选项格式,保存完整的活动信息 |
|
|
|
activityList.value = result.data.list.map(item => ({ |
|
|
|
activityList.value = result.data.list.map((item) => ({ |
|
|
|
label: item.goodsName, |
|
|
|
value: item.goodsId, // 传递活动ID而不是名称 |
|
|
|
goodsId: item.goodsId, |
|
|
|
timeType: item.timeType, |
|
|
|
...item |
|
|
|
...item, |
|
|
|
})); |
|
|
|
} else { |
|
|
|
activityList.value = []; |
|
|
|
@ -399,7 +517,14 @@ |
|
|
|
} |
|
|
|
|
|
|
|
async function show(rowData, isDetail = false) { |
|
|
|
initializingForm.value = true; |
|
|
|
Object.assign(form, formDefault); |
|
|
|
form.participantLawyerIds = []; |
|
|
|
form.draftParticipantIds = ''; |
|
|
|
canBatchSelectActivity.value = false; |
|
|
|
sameFirmLawyerOptions.value = []; |
|
|
|
defaultFileList.value = []; |
|
|
|
uploadRenderKey.value += 1; |
|
|
|
|
|
|
|
// 设置只读模式 |
|
|
|
readonlyMode.value = isDetail; |
|
|
|
@ -414,6 +539,13 @@ |
|
|
|
if (rowData && !_.isEmpty(rowData)) { |
|
|
|
// 编辑模式或详情模式:使用接口返回的数据 |
|
|
|
Object.assign(form, rowData); |
|
|
|
form.participantLawyerIds = rowData.draftParticipantIds |
|
|
|
? String(rowData.draftParticipantIds).split(',').filter(Boolean).map(Number) |
|
|
|
: []; |
|
|
|
if (form.participantLawyerIds.length > 0) { |
|
|
|
// 已保存的草稿必须优先回显,不能依赖活动列表接口中的开关字段。 |
|
|
|
loadSameFirmLawyers(); |
|
|
|
} |
|
|
|
// 只有在新增模式下才使用当前用户信息 |
|
|
|
// 详情/编辑模式使用接口返回的原始数据,不覆盖 |
|
|
|
|
|
|
|
@ -423,8 +555,12 @@ |
|
|
|
} |
|
|
|
|
|
|
|
// 编辑模式或详情模式下,如果有attachmentIds,则获取文件列表 |
|
|
|
if (form.attachmentIds && form.attachmentIds.trim()) { |
|
|
|
await getFileListByAttachmentIds(form.attachmentIds); |
|
|
|
const attachmentIds = form.attachmentIds == null ? '' : String(form.attachmentIds).trim(); |
|
|
|
form.attachmentIds = attachmentIds; |
|
|
|
if (attachmentIds) { |
|
|
|
await getFileListByAttachmentIds(attachmentIds); |
|
|
|
// 文件接口异步返回后重建一次组件,避免组件沿用上一次弹窗的内部列表。 |
|
|
|
uploadRenderKey.value += 1; |
|
|
|
} |
|
|
|
} else { |
|
|
|
// 新增模式:自动填充当前用户信息 |
|
|
|
@ -448,10 +584,16 @@ |
|
|
|
|
|
|
|
// 加载活动列表后,根据活动名称ID更新currentActivity和currentActivityType |
|
|
|
if (form.activityNameId && activityList.value.length > 0) { |
|
|
|
const selectedActivity = activityList.value.find(activity => activity.goodsId === form.activityNameId); |
|
|
|
const selectedActivity = activityList.value.find( |
|
|
|
(activity) => String(activity.goodsId) === String(form.activityNameId) |
|
|
|
); |
|
|
|
if (selectedActivity) { |
|
|
|
currentActivity.value = selectedActivity; |
|
|
|
currentActivityType.value = selectedActivity.timeType || ''; |
|
|
|
canBatchSelectActivity.value = Boolean(selectedActivity.canBatchSelect); |
|
|
|
if (canBatchSelectActivity.value) { |
|
|
|
loadSameFirmLawyers(); |
|
|
|
} |
|
|
|
// 将timeType放入serviceType字段中传递给后端 |
|
|
|
form.serviceType = selectedActivity.timeType || ''; |
|
|
|
} |
|
|
|
@ -465,6 +607,7 @@ |
|
|
|
visibleFlag.value = true; |
|
|
|
nextTick(() => { |
|
|
|
formRef.value.clearValidate(); |
|
|
|
initializingForm.value = false; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
@ -488,7 +631,7 @@ |
|
|
|
const result = await fileApi.getFileList(attachmentIds); |
|
|
|
if (result.data && result.data.length > 0) { |
|
|
|
// 将文件信息转换为Upload组件需要的格式,并清理URL |
|
|
|
defaultFileList.value = result.data.map(file => { |
|
|
|
defaultFileList.value = result.data.map((file) => { |
|
|
|
const cleanUrl = file.fileUrl ? file.fileUrl.replace(/[`\s]/g, '') : ''; |
|
|
|
return { |
|
|
|
fileId: file.fileId, |
|
|
|
@ -499,15 +642,15 @@ |
|
|
|
uid: file.fileId, |
|
|
|
name: file.fileName, |
|
|
|
status: 'done', |
|
|
|
url: cleanUrl |
|
|
|
url: cleanUrl, |
|
|
|
}; |
|
|
|
}); |
|
|
|
|
|
|
|
// 同时更新表单中的proofMaterials字段 |
|
|
|
form.proofMaterials = result.data.map(file => ({ |
|
|
|
form.proofMaterials = result.data.map((file) => ({ |
|
|
|
fileName: file.fileName, |
|
|
|
fileUrl: file.fileUrl ? file.fileUrl.replace(/[`\s]/g, '') : '', |
|
|
|
fileType: file.fileType |
|
|
|
fileType: file.fileType, |
|
|
|
})); |
|
|
|
|
|
|
|
console.log('文件列表已清理URL:', defaultFileList.value); |
|
|
|
@ -526,19 +669,21 @@ |
|
|
|
// 处理附件上传 |
|
|
|
function changeAttachment(fileList) { |
|
|
|
// 将文件信息保存到表单中 |
|
|
|
form.proofMaterials = fileList.map(file => { |
|
|
|
form.proofMaterials = fileList.map((file) => { |
|
|
|
return { |
|
|
|
fileName: file.name, |
|
|
|
fileUrl: file.url || file.response?.data?.fileUrl, |
|
|
|
fileType: file.type |
|
|
|
fileType: file.type, |
|
|
|
}; |
|
|
|
}); |
|
|
|
|
|
|
|
// 提取fileId并用逗号隔开 |
|
|
|
const fileIds = fileList.map(file => { |
|
|
|
const fileIds = fileList |
|
|
|
.map((file) => { |
|
|
|
// 从文件对象中获取fileId,优先从response中获取 |
|
|
|
return file.response?.data?.fileId || file.fileId || ''; |
|
|
|
}).filter(id => id); // 过滤掉空值 |
|
|
|
}) |
|
|
|
.filter((id) => id); // 过滤掉空值 |
|
|
|
|
|
|
|
form.attachmentIds = fileIds.join(','); |
|
|
|
|
|
|
|
@ -551,6 +696,12 @@ |
|
|
|
} |
|
|
|
|
|
|
|
function onClose() { |
|
|
|
visibleFlag.value = false; |
|
|
|
} |
|
|
|
|
|
|
|
// 等弹窗关闭动画和内部下拉菜单卸载完成后再清理响应式数据, |
|
|
|
// 避免 a-select 菜单丢失注入上下文或节点被重复移除。 |
|
|
|
function resetAfterClose() { |
|
|
|
Object.assign(form, formDefault); |
|
|
|
// 清空附件数据 |
|
|
|
defaultFileList.value = []; |
|
|
|
@ -558,7 +709,10 @@ |
|
|
|
form.attachmentIds = ''; |
|
|
|
// 重置只读模式 |
|
|
|
readonlyMode.value = false; |
|
|
|
visibleFlag.value = false; |
|
|
|
currentActivity.value = {}; |
|
|
|
currentActivityType.value = ''; |
|
|
|
activityList.value = []; |
|
|
|
sameFirmLawyers.value = []; |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------ 表单 ------------------------ |
|
|
|
@ -592,9 +746,9 @@ |
|
|
|
serviceContent: undefined, //服务内容描述 |
|
|
|
proofMaterials: undefined, //证明材料 |
|
|
|
attachmentIds: undefined, //附件ID列表(逗号隔开) |
|
|
|
participantLawyerIds: [], // 勾选同所同行律师ID列表 |
|
|
|
firmAuditStatus: undefined, //执业机构审核状态:0-待审核,1-通过,2-退回 |
|
|
|
recordStatus: undefined, //备案状态:0-未备案,1-已备案 |
|
|
|
filingNo: undefined, //备案编号 |
|
|
|
recordTime: undefined, //备案时间 |
|
|
|
updateTime: undefined, //更新时间 |
|
|
|
createTime: undefined, //创建时间 |
|
|
|
@ -602,6 +756,31 @@ |
|
|
|
|
|
|
|
let form = reactive({ ...formDefault }); |
|
|
|
|
|
|
|
// 本所同行人代报分类与人员状态 |
|
|
|
const canBatchSelectActivity = ref(false); |
|
|
|
const sameFirmLawyers = ref([]); |
|
|
|
const sameFirmLawyerOptions = computed(() => { |
|
|
|
return sameFirmLawyers.value.map((emp) => ({ |
|
|
|
label: `${emp.actualName} (${emp.phone || emp.loginName || '本所律师'})`, |
|
|
|
value: emp.employeeId, |
|
|
|
})); |
|
|
|
}); |
|
|
|
|
|
|
|
function filterSameFirmLawyerOption(input, option) { |
|
|
|
return option.label.toLowerCase().includes(input.toLowerCase()); |
|
|
|
} |
|
|
|
|
|
|
|
async function loadSameFirmLawyers() { |
|
|
|
try { |
|
|
|
const res = await serviceApplicationsApi.querySameFirmLawyers(); |
|
|
|
if (res && res.data) { |
|
|
|
sameFirmLawyers.value = res.data; |
|
|
|
} |
|
|
|
} catch (e) { |
|
|
|
console.error('加载同所律师失败:', e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 服务时长格式化函数 |
|
|
|
function formatServiceDuration(minutes) { |
|
|
|
if (minutes <= 30) { |
|
|
|
@ -636,12 +815,21 @@ |
|
|
|
return formatServiceDuration(totalMinutes); |
|
|
|
} |
|
|
|
|
|
|
|
// 监听服务开始时间和结束时间变化,自动计算服务时长 |
|
|
|
// 监听服务开始时间和结束时间变化,自动计算服务时长(仅适用于按时间段计算时长的活动,如 DICT 类型) |
|
|
|
watch( |
|
|
|
() => [form.serviceStart, form.serviceEnd], |
|
|
|
([startTime, endTime]) => { |
|
|
|
// 只有在非编辑模式下或当前活动类型为DICT时才自动计算服务时长 |
|
|
|
if ((!form.applicationId || currentActivityType.value === 'DICT') && (startTime && endTime)) { |
|
|
|
([startTime, endTime], [oldStartTime, oldEndTime] = []) => { |
|
|
|
// 编辑弹窗初始化时,起止时间与手工填写的服务时长会一起回填。 |
|
|
|
// 此时不能用时间差覆盖数据库中已保存的服务时长。 |
|
|
|
if (initializingForm.value) { |
|
|
|
return; |
|
|
|
} |
|
|
|
if (form.applicationId && oldStartTime == null && oldEndTime == null) { |
|
|
|
return; |
|
|
|
} |
|
|
|
// 只有在 DICT 类型(或默认未指定类型且同时有开始和结束时间)时才根据起止时间自动计算或联动清空服务时长 |
|
|
|
if (currentActivityType.value === 'DICT' || (!currentActivityType.value && startTime && endTime)) { |
|
|
|
if (startTime && endTime) { |
|
|
|
const start = dayjs(startTime); |
|
|
|
const end = dayjs(endTime); |
|
|
|
if (end.isAfter(start)) { |
|
|
|
@ -654,10 +842,11 @@ |
|
|
|
form.serviceDuration = undefined; |
|
|
|
message.warning('服务结束时间必须晚于开始时间'); |
|
|
|
} |
|
|
|
} else if (!form.applicationId && (!startTime || !endTime)) { |
|
|
|
// 只有在非编辑模式下才清空服务时长 |
|
|
|
} else if (!form.applicationId) { |
|
|
|
// 仅在新建且为 DICT 类型时,缺少起止时间才清空时长 |
|
|
|
form.serviceDuration = undefined; |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
{ immediate: true } |
|
|
|
); |
|
|
|
@ -680,12 +869,28 @@ |
|
|
|
watch( |
|
|
|
() => form.activityNameId, |
|
|
|
(activityNameId, oldActivityNameId) => { |
|
|
|
|
|
|
|
// 只有用户实际更换活动名称时才清空同行人;编辑页初始化回填必须保留。 |
|
|
|
if ( |
|
|
|
!initializingForm.value && |
|
|
|
oldActivityNameId != null && |
|
|
|
String(activityNameId) !== String(oldActivityNameId) |
|
|
|
) { |
|
|
|
form.participantLawyerIds = []; |
|
|
|
form.draftParticipantIds = ''; |
|
|
|
} |
|
|
|
if (activityNameId) { |
|
|
|
const selectedActivity = activityList.value.find(activity => activity.goodsId === activityNameId); |
|
|
|
const selectedActivity = activityList.value.find( |
|
|
|
(activity) => String(activity.goodsId) === String(activityNameId) |
|
|
|
); |
|
|
|
if (selectedActivity) { |
|
|
|
currentActivity.value = selectedActivity; |
|
|
|
currentActivityType.value = selectedActivity.timeType || ''; |
|
|
|
canBatchSelectActivity.value = Boolean(selectedActivity.canBatchSelect); |
|
|
|
if (canBatchSelectActivity.value) { |
|
|
|
loadSameFirmLawyers(); |
|
|
|
} else { |
|
|
|
form.participantLawyerIds = []; |
|
|
|
} |
|
|
|
// 将timeType放入serviceType字段中传递给后端 |
|
|
|
form.serviceType = selectedActivity.timeType || ''; |
|
|
|
|
|
|
|
@ -706,7 +911,7 @@ |
|
|
|
// 默认值 |
|
|
|
form.serviceDuration = 25; |
|
|
|
} |
|
|
|
} else if (selectedActivity.timeType === 'AMOUT') { |
|
|
|
} else if (['AMOUNT', 'AMOUT'].includes(selectedActivity.timeType)) { |
|
|
|
form.serviceDuration = undefined; |
|
|
|
} else if (selectedActivity.timeType === 'DICT') { |
|
|
|
// DICT类型:清空服务时长,让用户通过选择时间或手动填写 |
|
|
|
@ -717,12 +922,13 @@ |
|
|
|
} else { |
|
|
|
currentActivity.value = {}; |
|
|
|
currentActivityType.value = ''; |
|
|
|
canBatchSelectActivity.value = false; |
|
|
|
form.participantLawyerIds = []; |
|
|
|
} |
|
|
|
}, |
|
|
|
{ immediate: true } |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
const rules = { |
|
|
|
actualName: [{ required: true, message: '姓名 必填' }], |
|
|
|
certificateNumber: [{ required: true, message: '执业证号 必填' }], |
|
|
|
@ -735,19 +941,21 @@ |
|
|
|
// return Promise.reject('服务开始时间 必填'); |
|
|
|
//} |
|
|
|
return Promise.resolve(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
], |
|
|
|
serviceEnd: [ |
|
|
|
{ |
|
|
|
validator: async (rule, value) => { |
|
|
|
// 只有dict类型需要验证服务结束时间 |
|
|
|
//if (currentActivityType.value === 'DICT' && !value) { |
|
|
|
//return Promise.reject('服务结束时间 必填'); |
|
|
|
//} |
|
|
|
return Promise.resolve(); |
|
|
|
if (!value) { |
|
|
|
return Promise.reject('活动结束时间 必填'); |
|
|
|
} |
|
|
|
if (dayjs(value).isAfter(dayjs())) { |
|
|
|
return Promise.reject('活动结束时间不能晚于当前时间'); |
|
|
|
} |
|
|
|
return Promise.resolve(); |
|
|
|
}, |
|
|
|
}, |
|
|
|
], |
|
|
|
serviceDuration: [ |
|
|
|
{ |
|
|
|
@ -770,7 +978,7 @@ |
|
|
|
} |
|
|
|
} |
|
|
|
// amount类型需要验证服务时长范围 |
|
|
|
if (currentActivityType.value === 'AMOUT') { |
|
|
|
if (['AMOUNT', 'AMOUT'].includes(currentActivityType.value)) { |
|
|
|
if (!value) { |
|
|
|
return Promise.reject('服务时长(小时) 必填'); |
|
|
|
} |
|
|
|
@ -791,8 +999,8 @@ |
|
|
|
} |
|
|
|
|
|
|
|
return Promise.resolve(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
], |
|
|
|
recordNo: [ |
|
|
|
{ |
|
|
|
@ -802,19 +1010,19 @@ |
|
|
|
return Promise.reject('案件编号 必填'); |
|
|
|
} |
|
|
|
return Promise.resolve(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
], |
|
|
|
workloadScore: [ |
|
|
|
{ |
|
|
|
validator: async (rule, value) => { |
|
|
|
// amount类型需要验证金额 |
|
|
|
if (currentActivityType.value === 'AMOUT' && !value) { |
|
|
|
if (['AMOUNT', 'AMOUT'].includes(currentActivityType.value) && !value) { |
|
|
|
return Promise.reject('金额 必填'); |
|
|
|
} |
|
|
|
return Promise.resolve(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
], |
|
|
|
activityCategoryId: [{ required: true, message: '活动类型 必填' }], |
|
|
|
activityNameId: [{ required: true, message: '活动名称 必填' }], |
|
|
|
@ -824,9 +1032,9 @@ |
|
|
|
organizerPhone: [ |
|
|
|
{ required: true, message: '联系方式 必填' }, |
|
|
|
{ |
|
|
|
pattern: /^(1[3-9]\d{9}|[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/, |
|
|
|
message: '请输入正确的手机号或邮箱格式' |
|
|
|
} |
|
|
|
pattern: /^(1[3-9]\d{9}|0\d{2,3}-?\d{7,8}(?:-\d{1,6})?|[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/, |
|
|
|
message: '请输入正确的手机号、座机或邮箱格式', |
|
|
|
}, |
|
|
|
], |
|
|
|
serviceContent: [{ required: true, message: '服务内容描述 必填' }], |
|
|
|
proofMaterials: [ |
|
|
|
@ -837,8 +1045,8 @@ |
|
|
|
return Promise.reject('请上传证明材料'); |
|
|
|
} |
|
|
|
return Promise.resolve(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
], |
|
|
|
}; |
|
|
|
|
|
|
|
@ -882,19 +1090,6 @@ |
|
|
|
async function save() { |
|
|
|
SmartLoading.show(); |
|
|
|
try { |
|
|
|
// 案号重复检查 |
|
|
|
if (form.recordNo) { |
|
|
|
try { |
|
|
|
const checkResult = await serviceApplicationsApi.checkCaseNumber(form.recordNo, form.applicationId); |
|
|
|
if (!checkResult.ok) { |
|
|
|
message.error(`本案仅限一人申报,已由${checkResult.data.lawyerName}律师申报`); |
|
|
|
return; |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('案号校验失败:', error); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 准备提交数据 |
|
|
|
const submitData = { ...form }; |
|
|
|
|
|
|
|
@ -910,14 +1105,9 @@ |
|
|
|
// 新增保存:调用add接口 |
|
|
|
await serviceApplicationsApi.add(submitData); |
|
|
|
} |
|
|
|
message.success('保存成功'); |
|
|
|
message.success('保存成功,请在列表中提交'); |
|
|
|
emits('reloadList'); |
|
|
|
onClose(); |
|
|
|
|
|
|
|
// 保存成功后刷新页面 |
|
|
|
setTimeout(() => { |
|
|
|
window.location.reload(); |
|
|
|
}, 1000); |
|
|
|
} catch (err) { |
|
|
|
smartSentry.captureError(err); |
|
|
|
} finally { |
|
|
|
@ -929,19 +1119,6 @@ |
|
|
|
async function submit() { |
|
|
|
SmartLoading.show(); |
|
|
|
try { |
|
|
|
// 案号重复检查 |
|
|
|
if (form.recordNo) { |
|
|
|
try { |
|
|
|
const checkResult = await serviceApplicationsApi.checkCaseNumber(form.recordNo, form.applicationId); |
|
|
|
if (!checkResult.ok) { |
|
|
|
message.error(`本案仅限一人申报,已由${checkResult.data.lawyerName}律师申报`); |
|
|
|
return; |
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
console.error('案号校验失败:', error); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 准备提交数据 |
|
|
|
const submitData = { ...form }; |
|
|
|
|
|
|
|
@ -951,7 +1128,7 @@ |
|
|
|
} |
|
|
|
|
|
|
|
// 调用submit接口,传递完整数据 |
|
|
|
await serviceApplicationsApi.submit(submitData); |
|
|
|
await serviceApplicationsApi.addSubmit(submitData); |
|
|
|
message.success('提交成功'); |
|
|
|
emits('reloadList'); |
|
|
|
onClose(); |
|
|
|
@ -1007,15 +1184,14 @@ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 获取文件URL |
|
|
|
function getFileUrl(file) { |
|
|
|
// 获取文件URL |
|
|
|
function getFileUrl(file) { |
|
|
|
const url = file.fileUrl; |
|
|
|
return url; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 获取文件名 |
|
|
|
function getFileName(file) { |
|
|
|
// 获取文件名 |
|
|
|
function getFileName(file) { |
|
|
|
return file.fileName; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
</script> |
|
|
|
|