|
|
@@ -1,319 +1,143 @@
|
|
|
<template>
|
|
|
<div class="application-dialog-container">
|
|
|
- <van-popup
|
|
|
- v-model:show="state.dialog.isShowDialog"
|
|
|
- position="bottom"
|
|
|
- :style="{ height: '90vh' }"
|
|
|
- round
|
|
|
- :closeable="true"
|
|
|
- @close="onCancel"
|
|
|
- :close-on-click-overlay="false"
|
|
|
- >
|
|
|
+ <van-popup v-model:show="state.dialog.isShowDialog" position="bottom" :style="{ height: '90vh' }" round
|
|
|
+ :closeable="true" @close="onCancel" :close-on-click-overlay="false">
|
|
|
<div class="popup-wrapper">
|
|
|
<h3 class="popup-title">{{ state.dialog.title }}</h3>
|
|
|
<div class="popup-content">
|
|
|
- <van-form
|
|
|
- ref="expertDialogFormRef"
|
|
|
- @submit="onSubmit"
|
|
|
- >
|
|
|
- <h4 class="mb8 mt8">基本信息</h4>
|
|
|
+ <van-form ref="expertDialogFormRef" @submit="onSubmit">
|
|
|
+ <h4 class="mb8 mt8">基本信息</h4>
|
|
|
<van-cell-group>
|
|
|
- <van-field
|
|
|
- v-model="state.form.projectName"
|
|
|
- label="课题名称"
|
|
|
- placeholder="请选择"
|
|
|
- readonly
|
|
|
- is-link
|
|
|
- required
|
|
|
- @click="showProjectPicker = true"
|
|
|
- :rules="rules.projectGroupId"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="userInfos.userName"
|
|
|
- label="姓名"
|
|
|
- placeholder="姓名"
|
|
|
- readonly
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="userInfos.deptName"
|
|
|
- label="部门"
|
|
|
- placeholder="部门"
|
|
|
- readonly
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="userInfos.phone"
|
|
|
- label="联系方式"
|
|
|
- placeholder="联系方式"
|
|
|
- readonly
|
|
|
- />
|
|
|
+ <van-field v-model="state.form.projectName" label="课题名称" placeholder="请选择" readonly is-link required
|
|
|
+ @click="showProjectPicker = true" :rules="rules.projectGroupId" />
|
|
|
+ <van-field v-model="userInfos.userName" label="姓名" placeholder="姓名" readonly />
|
|
|
+ <van-field v-model="userInfos.deptName" label="部门" placeholder="部门" readonly />
|
|
|
+ <van-field v-model="userInfos.phone" label="联系方式" placeholder="联系方式" readonly />
|
|
|
</van-cell-group>
|
|
|
|
|
|
- <h4 class="mb8 mt10">实验动物笼位预约信息</h4>
|
|
|
+ <h4 class="mb8 mt10">实验动物笼位预约信息</h4>
|
|
|
<van-cell-group>
|
|
|
- <van-field
|
|
|
- v-model="state.form.number"
|
|
|
- label="笼位数量"
|
|
|
- placeholder="笼位数量"
|
|
|
- type="digit"
|
|
|
- required
|
|
|
- :rules="rules.number"
|
|
|
- >
|
|
|
+ <van-field v-model="state.form.number" label="笼位数量" placeholder="笼位数量" type="digit" required
|
|
|
+ :rules="rules.number">
|
|
|
<template #button>
|
|
|
- <van-stepper
|
|
|
- v-model="state.form.number"
|
|
|
- :min="1"
|
|
|
- integer
|
|
|
- />
|
|
|
+ <van-stepper v-model="state.form.number" :min="1" integer />
|
|
|
</template>
|
|
|
</van-field>
|
|
|
- <van-field
|
|
|
- v-model="state.form.startDate"
|
|
|
- label="开始使用时间"
|
|
|
- placeholder="请选择时间"
|
|
|
- readonly
|
|
|
- is-link
|
|
|
- required
|
|
|
- @click="showStartDatePicker = true"
|
|
|
- :rules="rules.startDate"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="state.form.categoryName"
|
|
|
- label="品种品系"
|
|
|
- placeholder="请选择"
|
|
|
- readonly
|
|
|
- is-link
|
|
|
- required
|
|
|
- @click="showCategoryPicker = true"
|
|
|
- :rules="rules.categoryId"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="state.form.variety"
|
|
|
- label="品种品系"
|
|
|
- placeholder="请输入品种品系"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="state.form.levelName"
|
|
|
- label="饲养区域"
|
|
|
- placeholder="请选择"
|
|
|
- readonly
|
|
|
- is-link
|
|
|
- @click="showLevelPicker = true"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="state.form.age"
|
|
|
- label="周龄"
|
|
|
- placeholder="请输入周龄"
|
|
|
- type="digit"
|
|
|
- >
|
|
|
+ <van-field v-model="state.form.startDate" label="开始使用时间" placeholder="请选择时间" readonly is-link required
|
|
|
+ @click="showStartDatePicker = true" :rules="rules.startDate" />
|
|
|
+ <van-field v-model="state.form.categoryName" label="动物类别" placeholder="请选择" readonly is-link required
|
|
|
+ @click="showCategoryPicker = true" :rules="rules.categoryId" />
|
|
|
+ <van-field v-model="state.form.variety" label="品种品系" placeholder="请输入品种品系" required
|
|
|
+ :rules="rules.variety" />
|
|
|
+ <van-field v-model="state.form.levelName" label="饲养区域" placeholder="请选择" readonly is-link
|
|
|
+ @click="showLevelPicker = true" />
|
|
|
+ <van-field v-model="state.form.age" label="周龄" placeholder="请输入周龄" type="digit">
|
|
|
<template #button>
|
|
|
- <van-stepper
|
|
|
- v-model="state.form.age"
|
|
|
- :min="0"
|
|
|
- integer
|
|
|
- />
|
|
|
+ <van-stepper v-model="state.form.age" :min="0" integer />
|
|
|
</template>
|
|
|
</van-field>
|
|
|
- <van-field
|
|
|
- v-model="state.form.weight"
|
|
|
- label="体重"
|
|
|
- placeholder="请输入体重"
|
|
|
- type="number"
|
|
|
- >
|
|
|
+ <van-field v-model="state.form.weight" label="体重" placeholder="请输入体重" type="number">
|
|
|
<template #button>
|
|
|
- <van-stepper
|
|
|
- v-model="state.form.weight"
|
|
|
- :min="0"
|
|
|
- />
|
|
|
+ <van-stepper v-model="state.form.weight" :min="0" />
|
|
|
</template>
|
|
|
</van-field>
|
|
|
- <van-field
|
|
|
- v-model="state.form.maleNumber"
|
|
|
- label="雄性"
|
|
|
- placeholder="雄性数量"
|
|
|
- type="digit"
|
|
|
- >
|
|
|
+ <van-field v-model="state.form.maleNumber" label="雄性" placeholder="雄性数量" type="digit">
|
|
|
<template #button>
|
|
|
- <van-stepper
|
|
|
- v-model="state.form.maleNumber"
|
|
|
- :min="0"
|
|
|
- integer
|
|
|
- />
|
|
|
+ <van-stepper v-model="state.form.maleNumber" :min="0" integer />
|
|
|
</template>
|
|
|
</van-field>
|
|
|
- <van-field
|
|
|
- v-model="state.form.famaleNumber"
|
|
|
- label="雌性"
|
|
|
- placeholder="雌性数量"
|
|
|
- type="digit"
|
|
|
- >
|
|
|
+ <van-field v-model="state.form.famaleNumber" label="雌性" placeholder="雌性数量" type="digit">
|
|
|
<template #button>
|
|
|
- <van-stepper
|
|
|
- v-model="state.form.famaleNumber"
|
|
|
- :min="0"
|
|
|
- integer
|
|
|
- />
|
|
|
+ <van-stepper v-model="state.form.famaleNumber" :min="0" integer />
|
|
|
</template>
|
|
|
</van-field>
|
|
|
- <van-field
|
|
|
- v-model="state.form.totalNumber"
|
|
|
- label="合计"
|
|
|
- placeholder="合计"
|
|
|
- readonly
|
|
|
- type="digit"
|
|
|
- >
|
|
|
+ <van-field v-model="state.form.totalNumber" label="合计" placeholder="合计" readonly type="digit">
|
|
|
<!-- <template #button>
|
|
|
<van-stepper v-model="state.form.totalNumber" :min="0" integer disabled />
|
|
|
</template> -->
|
|
|
</van-field>
|
|
|
- <van-field
|
|
|
- v-model="state.form.feedingDay"
|
|
|
- label="饲养总天数"
|
|
|
- placeholder="饲养总天数"
|
|
|
- type="digit"
|
|
|
- required
|
|
|
- :rules="rules.feedingDay"
|
|
|
- >
|
|
|
+ <van-field v-model="state.form.feedingDay" label="饲养总天数" placeholder="饲养总天数" type="digit" required
|
|
|
+ :rules="rules.feedingDay">
|
|
|
<template #button>
|
|
|
- <van-stepper
|
|
|
- v-model="state.form.feedingDay"
|
|
|
- :min="1"
|
|
|
- integer
|
|
|
- />
|
|
|
+ <van-stepper v-model="state.form.feedingDay" :min="1" integer />
|
|
|
</template>
|
|
|
</van-field>
|
|
|
</van-cell-group>
|
|
|
|
|
|
- <h4 class="mb8 mt20">采购渠道</h4>
|
|
|
+ <h4 class="mb8 mt20">采购渠道</h4>
|
|
|
<van-cell-group>
|
|
|
- <van-field
|
|
|
- label="采购渠道"
|
|
|
- required
|
|
|
- :rules="rules.buyFrom"
|
|
|
- >
|
|
|
+ <van-field label="采购渠道" required :rules="rules.buyFrom">
|
|
|
<template #input>
|
|
|
- <van-radio-group
|
|
|
- v-model="state.form.buyFrom"
|
|
|
- direction="horizontal"
|
|
|
- >
|
|
|
+ <van-radio-group v-model="state.form.buyFrom" direction="horizontal">
|
|
|
<van-radio :name="ProcurementChannels.PURCHASED_BY_OTHERS">动物房代购</van-radio>
|
|
|
<van-radio :name="ProcurementChannels.PURCHASED_BY_MYSELF">自行购买</van-radio>
|
|
|
</van-radio-group>
|
|
|
</template>
|
|
|
</van-field>
|
|
|
- <van-field
|
|
|
- v-if="state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF"
|
|
|
- v-model="state.form.comeFromUnit"
|
|
|
- label="外购来源单位"
|
|
|
- placeholder="请输入外购来源单位"
|
|
|
- required
|
|
|
- :rules="rules.comeFromUnit"
|
|
|
- />
|
|
|
- <van-field
|
|
|
- v-model="state.form.comeTime"
|
|
|
- label="动物到达时间"
|
|
|
- placeholder="请选择到达时间"
|
|
|
- readonly
|
|
|
- is-link
|
|
|
- @click="showComeTimePicker = true"
|
|
|
- />
|
|
|
+ <van-field v-if="state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF"
|
|
|
+ v-model="state.form.comeFromUnit" label="外购来源单位" placeholder="请输入外购来源单位" required
|
|
|
+ :rules="rules.comeFromUnit" />
|
|
|
+ <van-field v-model="state.form.comeTime" label="动物到达时间" placeholder="请选择到达时间" readonly is-link
|
|
|
+ @click="showComeTimePicker = true" />
|
|
|
</van-cell-group>
|
|
|
|
|
|
<!-- 自行购买时的文件上传 -->
|
|
|
<template v-if="state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF">
|
|
|
<h4 class="mb8 mt20">文件上传</h4>
|
|
|
<van-cell-group>
|
|
|
- <van-cell
|
|
|
- title="生产许可证副本"
|
|
|
- required
|
|
|
- :rules="rules.licenseNumberFile"
|
|
|
- >
|
|
|
- <van-uploader
|
|
|
- v-model="licenseNumberFileList"
|
|
|
+ <van-cell title="生产许可证副本" required :rules="rules.licenseNumberFile">
|
|
|
+ <van-uploader v-model="licenseNumberFileList"
|
|
|
:after-read="(file) => handleFileUpload(file, UploadFileType.LICENSE_NUMBER)"
|
|
|
- :before-delete="() => handleRemove(UploadFileType.LICENSE_NUMBER)"
|
|
|
- :max-count="1"
|
|
|
- :accept="state.SUPPORT_FILE_UPLOAD_TYPE_MAX"
|
|
|
- />
|
|
|
+ :before-delete="() => handleRemove(UploadFileType.LICENSE_NUMBER)" :max-count="1"
|
|
|
+ :accept="state.SUPPORT_FILE_UPLOAD_TYPE_MAX" />
|
|
|
<div class="upload-tip">支持格式:jpg png pdf等,单个文件不超过20MB</div>
|
|
|
</van-cell>
|
|
|
- <van-cell
|
|
|
- title="近三个月动物质量检测证明"
|
|
|
- required
|
|
|
- :rules="rules.animalTestDateFile"
|
|
|
- >
|
|
|
- <van-uploader
|
|
|
- v-model="animalTestDateFileList"
|
|
|
+ <van-cell title="近三个月动物质量检测证明" required :rules="rules.animalTestDateFile">
|
|
|
+ <van-uploader v-model="animalTestDateFileList"
|
|
|
:after-read="(file) => handleFileUpload(file, UploadFileType.ANIMAL_TEST_DATE)"
|
|
|
- :before-delete="() => handleRemove(UploadFileType.ANIMAL_TEST_DATE)"
|
|
|
- :max-count="1"
|
|
|
- :accept="state.SUPPORT_FILE_UPLOAD_TYPE_MAX"
|
|
|
- />
|
|
|
+ :before-delete="() => handleRemove(UploadFileType.ANIMAL_TEST_DATE)" :max-count="1"
|
|
|
+ :accept="state.SUPPORT_FILE_UPLOAD_TYPE_MAX" />
|
|
|
<div class="upload-tip">支持格式:jpg png pdf等,单个文件不超过20MB</div>
|
|
|
</van-cell>
|
|
|
<van-cell title="基因鉴定报告">
|
|
|
- <van-uploader
|
|
|
- v-model="geneIdentificationFileList"
|
|
|
+ <van-uploader v-model="geneIdentificationFileList"
|
|
|
:after-read="(file) => handleFileUpload(file, UploadFileType.ENV_TEST_DATE)"
|
|
|
- :before-delete="() => handleRemove(UploadFileType.ENV_TEST_DATE)"
|
|
|
- :max-count="1"
|
|
|
- :accept="state.SUPPORT_FILE_UPLOAD_TYPE_MAX"
|
|
|
- />
|
|
|
+ :before-delete="() => handleRemove(UploadFileType.ENV_TEST_DATE)" :max-count="1"
|
|
|
+ :accept="state.SUPPORT_FILE_UPLOAD_TYPE_MAX" />
|
|
|
<div class="upload-tip">支持格式:jpg png pdf等,单个文件不超过20MB</div>
|
|
|
</van-cell>
|
|
|
</van-cell-group>
|
|
|
</template>
|
|
|
|
|
|
- <h4 class="mb8 mt20">特殊要求和附件</h4>
|
|
|
+ <h4 class="mb8 mt20">特殊要求和附件</h4>
|
|
|
<van-cell-group>
|
|
|
<van-field label="是否有特殊饲养要求">
|
|
|
<template #input>
|
|
|
- <van-radio-group
|
|
|
- v-model="state.form.hasFeedingSpecial"
|
|
|
- direction="horizontal"
|
|
|
- >
|
|
|
+ <van-radio-group v-model="state.form.hasFeedingSpecial" direction="horizontal">
|
|
|
<van-radio :name="FeedingSpecial.HAVE_FEEDING_SPECIAL">有</van-radio>
|
|
|
<van-radio :name="FeedingSpecial.NO_FEEDING_SPECIAL">无</van-radio>
|
|
|
</van-radio-group>
|
|
|
</template>
|
|
|
</van-field>
|
|
|
- <van-field
|
|
|
- v-if="state.form.hasFeedingSpecial === FeedingSpecial.HAVE_FEEDING_SPECIAL"
|
|
|
- v-model="state.form.feedingSpecialDesc"
|
|
|
- label="特殊饲养要求"
|
|
|
- placeholder="输入特殊饲养要求,如每天更换垫料等"
|
|
|
- required
|
|
|
- :rules="rules.feedingSpecialDesc"
|
|
|
- />
|
|
|
+ <van-field v-if="state.form.hasFeedingSpecial === FeedingSpecial.HAVE_FEEDING_SPECIAL"
|
|
|
+ v-model="state.form.feedingSpecialDesc" label="特殊饲养要求" placeholder="输入特殊饲养要求,如每天更换垫料等" required
|
|
|
+ :rules="rules.feedingSpecialDesc" />
|
|
|
</van-cell-group>
|
|
|
|
|
|
<h4 class="mb8 mt20">附件上传</h4>
|
|
|
<van-cell-group>
|
|
|
- <van-cell
|
|
|
- title="实验动物福利伦理审查申请表"
|
|
|
- required
|
|
|
- :rules="rules.ethicsCheckFile"
|
|
|
- >
|
|
|
- <van-uploader
|
|
|
- v-model="ethicsCheckFileList"
|
|
|
+ <van-cell title="实验动物福利伦理审查申请表" required :rules="rules.ethicsCheckFile">
|
|
|
+ <van-uploader v-model="ethicsCheckFileList"
|
|
|
:after-read="(file) => handleFileUpload(file, UploadFileType.ETHICS_CHECK_FILE)"
|
|
|
- :before-delete="() => handleRemove(UploadFileType.ETHICS_CHECK_FILE)"
|
|
|
- :max-count="1"
|
|
|
- :accept="state.SUPPORT_FILE_UPLOAD_TYPE_MAX"
|
|
|
- />
|
|
|
+ :before-delete="() => handleRemove(UploadFileType.ETHICS_CHECK_FILE)" :max-count="1"
|
|
|
+ :accept="state.SUPPORT_FILE_UPLOAD_TYPE_MAX" />
|
|
|
<div class="upload-tip">支持格式:jpg png pdf等,单个文件不超过20MB</div>
|
|
|
</van-cell>
|
|
|
- <van-cell
|
|
|
- title="实验动物福利伦理审查意见表"
|
|
|
- required
|
|
|
- :rules="rules.ethicsAdviceFile"
|
|
|
- >
|
|
|
- <van-uploader
|
|
|
- v-model="ethicsAdviceFileList"
|
|
|
+ <van-cell title="实验动物福利伦理审查意见表" required :rules="rules.ethicsAdviceFile">
|
|
|
+ <van-uploader v-model="ethicsAdviceFileList"
|
|
|
:after-read="(file) => handleFileUpload(file, UploadFileType.ETHICS_ADVICE_FILE)"
|
|
|
- :before-delete="() => handleRemove(UploadFileType.ETHICS_ADVICE_FILE)"
|
|
|
- :max-count="1"
|
|
|
- :accept="state.SUPPORT_FILE_UPLOAD_TYPE_MAX"
|
|
|
- />
|
|
|
+ :before-delete="() => handleRemove(UploadFileType.ETHICS_ADVICE_FILE)" :max-count="1"
|
|
|
+ :accept="state.SUPPORT_FILE_UPLOAD_TYPE_MAX" />
|
|
|
<div class="upload-tip">支持格式:jpg png pdf等,单个文件不超过20MB</div>
|
|
|
</van-cell>
|
|
|
</van-cell-group>
|
|
|
@@ -328,12 +152,7 @@
|
|
|
</van-form>
|
|
|
</div>
|
|
|
<div class="dialog-footer">
|
|
|
- <van-button
|
|
|
- type="primary"
|
|
|
- @click="onSubmit"
|
|
|
- block
|
|
|
- native-type="submit"
|
|
|
- >
|
|
|
+ <van-button type="primary" @click="onSubmit" block native-type="submit">
|
|
|
提交
|
|
|
</van-button>
|
|
|
</div>
|
|
|
@@ -341,555 +160,518 @@
|
|
|
</van-popup>
|
|
|
|
|
|
<!-- 课题选择器 -->
|
|
|
- <van-popup
|
|
|
- v-model:show="showProjectPicker"
|
|
|
- position="bottom"
|
|
|
- >
|
|
|
- <van-picker
|
|
|
- :columns="projects"
|
|
|
- :columns-field-names="{ text: 'projectName', value: 'id' }"
|
|
|
- @confirm="onProjectConfirm"
|
|
|
- @cancel="showProjectPicker = false"
|
|
|
- />
|
|
|
+ <van-popup v-model:show="showProjectPicker" position="bottom">
|
|
|
+ <van-picker :columns="projects" :columns-field-names="{ text: 'projectName', value: 'id' }"
|
|
|
+ @confirm="onProjectConfirm" @cancel="showProjectPicker = false" />
|
|
|
</van-popup>
|
|
|
|
|
|
- <!-- 品种品系选择器 -->
|
|
|
- <van-popup
|
|
|
- v-model:show="showCategoryPicker"
|
|
|
- position="bottom"
|
|
|
- >
|
|
|
- <van-picker
|
|
|
- :columns="animalTypeList"
|
|
|
- :columns-field-names="{ text: 'name', value: 'id' }"
|
|
|
- @confirm="onCategoryConfirm"
|
|
|
- @cancel="showCategoryPicker = false"
|
|
|
- />
|
|
|
+ <!-- 动物类别选择器 -->
|
|
|
+ <van-popup v-model:show="showCategoryPicker" position="bottom">
|
|
|
+ <van-picker :columns="animalTypeList" :columns-field-names="{ text: 'name', value: 'id' }"
|
|
|
+ @confirm="onCategoryConfirm" @cancel="showCategoryPicker = false" />
|
|
|
</van-popup>
|
|
|
|
|
|
<!-- 饲养区域选择器 -->
|
|
|
- <van-popup
|
|
|
- v-model:show="showLevelPicker"
|
|
|
- position="bottom"
|
|
|
- >
|
|
|
- <van-picker
|
|
|
- :columns="LeavelList"
|
|
|
- :columns-field-names="{ text: 'name', value: 'id' }"
|
|
|
- @confirm="onLevelConfirm"
|
|
|
- @cancel="showLevelPicker = false"
|
|
|
- />
|
|
|
+ <van-popup v-model:show="showLevelPicker" position="bottom">
|
|
|
+ <van-picker :columns="LeavelList" :columns-field-names="{ text: 'name', value: 'id' }" @confirm="onLevelConfirm"
|
|
|
+ @cancel="showLevelPicker = false" />
|
|
|
</van-popup>
|
|
|
|
|
|
<!-- 开始使用时间选择器 -->
|
|
|
- <van-popup
|
|
|
- v-model:show="showStartDatePicker"
|
|
|
- position="bottom"
|
|
|
- :style="{ height: '80vh' }"
|
|
|
- round
|
|
|
- >
|
|
|
- <van-calendar
|
|
|
- v-model:show="showStartDatePicker"
|
|
|
- @confirm="onStartDateConfirm"
|
|
|
- :min-date="new Date()"
|
|
|
- />
|
|
|
+ <van-popup v-model:show="showStartDatePicker" position="bottom" :style="{ height: '80vh' }" round>
|
|
|
+ <van-calendar v-model:show="showStartDatePicker" @confirm="onStartDateConfirm" :min-date="new Date()" />
|
|
|
</van-popup>
|
|
|
|
|
|
<!-- 动物到达时间选择器 -->
|
|
|
- <van-popup
|
|
|
- v-model:show="showComeTimePicker"
|
|
|
- position="bottom"
|
|
|
- :style="{ height: '80vh' }"
|
|
|
- round
|
|
|
- >
|
|
|
- <van-calendar
|
|
|
- v-model:show="showComeTimePicker"
|
|
|
- @confirm="onComeTimeConfirm"
|
|
|
- />
|
|
|
+ <van-popup v-model:show="showComeTimePicker" position="bottom" :style="{ height: '80vh' }" round>
|
|
|
+ <van-calendar v-model:show="showComeTimePicker" @confirm="onComeTimeConfirm" />
|
|
|
</van-popup>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts" name="systemProDialog">
|
|
|
- import { reactive, ref, watch } from 'vue'
|
|
|
- import to from 'await-to-js'
|
|
|
- import { showToast, showNotify } from 'vant'
|
|
|
- import type { FormInstance } from 'vant/es'
|
|
|
- import dayjs from 'dayjs'
|
|
|
- import { storeToRefs } from 'pinia'
|
|
|
- import { usePlatAnimalCageApplicationApi } from '/@/api/platform/animal'
|
|
|
- import { LeavelList, SUPPORT_FILE_UPLOAD_TYPE_MAX } from '/@/constants/pageConstants'
|
|
|
- import { deepClone } from '/@/utils/other'
|
|
|
- import { useUserInfo } from '/@/stores/userInfo'
|
|
|
- import { ProcurementChannels, FeedingSpecial, UploadFileType } from '/@/constants/pageConstants'
|
|
|
- import { handleUpload } from '/@/utils/upload'
|
|
|
- import { formatDate } from '/@/utils/formatTime'
|
|
|
-
|
|
|
- const stores = useUserInfo()
|
|
|
- const { userInfos } = storeToRefs(stores)
|
|
|
-
|
|
|
- // 定义子组件向父组件传值/事件
|
|
|
- const emit = defineEmits(['refresh'])
|
|
|
-
|
|
|
- const platAnimalCageApplicationApi = usePlatAnimalCageApplicationApi()
|
|
|
-
|
|
|
- const expertDialogFormRef = ref<FormInstance>()
|
|
|
- const projectGroupList = ref<any[]>([])
|
|
|
- const projects = ref<any[]>([])
|
|
|
- const showProjectPicker = ref(false)
|
|
|
- const showCategoryPicker = ref(false)
|
|
|
- const showLevelPicker = ref(false)
|
|
|
- const showStartDatePicker = ref(false)
|
|
|
- const showComeTimePicker = ref(false)
|
|
|
-
|
|
|
- const rules = {
|
|
|
- projectGroupId: [{ required: true, message: '课题名称不能为空' }],
|
|
|
- categoryId: [{ required: true, message: '品种品系不能为空' }],
|
|
|
- number: [{ required: true, message: '笼位数量不能为空' }],
|
|
|
- startDate: [{ required: true, message: '开始使用时间不能为空' }],
|
|
|
- buyFrom: [{ required: true, message: '采购渠道不能为空' }],
|
|
|
- feedingDay: [{ required: true, message: '饲养总天数不能为空' }],
|
|
|
- comeFromUnit: [{ required: true, message: '外购来源单位不能为空' }],
|
|
|
- feedingSpecialDesc: [{ required: true, message: '特殊饲养要求不能为空' }],
|
|
|
- ethicsCheckFile: [{ required: true, message: '实验动物福利伦理审查申请表不能为空' }],
|
|
|
- ethicsAdviceFile: [{ required: true, message: '实验动物福利伦理审查意见表不能为空' }],
|
|
|
- licenseNumberFile: [{ required: true, message: '生产许可证副本不能为空' }],
|
|
|
- animalTestDateFile: [{ required: true, message: '近三个月动物质量检测证明不能为空' }],
|
|
|
- }
|
|
|
-
|
|
|
- const licenseNumberFileList = ref<any[]>([])
|
|
|
- const animalTestDateFileList = ref<any[]>([])
|
|
|
- const geneIdentificationFileList = ref<any[]>([])
|
|
|
- const ethicsCheckFileList = ref<any[]>([])
|
|
|
- const ethicsAdviceFileList = ref<any[]>([])
|
|
|
-
|
|
|
- const safePromise = ref<boolean>(false)
|
|
|
- const animalTypeList = ref<any[]>([])
|
|
|
-
|
|
|
- const defaultFormData = {
|
|
|
- projectGroupName: '',
|
|
|
- projectGroupId: null,
|
|
|
- projectName: '',
|
|
|
- categoryName: '',
|
|
|
- variety: '',
|
|
|
- categoryId: null,
|
|
|
- level: null,
|
|
|
- levelName: '',
|
|
|
- number: 1,
|
|
|
- startDate: '',
|
|
|
- maleNumber: 0,
|
|
|
- famaleNumber: 0,
|
|
|
- weight: 0,
|
|
|
- age: 0,
|
|
|
- feedingDay: 0,
|
|
|
- buyFrom: ProcurementChannels.PURCHASED_BY_OTHERS,
|
|
|
- comeTime: '',
|
|
|
- comeFromUnit: '',
|
|
|
- licenseNumberFile: [],
|
|
|
- animalTestDateFile: [],
|
|
|
- geneIdentificationFile: [],
|
|
|
- hasFeedingSpecial: FeedingSpecial.HAVE_FEEDING_SPECIAL,
|
|
|
- feedingSpecialDesc: '',
|
|
|
- ethicsCheckFile: [],
|
|
|
- ethicsAdviceFile: [],
|
|
|
- deptName: '',
|
|
|
- phone: '',
|
|
|
- totalNumber: 0,
|
|
|
- }
|
|
|
-
|
|
|
- const state = reactive({
|
|
|
- SUPPORT_FILE_UPLOAD_TYPE_MAX,
|
|
|
- form: { ...defaultFormData },
|
|
|
- dialog: {
|
|
|
- isShowDialog: false,
|
|
|
- type: '',
|
|
|
- title: '',
|
|
|
- submitTxt: '',
|
|
|
- },
|
|
|
+import { reactive, ref, watch } from 'vue'
|
|
|
+import to from 'await-to-js'
|
|
|
+import { showToast, showNotify } from 'vant'
|
|
|
+import type { FormInstance } from 'vant/es'
|
|
|
+import dayjs from 'dayjs'
|
|
|
+import { storeToRefs } from 'pinia'
|
|
|
+import { usePlatAnimalCageApplicationApi } from '/@/api/platform/animal'
|
|
|
+import { LeavelList, SUPPORT_FILE_UPLOAD_TYPE_MAX } from '/@/constants/pageConstants'
|
|
|
+import { deepClone } from '/@/utils/other'
|
|
|
+import { useUserInfo } from '/@/stores/userInfo'
|
|
|
+import { ProcurementChannels, FeedingSpecial, UploadFileType } from '/@/constants/pageConstants'
|
|
|
+import { handleUpload } from '/@/utils/upload'
|
|
|
+import { formatDate } from '/@/utils/formatTime'
|
|
|
+
|
|
|
+const stores = useUserInfo()
|
|
|
+const { userInfos } = storeToRefs(stores)
|
|
|
+
|
|
|
+// 定义子组件向父组件传值/事件
|
|
|
+const emit = defineEmits(['refresh'])
|
|
|
+
|
|
|
+const platAnimalCageApplicationApi = usePlatAnimalCageApplicationApi()
|
|
|
+
|
|
|
+const expertDialogFormRef = ref<FormInstance>()
|
|
|
+const projectGroupList = ref<any[]>([])
|
|
|
+const projects = ref<any[]>([])
|
|
|
+const showProjectPicker = ref(false)
|
|
|
+const showCategoryPicker = ref(false)
|
|
|
+const showLevelPicker = ref(false)
|
|
|
+const showStartDatePicker = ref(false)
|
|
|
+const showComeTimePicker = ref(false)
|
|
|
+
|
|
|
+const rules = {
|
|
|
+ projectGroupId: [{ required: true, message: '课题名称不能为空' }],
|
|
|
+ categoryId: [{ required: true, message: '动物类别不能为空' }],
|
|
|
+ variety: [{ required: true, message: '品种品系不能为空' }],
|
|
|
+ number: [{ required: true, message: '笼位数量不能为空' }],
|
|
|
+ startDate: [{ required: true, message: '开始使用时间不能为空' }],
|
|
|
+ buyFrom: [{ required: true, message: '采购渠道不能为空' }],
|
|
|
+ feedingDay: [{ required: true, message: '饲养总天数不能为空' }],
|
|
|
+ comeFromUnit: [{ required: true, message: '外购来源单位不能为空' }],
|
|
|
+ feedingSpecialDesc: [{ required: true, message: '特殊饲养要求不能为空' }],
|
|
|
+ ethicsCheckFile: [{ required: true, message: '实验动物福利伦理审查申请表不能为空' }],
|
|
|
+ ethicsAdviceFile: [{ required: true, message: '实验动物福利伦理审查意见表不能为空' }],
|
|
|
+ licenseNumberFile: [{ required: true, message: '生产许可证副本不能为空' }],
|
|
|
+ animalTestDateFile: [{ required: true, message: '近三个月动物质量检测证明不能为空' }],
|
|
|
+}
|
|
|
+
|
|
|
+const licenseNumberFileList = ref<any[]>([])
|
|
|
+const animalTestDateFileList = ref<any[]>([])
|
|
|
+const geneIdentificationFileList = ref<any[]>([])
|
|
|
+const ethicsCheckFileList = ref<any[]>([])
|
|
|
+const ethicsAdviceFileList = ref<any[]>([])
|
|
|
+
|
|
|
+const safePromise = ref<boolean>(false)
|
|
|
+const animalTypeList = ref<any[]>([])
|
|
|
+
|
|
|
+const defaultFormData = {
|
|
|
+ projectGroupName: '',
|
|
|
+ projectGroupId: null,
|
|
|
+ projectName: '',
|
|
|
+ categoryName: '',
|
|
|
+ variety: '',
|
|
|
+ categoryId: null,
|
|
|
+ level: null,
|
|
|
+ levelName: '',
|
|
|
+ number: 1,
|
|
|
+ startDate: '',
|
|
|
+ maleNumber: 0,
|
|
|
+ famaleNumber: 0,
|
|
|
+ weight: 0,
|
|
|
+ age: 0,
|
|
|
+ feedingDay: 0,
|
|
|
+ buyFrom: ProcurementChannels.PURCHASED_BY_OTHERS,
|
|
|
+ comeTime: '',
|
|
|
+ comeFromUnit: '',
|
|
|
+ licenseNumberFile: [],
|
|
|
+ animalTestDateFile: [],
|
|
|
+ geneIdentificationFile: [],
|
|
|
+ hasFeedingSpecial: FeedingSpecial.HAVE_FEEDING_SPECIAL,
|
|
|
+ feedingSpecialDesc: '',
|
|
|
+ ethicsCheckFile: [],
|
|
|
+ ethicsAdviceFile: [],
|
|
|
+ deptName: '',
|
|
|
+ phone: '',
|
|
|
+ totalNumber: 0,
|
|
|
+}
|
|
|
+
|
|
|
+const state = reactive({
|
|
|
+ SUPPORT_FILE_UPLOAD_TYPE_MAX,
|
|
|
+ form: { ...defaultFormData },
|
|
|
+ dialog: {
|
|
|
+ isShowDialog: false,
|
|
|
+ type: '',
|
|
|
+ title: '',
|
|
|
+ submitTxt: '',
|
|
|
+ },
|
|
|
+})
|
|
|
+
|
|
|
+const getDicts = () => {
|
|
|
+ Promise.all([
|
|
|
+ platAnimalCageApplicationApi.getAnimalTypeList({}),
|
|
|
+ platAnimalCageApplicationApi.getProjectGroup({}),
|
|
|
+ ]).then(([animalType, projectGroup]) => {
|
|
|
+ animalTypeList.value = animalType.data
|
|
|
+ if (projectGroup && projectGroup.data) {
|
|
|
+ projectGroupList.value = projectGroup.data
|
|
|
+ const currentProject = projectGroup.data[0]?.projects
|
|
|
+ if (currentProject) {
|
|
|
+ projects.value = currentProject
|
|
|
+ }
|
|
|
+ }
|
|
|
})
|
|
|
+}
|
|
|
+
|
|
|
+// 重置表单数据
|
|
|
+const resetForm = () => {
|
|
|
+ state.form = { ...defaultFormData }
|
|
|
+ expertDialogFormRef.value?.resetValidation()
|
|
|
+ licenseNumberFileList.value = []
|
|
|
+ animalTestDateFileList.value = []
|
|
|
+ geneIdentificationFileList.value = []
|
|
|
+ ethicsCheckFileList.value = []
|
|
|
+ ethicsAdviceFileList.value = []
|
|
|
+ safePromise.value = false
|
|
|
+}
|
|
|
+
|
|
|
+// 打开弹窗
|
|
|
+const openDialog = () => {
|
|
|
+ resetForm()
|
|
|
+ getDicts()
|
|
|
+ state.dialog.title = '新增实验动物笼位申请'
|
|
|
+ state.dialog.isShowDialog = true
|
|
|
+}
|
|
|
+
|
|
|
+// 关闭弹窗
|
|
|
+const closeDialog = () => {
|
|
|
+ expertDialogFormRef.value?.resetValidation()
|
|
|
+ state.dialog.isShowDialog = false
|
|
|
+ licenseNumberFileList.value = []
|
|
|
+ animalTestDateFileList.value = []
|
|
|
+ geneIdentificationFileList.value = []
|
|
|
+ ethicsCheckFileList.value = []
|
|
|
+ ethicsAdviceFileList.value = []
|
|
|
+ safePromise.value = false
|
|
|
+}
|
|
|
+
|
|
|
+// 取消
|
|
|
+const onCancel = () => {
|
|
|
+ closeDialog()
|
|
|
+}
|
|
|
+
|
|
|
+const handleFileUpload = async (file: any, type: UploadFileType) => {
|
|
|
+ // 处理单个文件或文件数组
|
|
|
+ const files = Array.isArray(file) ? file : [file]
|
|
|
+
|
|
|
+ for (const item of files) {
|
|
|
+ // 检查文件大小
|
|
|
+ if (item.file && item.file.size / 1024 / 1024 > 20) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '上传文件大小不能超过 20MB!',
|
|
|
+ })
|
|
|
+ // 移除文件
|
|
|
+ if (type === UploadFileType.LICENSE_NUMBER) {
|
|
|
+ licenseNumberFileList.value = licenseNumberFileList.value.filter((f) => f !== item)
|
|
|
+ } else if (type === UploadFileType.ANIMAL_TEST_DATE) {
|
|
|
+ animalTestDateFileList.value = animalTestDateFileList.value.filter((f) => f !== item)
|
|
|
+ } else if (type === UploadFileType.ENV_TEST_DATE) {
|
|
|
+ geneIdentificationFileList.value = geneIdentificationFileList.value.filter((f) => f !== item)
|
|
|
+ } else if (type === UploadFileType.ETHICS_CHECK_FILE) {
|
|
|
+ ethicsCheckFileList.value = ethicsCheckFileList.value.filter((f) => f !== item)
|
|
|
+ } else if (type === UploadFileType.ETHICS_ADVICE_FILE) {
|
|
|
+ ethicsAdviceFileList.value = ethicsAdviceFileList.value.filter((f) => f !== item)
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- const getDicts = () => {
|
|
|
- Promise.all([
|
|
|
- platAnimalCageApplicationApi.getAnimalTypeList({}),
|
|
|
- platAnimalCageApplicationApi.getProjectGroup({}),
|
|
|
- ]).then(([animalType, projectGroup]) => {
|
|
|
- animalTypeList.value = animalType.data
|
|
|
- if (projectGroup && projectGroup.data) {
|
|
|
- projectGroupList.value = projectGroup.data
|
|
|
- const currentProject = projectGroup.data[0]?.projects
|
|
|
- if (currentProject) {
|
|
|
- projects.value = currentProject
|
|
|
- }
|
|
|
+ if (item.file) {
|
|
|
+ item.status = 'uploading'
|
|
|
+ const [err, res]: ToResponse = await to(handleUpload(item.file))
|
|
|
+ if (err) {
|
|
|
+ item.status = 'failed'
|
|
|
+ showNotify({
|
|
|
+ type: 'danger',
|
|
|
+ message: '上传失败',
|
|
|
+ })
|
|
|
+ return
|
|
|
}
|
|
|
- })
|
|
|
+ item.status = 'done'
|
|
|
+ item.url = res
|
|
|
+ item.name = item.file.name
|
|
|
+
|
|
|
+ // 保存到 form
|
|
|
+ if (type === UploadFileType.LICENSE_NUMBER) {
|
|
|
+ state.form.licenseNumberFile = [{ name: item.name, url: res }]
|
|
|
+ } else if (type === UploadFileType.ANIMAL_TEST_DATE) {
|
|
|
+ state.form.animalTestDateFile = [{ name: item.name, url: res }]
|
|
|
+ } else if (type === UploadFileType.ENV_TEST_DATE) {
|
|
|
+ state.form.geneIdentificationFile = [{ name: item.name, url: res }]
|
|
|
+ } else if (type === UploadFileType.ETHICS_CHECK_FILE) {
|
|
|
+ state.form.ethicsCheckFile = [{ name: item.name, url: res }]
|
|
|
+ } else if (type === UploadFileType.ETHICS_ADVICE_FILE) {
|
|
|
+ state.form.ethicsAdviceFile = [{ name: item.name, url: res }]
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- // 重置表单数据
|
|
|
- const resetForm = () => {
|
|
|
- state.form = { ...defaultFormData }
|
|
|
- expertDialogFormRef.value?.resetValidation()
|
|
|
+const handleRemove = (type: UploadFileType) => {
|
|
|
+ if (type === UploadFileType.LICENSE_NUMBER) {
|
|
|
licenseNumberFileList.value = []
|
|
|
+ state.form.licenseNumberFile = []
|
|
|
+ } else if (type === UploadFileType.ANIMAL_TEST_DATE) {
|
|
|
animalTestDateFileList.value = []
|
|
|
+ state.form.animalTestDateFile = []
|
|
|
+ } else if (type === UploadFileType.ENV_TEST_DATE) {
|
|
|
geneIdentificationFileList.value = []
|
|
|
+ state.form.geneIdentificationFile = []
|
|
|
+ } else if (type === UploadFileType.ETHICS_CHECK_FILE) {
|
|
|
ethicsCheckFileList.value = []
|
|
|
+ state.form.ethicsCheckFile = []
|
|
|
+ } else if (type === UploadFileType.ETHICS_ADVICE_FILE) {
|
|
|
ethicsAdviceFileList.value = []
|
|
|
- safePromise.value = false
|
|
|
+ state.form.ethicsAdviceFile = []
|
|
|
}
|
|
|
-
|
|
|
- // 打开弹窗
|
|
|
- const openDialog = () => {
|
|
|
- resetForm()
|
|
|
- getDicts()
|
|
|
- state.dialog.title = '新增实验动物笼位申请'
|
|
|
- state.dialog.isShowDialog = true
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+const onProjectConfirm = ({ selectedOptions }: { selectedOptions: any[] }) => {
|
|
|
+ if (selectedOptions.length > 0) {
|
|
|
+ const selected = selectedOptions[0]
|
|
|
+ state.form.projectGroupId = selected.id
|
|
|
+ state.form.projectName = selected.projectName
|
|
|
}
|
|
|
-
|
|
|
- // 关闭弹窗
|
|
|
- const closeDialog = () => {
|
|
|
- expertDialogFormRef.value?.resetValidation()
|
|
|
- state.dialog.isShowDialog = false
|
|
|
- licenseNumberFileList.value = []
|
|
|
- animalTestDateFileList.value = []
|
|
|
- geneIdentificationFileList.value = []
|
|
|
- ethicsCheckFileList.value = []
|
|
|
- ethicsAdviceFileList.value = []
|
|
|
- safePromise.value = false
|
|
|
+ showProjectPicker.value = false
|
|
|
+}
|
|
|
+
|
|
|
+const onCategoryConfirm = ({ selectedOptions }: { selectedOptions: any[] }) => {
|
|
|
+ if (selectedOptions.length > 0) {
|
|
|
+ const selected = selectedOptions[0]
|
|
|
+ state.form.categoryId = selected.id
|
|
|
+ state.form.categoryName = selected.name
|
|
|
}
|
|
|
-
|
|
|
- // 取消
|
|
|
- const onCancel = () => {
|
|
|
- closeDialog()
|
|
|
+ showCategoryPicker.value = false
|
|
|
+}
|
|
|
+
|
|
|
+const onLevelConfirm = ({ selectedOptions }: { selectedOptions: any[] }) => {
|
|
|
+ if (selectedOptions.length > 0) {
|
|
|
+ const selected = selectedOptions[0]
|
|
|
+ state.form.level = selected.id
|
|
|
+ state.form.levelName = selected.name
|
|
|
}
|
|
|
-
|
|
|
- const handleFileUpload = async (file: any, type: UploadFileType) => {
|
|
|
- // 处理单个文件或文件数组
|
|
|
- const files = Array.isArray(file) ? file : [file]
|
|
|
-
|
|
|
- for (const item of files) {
|
|
|
- // 检查文件大小
|
|
|
- if (item.file && item.file.size / 1024 / 1024 > 20) {
|
|
|
- showNotify({
|
|
|
- type: 'warning',
|
|
|
- message: '上传文件大小不能超过 20MB!',
|
|
|
- })
|
|
|
- // 移除文件
|
|
|
- if (type === UploadFileType.LICENSE_NUMBER) {
|
|
|
- licenseNumberFileList.value = licenseNumberFileList.value.filter((f) => f !== item)
|
|
|
- } else if (type === UploadFileType.ANIMAL_TEST_DATE) {
|
|
|
- animalTestDateFileList.value = animalTestDateFileList.value.filter((f) => f !== item)
|
|
|
- } else if (type === UploadFileType.ENV_TEST_DATE) {
|
|
|
- geneIdentificationFileList.value = geneIdentificationFileList.value.filter((f) => f !== item)
|
|
|
- } else if (type === UploadFileType.ETHICS_CHECK_FILE) {
|
|
|
- ethicsCheckFileList.value = ethicsCheckFileList.value.filter((f) => f !== item)
|
|
|
- } else if (type === UploadFileType.ETHICS_ADVICE_FILE) {
|
|
|
- ethicsAdviceFileList.value = ethicsAdviceFileList.value.filter((f) => f !== item)
|
|
|
- }
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if (item.file) {
|
|
|
- item.status = 'uploading'
|
|
|
- const [err, res]: ToResponse = await to(handleUpload(item.file))
|
|
|
- if (err) {
|
|
|
- item.status = 'failed'
|
|
|
- showNotify({
|
|
|
- type: 'danger',
|
|
|
- message: '上传失败',
|
|
|
- })
|
|
|
- return
|
|
|
- }
|
|
|
- item.status = 'done'
|
|
|
- item.url = res
|
|
|
- item.name = item.file.name
|
|
|
-
|
|
|
- // 保存到 form
|
|
|
- if (type === UploadFileType.LICENSE_NUMBER) {
|
|
|
- state.form.licenseNumberFile = [{ name: item.name, url: res }]
|
|
|
- } else if (type === UploadFileType.ANIMAL_TEST_DATE) {
|
|
|
- state.form.animalTestDateFile = [{ name: item.name, url: res }]
|
|
|
- } else if (type === UploadFileType.ENV_TEST_DATE) {
|
|
|
- state.form.geneIdentificationFile = [{ name: item.name, url: res }]
|
|
|
- } else if (type === UploadFileType.ETHICS_CHECK_FILE) {
|
|
|
- state.form.ethicsCheckFile = [{ name: item.name, url: res }]
|
|
|
- } else if (type === UploadFileType.ETHICS_ADVICE_FILE) {
|
|
|
- state.form.ethicsAdviceFile = [{ name: item.name, url: res }]
|
|
|
+ showLevelPicker.value = false
|
|
|
+}
|
|
|
+
|
|
|
+const onStartDateConfirm = (date: Date) => {
|
|
|
+ state.form.startDate = formatDate(date, 'YYYY-mm-dd')
|
|
|
+ showStartDatePicker.value = false
|
|
|
+}
|
|
|
+
|
|
|
+const onComeTimeConfirm = (date: Date) => {
|
|
|
+ state.form.comeTime = formatDate(date, 'YYYY-mm-dd')
|
|
|
+ showComeTimePicker.value = false
|
|
|
+}
|
|
|
+
|
|
|
+// 提交
|
|
|
+const onSubmit = async () => {
|
|
|
+ try {
|
|
|
+ await expertDialogFormRef.value?.validate()
|
|
|
+ } catch (error: any) {
|
|
|
+ // 显示表单验证错误
|
|
|
+ let errorMessage = '请完善必填信息'
|
|
|
+ if (error) {
|
|
|
+ // Vant 表单验证错误可能是数组格式
|
|
|
+ if (Array.isArray(error) && error.length > 0) {
|
|
|
+ const firstError = error[0]
|
|
|
+ if (firstError && firstError.message) {
|
|
|
+ errorMessage = firstError.message
|
|
|
}
|
|
|
+ } else if (error.message) {
|
|
|
+ errorMessage = error.message
|
|
|
}
|
|
|
}
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: errorMessage,
|
|
|
+ })
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
- const handleRemove = (type: UploadFileType) => {
|
|
|
- if (type === UploadFileType.LICENSE_NUMBER) {
|
|
|
- licenseNumberFileList.value = []
|
|
|
- state.form.licenseNumberFile = []
|
|
|
- } else if (type === UploadFileType.ANIMAL_TEST_DATE) {
|
|
|
- animalTestDateFileList.value = []
|
|
|
- state.form.animalTestDateFile = []
|
|
|
- } else if (type === UploadFileType.ENV_TEST_DATE) {
|
|
|
- geneIdentificationFileList.value = []
|
|
|
- state.form.geneIdentificationFile = []
|
|
|
- } else if (type === UploadFileType.ETHICS_CHECK_FILE) {
|
|
|
- ethicsCheckFileList.value = []
|
|
|
- state.form.ethicsCheckFile = []
|
|
|
- } else if (type === UploadFileType.ETHICS_ADVICE_FILE) {
|
|
|
- ethicsAdviceFileList.value = []
|
|
|
- state.form.ethicsAdviceFile = []
|
|
|
- }
|
|
|
- return true
|
|
|
- }
|
|
|
-
|
|
|
- const onProjectConfirm = ({ selectedOptions }: { selectedOptions: any[] }) => {
|
|
|
- if (selectedOptions.length > 0) {
|
|
|
- const selected = selectedOptions[0]
|
|
|
- state.form.projectGroupId = selected.id
|
|
|
- state.form.projectName = selected.projectName
|
|
|
- }
|
|
|
- showProjectPicker.value = false
|
|
|
- }
|
|
|
-
|
|
|
- const onCategoryConfirm = ({ selectedOptions }: { selectedOptions: any[] }) => {
|
|
|
- if (selectedOptions.length > 0) {
|
|
|
- const selected = selectedOptions[0]
|
|
|
- state.form.categoryId = selected.id
|
|
|
- state.form.categoryName = selected.name
|
|
|
- }
|
|
|
- showCategoryPicker.value = false
|
|
|
- }
|
|
|
-
|
|
|
- const onLevelConfirm = ({ selectedOptions }: { selectedOptions: any[] }) => {
|
|
|
- if (selectedOptions.length > 0) {
|
|
|
- const selected = selectedOptions[0]
|
|
|
- state.form.level = selected.id
|
|
|
- state.form.levelName = selected.name
|
|
|
- }
|
|
|
- showLevelPicker.value = false
|
|
|
- }
|
|
|
-
|
|
|
- const onStartDateConfirm = (date: Date) => {
|
|
|
- state.form.startDate = formatDate(date, 'YYYY-mm-dd')
|
|
|
- showStartDatePicker.value = false
|
|
|
+ if (!safePromise.value) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '请阅读并勾选安全承诺!',
|
|
|
+ })
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
- const onComeTimeConfirm = (date: Date) => {
|
|
|
- state.form.comeTime = formatDate(date, 'YYYY-mm-dd')
|
|
|
- showComeTimePicker.value = false
|
|
|
+ if (!state.form.maleNumber && !state.form.famaleNumber) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '请输入雄性或雌性数量!',
|
|
|
+ })
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
- // 提交
|
|
|
- const onSubmit = async () => {
|
|
|
- try {
|
|
|
- await expertDialogFormRef.value?.validate()
|
|
|
- } catch (error: any) {
|
|
|
- // 显示表单验证错误
|
|
|
- let errorMessage = '请完善必填信息'
|
|
|
- if (error) {
|
|
|
- // Vant 表单验证错误可能是数组格式
|
|
|
- if (Array.isArray(error) && error.length > 0) {
|
|
|
- const firstError = error[0]
|
|
|
- if (firstError && firstError.message) {
|
|
|
- errorMessage = firstError.message
|
|
|
- }
|
|
|
- } else if (error.message) {
|
|
|
- errorMessage = error.message
|
|
|
- }
|
|
|
- }
|
|
|
+ // 验证自行购买时的必填项
|
|
|
+ if (state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF) {
|
|
|
+ if (!state.form.licenseNumberFile.length) {
|
|
|
showNotify({
|
|
|
type: 'warning',
|
|
|
- message: errorMessage,
|
|
|
+ message: '请上传生产许可证副本!',
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
-
|
|
|
- if (!safePromise.value) {
|
|
|
+ if (!state.form.animalTestDateFile.length) {
|
|
|
showNotify({
|
|
|
type: 'warning',
|
|
|
- message: '请阅读并勾选安全承诺!',
|
|
|
- })
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- if (!state.form.maleNumber && !state.form.famaleNumber) {
|
|
|
- showNotify({
|
|
|
- type: 'warning',
|
|
|
- message: '请输入雄性或雌性数量!',
|
|
|
+ message: '请上传近三个月动物质量检测证明!',
|
|
|
})
|
|
|
return
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // 验证自行购买时的必填项
|
|
|
- if (state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF) {
|
|
|
- if (!state.form.licenseNumberFile.length) {
|
|
|
- showNotify({
|
|
|
- type: 'warning',
|
|
|
- message: '请上传生产许可证副本!',
|
|
|
- })
|
|
|
- return
|
|
|
- }
|
|
|
- if (!state.form.animalTestDateFile.length) {
|
|
|
- showNotify({
|
|
|
- type: 'warning',
|
|
|
- message: '请上传近三个月动物质量检测证明!',
|
|
|
- })
|
|
|
- return
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // 验证必填文件
|
|
|
- if (!state.form.ethicsCheckFile.length) {
|
|
|
- showNotify({
|
|
|
- type: 'warning',
|
|
|
- message: '请上传实验动物福利伦理审查申请表!',
|
|
|
- })
|
|
|
- return
|
|
|
- }
|
|
|
- if (!state.form.ethicsAdviceFile.length) {
|
|
|
- showNotify({
|
|
|
- type: 'warning',
|
|
|
- message: '请上传实验动物福利伦理审查意见表!',
|
|
|
- })
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- const params = {
|
|
|
- ...deepClone(state.form),
|
|
|
- categoryName: animalTypeList.value.find((item) => item.id == state.form.categoryId)?.name,
|
|
|
- projectGroupName: projects.value.find((item) => item.id == state.form.projectGroupId)?.projectName,
|
|
|
- startDate: dayjs(state.form.startDate).format('YYYY-MM-DD'),
|
|
|
- comeTime: state.form.comeTime ? dayjs(state.form.comeTime).format('YYYY-MM-DD') : '',
|
|
|
- licenseNumberFile: JSON.stringify(state.form.licenseNumberFile),
|
|
|
- animalTestDateFile: JSON.stringify(state.form.animalTestDateFile),
|
|
|
- geneIdentificationFile: JSON.stringify(state.form.geneIdentificationFile),
|
|
|
- ethicsCheckFile: JSON.stringify(state.form.ethicsCheckFile),
|
|
|
- ethicsAdviceFile: JSON.stringify(state.form.ethicsAdviceFile),
|
|
|
- maleNumber: Number(state.form.maleNumber) || 0,
|
|
|
- famaleNumber: Number(state.form.famaleNumber) || 0,
|
|
|
- number: Number(state.form.number) || 1,
|
|
|
- age: Number(state.form.age) || 0,
|
|
|
- weight: state.form.weight ? parseFloat(String(state.form.weight)) : 0,
|
|
|
- feedingDay: Number(state.form.feedingDay) || 0,
|
|
|
- totalNumber: Number(state.form.totalNumber) || 0,
|
|
|
- }
|
|
|
-
|
|
|
- Object.entries(params).forEach(([key, value]) => {
|
|
|
- if (value === '' || value === null) {
|
|
|
- delete params[key as keyof typeof params]
|
|
|
- }
|
|
|
- })
|
|
|
-
|
|
|
- const post = platAnimalCageApplicationApi.create
|
|
|
- const [err]: ToResponse = await to(post(params))
|
|
|
- if (err) return
|
|
|
- showToast({
|
|
|
- type: 'success',
|
|
|
- message: '操作成功',
|
|
|
+ // 验证必填文件
|
|
|
+ if (!state.form.ethicsCheckFile.length) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '请上传实验动物福利伦理审查申请表!',
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!state.form.ethicsAdviceFile.length) {
|
|
|
+ showNotify({
|
|
|
+ type: 'warning',
|
|
|
+ message: '请上传实验动物福利伦理审查意见表!',
|
|
|
})
|
|
|
- closeDialog()
|
|
|
- emit('refresh')
|
|
|
+ return
|
|
|
}
|
|
|
|
|
|
- watch(
|
|
|
- () => [state.form.maleNumber, state.form.famaleNumber],
|
|
|
- ([maleNumber, famaleNumber]) => {
|
|
|
- state.form.totalNumber = (Number(maleNumber) || 0) + (Number(famaleNumber) || 0)
|
|
|
- },
|
|
|
- { immediate: true },
|
|
|
- )
|
|
|
-
|
|
|
- // 暴露变量
|
|
|
- defineExpose({
|
|
|
- openDialog,
|
|
|
+ const params = {
|
|
|
+ ...deepClone(state.form),
|
|
|
+ categoryName: animalTypeList.value.find((item) => item.id == state.form.categoryId)?.name,
|
|
|
+ projectGroupName: projects.value.find((item) => item.id == state.form.projectGroupId)?.projectName,
|
|
|
+ startDate: dayjs(state.form.startDate).format('YYYY-MM-DD'),
|
|
|
+ comeTime: state.form.comeTime ? dayjs(state.form.comeTime).format('YYYY-MM-DD') : '',
|
|
|
+ licenseNumberFile: JSON.stringify(state.form.licenseNumberFile),
|
|
|
+ animalTestDateFile: JSON.stringify(state.form.animalTestDateFile),
|
|
|
+ geneIdentificationFile: JSON.stringify(state.form.geneIdentificationFile),
|
|
|
+ ethicsCheckFile: JSON.stringify(state.form.ethicsCheckFile),
|
|
|
+ ethicsAdviceFile: JSON.stringify(state.form.ethicsAdviceFile),
|
|
|
+ maleNumber: Number(state.form.maleNumber) || 0,
|
|
|
+ famaleNumber: Number(state.form.famaleNumber) || 0,
|
|
|
+ number: Number(state.form.number) || 1,
|
|
|
+ age: Number(state.form.age) || 0,
|
|
|
+ weight: state.form.weight ? parseFloat(String(state.form.weight)) : 0,
|
|
|
+ feedingDay: Number(state.form.feedingDay) || 0,
|
|
|
+ totalNumber: Number(state.form.totalNumber) || 0,
|
|
|
+ }
|
|
|
+
|
|
|
+ Object.entries(params).forEach(([key, value]) => {
|
|
|
+ if (value === '' || value === null) {
|
|
|
+ delete params[key as keyof typeof params]
|
|
|
+ }
|
|
|
})
|
|
|
+
|
|
|
+ const post = platAnimalCageApplicationApi.create
|
|
|
+ const [err]: ToResponse = await to(post(params))
|
|
|
+ if (err) return
|
|
|
+ showToast({
|
|
|
+ type: 'success',
|
|
|
+ message: '操作成功',
|
|
|
+ })
|
|
|
+ closeDialog()
|
|
|
+ emit('refresh')
|
|
|
+}
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => [state.form.maleNumber, state.form.famaleNumber],
|
|
|
+ ([maleNumber, famaleNumber]) => {
|
|
|
+ state.form.totalNumber = (Number(maleNumber) || 0) + (Number(famaleNumber) || 0)
|
|
|
+ },
|
|
|
+ { immediate: true },
|
|
|
+)
|
|
|
+
|
|
|
+// 暴露变量
|
|
|
+defineExpose({
|
|
|
+ openDialog,
|
|
|
+})
|
|
|
</script>
|
|
|
<style lang="scss" scoped>
|
|
|
- .application-dialog-container {
|
|
|
- .popup-wrapper {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- height: 100%;
|
|
|
- overflow: hidden;
|
|
|
- }
|
|
|
+.application-dialog-container {
|
|
|
+ .popup-wrapper {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
|
|
|
- .popup-title {
|
|
|
- font-size: 18px;
|
|
|
- font-weight: 600;
|
|
|
- text-align: center;
|
|
|
- padding: 16px 0;
|
|
|
- margin: 0;
|
|
|
- border-bottom: 1px solid #ebedf0;
|
|
|
- flex-shrink: 0;
|
|
|
- background-color: #fff;
|
|
|
- position: sticky;
|
|
|
- top: 0;
|
|
|
- z-index: 1;
|
|
|
- padding-right: 40px;
|
|
|
- }
|
|
|
+ .popup-title {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ text-align: center;
|
|
|
+ padding: 16px 0;
|
|
|
+ margin: 0;
|
|
|
+ border-bottom: 1px solid #ebedf0;
|
|
|
+ flex-shrink: 0;
|
|
|
+ background-color: #fff;
|
|
|
+ position: sticky;
|
|
|
+ top: 0;
|
|
|
+ z-index: 1;
|
|
|
+ padding-right: 40px;
|
|
|
+ }
|
|
|
|
|
|
- .popup-content {
|
|
|
- flex: 1;
|
|
|
- padding: 16px;
|
|
|
- overflow-y: auto;
|
|
|
- -webkit-overflow-scrolling: touch;
|
|
|
- }
|
|
|
+ .popup-content {
|
|
|
+ flex: 1;
|
|
|
+ padding: 16px;
|
|
|
+ overflow-y: auto;
|
|
|
+ -webkit-overflow-scrolling: touch;
|
|
|
+ }
|
|
|
|
|
|
- h4 {
|
|
|
- font-size: 16px;
|
|
|
- font-weight: 600;
|
|
|
- margin: 16px 0 8px;
|
|
|
- padding-left: 8px;
|
|
|
- position: relative;
|
|
|
-
|
|
|
- &::before {
|
|
|
- content: '';
|
|
|
- position: absolute;
|
|
|
- left: 0;
|
|
|
- top: 50%;
|
|
|
- transform: translateY(-50%);
|
|
|
- width: 3px;
|
|
|
- height: 16px;
|
|
|
- background-color: #1c9bfd;
|
|
|
- }
|
|
|
+ h4 {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 600;
|
|
|
+ margin: 16px 0 8px;
|
|
|
+ padding-left: 8px;
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ &::before {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ top: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ width: 3px;
|
|
|
+ height: 16px;
|
|
|
+ background-color: #1c9bfd;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- .checkbox-wrapper {
|
|
|
- padding: 16px;
|
|
|
- background-color: #f7f8fa;
|
|
|
- border-radius: 8px;
|
|
|
- margin: 16px 0;
|
|
|
+ .checkbox-wrapper {
|
|
|
+ padding: 16px;
|
|
|
+ background-color: #f7f8fa;
|
|
|
+ border-radius: 8px;
|
|
|
+ margin: 16px 0;
|
|
|
|
|
|
.safePromise {
|
|
|
white-space: pre-wrap;
|
|
|
- line-height: 1.6;
|
|
|
- }
|
|
|
+ line-height: 1.6;
|
|
|
}
|
|
|
-
|
|
|
- .dialog-footer {
|
|
|
- padding: 16px;
|
|
|
- padding-bottom: calc(16px + env(safe-area-inset-bottom));
|
|
|
- flex-shrink: 0;
|
|
|
- background-color: #fff;
|
|
|
- border-top: 1px solid #ebedf0;
|
|
|
- position: sticky;
|
|
|
- bottom: 0;
|
|
|
- z-index: 10;
|
|
|
- }
|
|
|
-
|
|
|
- .upload-tip {
|
|
|
- font-size: 12px;
|
|
|
- color: #969799;
|
|
|
- margin-top: 8px;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- :deep(.van-checkbox) {
|
|
|
- white-space: pre-wrap;
|
|
|
- line-height: 1.6;
|
|
|
}
|
|
|
|
|
|
- :deep(.van-field__label) {
|
|
|
- width: 120px;
|
|
|
+ .dialog-footer {
|
|
|
+ padding: 16px;
|
|
|
+ padding-bottom: calc(16px + env(safe-area-inset-bottom));
|
|
|
+ flex-shrink: 0;
|
|
|
+ background-color: #fff;
|
|
|
+ border-top: 1px solid #ebedf0;
|
|
|
+ position: sticky;
|
|
|
+ bottom: 0;
|
|
|
+ z-index: 10;
|
|
|
}
|
|
|
|
|
|
- :deep(.van-popup__close-icon) {
|
|
|
- z-index: 100;
|
|
|
- top: 16px;
|
|
|
- right: 16px;
|
|
|
+ .upload-tip {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #969799;
|
|
|
+ margin-top: 8px;
|
|
|
}
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.van-checkbox) {
|
|
|
+ white-space: pre-wrap;
|
|
|
+ line-height: 1.6;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.van-field__label) {
|
|
|
+ width: 120px;
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.van-popup__close-icon) {
|
|
|
+ z-index: 100;
|
|
|
+ top: 16px;
|
|
|
+ right: 16px;
|
|
|
+}
|
|
|
</style>
|