| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736 |
- <template>
- <div class="application-dialog-container">
- <el-dialog :title="state.dialog.title" @close="onCancel" :close-on-click-modal="false" :destroy-on-close="true"
- v-model="state.dialog.isShowDialog" width="800px">
- <el-form ref="expertDialogFormRef" :model="state.form" :rules="rules" size="default" label-width="140px"
- label-position="top">
- <LaText size="16" type="important" bold class="mb16">基本信息</LaText>
- <el-row :gutter="20">
- <el-col :span="12" class="mb16">
- <el-form-item label="课题名称" prop="projectGroupId">
- <el-select :disabled="state.dialog.type === 'view'" v-model="state.form.projectGroupId" placeholder="请选择">
- <el-option v-for="item in projects" :key="item.id" :label="item.projectName" :value="item.id" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12" class="mb16">
- <el-form-item label="姓名" prop="group">
- <el-input v-if="state.dialog.type === 'add'" v-model="userInfos.nickName" disabled />
- <el-input v-else v-model="state.form.userName" disabled />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="12" class="mb16">
- <el-form-item label="部门" prop="deptName">
- <el-input v-if="state.dialog.type === 'add'" v-model="userInfos.deptName" disabled />
- <el-input v-else v-model="state.form.deptName" disabled />
- </el-form-item>
- </el-col>
- <el-col :span="12" class="mb16">
- <el-form-item label="联系方式" prop="phone">
- <el-input v-if="state.dialog.type === 'add'" v-model="userInfos.phone" disabled />
- <el-input v-else v-model="state.form.phone" disabled />
- </el-form-item>
- </el-col>
- </el-row>
- <LaText class="mb16 mt20" size="16" type="important" bold>实验动物笼位预约信息</LaText>
- <el-row class="mt10" :gutter="20">
- <el-col :span="12" class="mb16">
- <el-form-item label="笼位数量" prop="number">
- <el-input-number :disabled="state.dialog.type === 'view'" v-model="state.form.number" style="width: 100%"
- :min="1" />
- </el-form-item>
- </el-col>
- <el-col :span="12" class="mb16">
- <el-form-item label="开始使用时间" prop="startDate">
- <el-date-picker :disabled="state.dialog.type === 'view'" v-model="state.form.startDate" type="date"
- placeholder="请选择开始使用时间" clearable style="width: 100%" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row class="mt10" :gutter="20">
- <el-col :span="12" class="mb16">
- <el-form-item label="动物类别" prop="categoryId">
- <el-select :disabled="state.dialog.type === 'view'" v-model="state.form.categoryId" placeholder="请选择">
- <el-option v-for="item in animalTypeList" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12" class="mb16">
- <el-form-item label="品种品系" prop="variety">
- <el-input :disabled="state.dialog.type === 'view'" v-model="state.form.variety" placeholder="请输入品种品系" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row class="mt10" :gutter="20">
- <el-col :span="12" class="mb16">
- <el-form-item label="饲养区域" prop="level">
- <el-select :disabled="state.dialog.type === 'view'" v-model="state.form.level" placeholder="请选择">
- <el-option v-for="item in LeavelList" :key="item.id" :label="item.name" :value="item.id" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="12" class="mb16">
- <el-form-item label="周龄(w)" prop="age">
- <div style="display: flex; align-items: center; gap: 8px;">
- <el-input-number :disabled="state.dialog.type === 'view'" v-model="state.form.age.min"
- placeholder="最小周龄" style="width: 45%" :min="0" />
- <span style="color: #999;">至</span>
- <el-input-number :disabled="state.dialog.type === 'view'" v-model="state.form.age.max"
- placeholder="最大周龄" style="width: 45%" :min="0" />
- </div>
- </el-form-item>
- </el-col>
- <el-col :span="12" class="mb16">
- <el-form-item label="体重(g)" prop="weight">
- <div style="display: flex; align-items: center; gap: 8px;">
- <el-input-number :disabled="state.dialog.type === 'view'" v-model="state.form.weight.min"
- placeholder="最小体重" style="width: 45%" :min="0" :precision="2" />
- <span style="color: #999;">至</span>
- <el-input-number :disabled="state.dialog.type === 'view'" v-model="state.form.weight.max"
- placeholder="最大体重" style="width: 45%" :min="0" :precision="2" />
- </div>
- </el-form-item>
- </el-col>
- <el-col :span="12" class="mb16">
- <el-form-item label="饲养总天数" prop="feedingDay">
- <el-input-number :disabled="state.dialog.type === 'view'" v-model="state.form.feedingDay"
- style="width: 100%" :min="1" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row class="mt10" :gutter="20">
- <el-col :span="6" class="mb16">
- <el-form-item label="雄性" prop="maleNumber">
- <el-input-number style="width: 100%" :disabled="state.dialog.type === 'view'" placeholder="雄性数量"
- v-model="state.form.maleNumber" :min="0" />
- </el-form-item>
- </el-col>
- <el-col :span="6" class="mb16">
- <el-form-item label="雌性" prop="famaleNumber">
- <el-input-number style="width: 100%" :disabled="state.dialog.type === 'view'" placeholder="雌性数量"
- v-model="state.form.famaleNumber" :min="0" />
- </el-form-item>
- </el-col>
- <el-col :span="12" class="mb16">
- <el-form-item label="合计" prop="totalNumber">
- <el-input-number style="width: 100%" disabled placeholder="合计" v-model="state.form.totalNumber"
- :min="0" />
- </el-form-item>
- </el-col>
- </el-row>
- <LaText class="mb16 mt20" size="16" type="important" bold>采购渠道</LaText>
- <el-row class="mt10" :gutter="20">
- <el-col :span="12" class="mb16">
- <el-form-item label="采购渠道" prop="buyFrom">
- <el-radio-group :disabled="state.dialog.type === 'view'" v-model="state.form.buyFrom">
- <el-radio :label="ProcurementChannels.PURCHASED_BY_OTHERS" size="large">动物房代购</el-radio>
- <el-radio :label="ProcurementChannels.PURCHASED_BY_MYSELF" size="large">自行购买</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="12" class="mb16">
- <el-form-item label="动物到达时间" prop="comeTime"
- :required="state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF">
- <el-date-picker :disabled="state.dialog.type === 'view'" v-model="state.form.comeTime" type="date"
- placeholder="请选择到达时间" clearable style="width: 100%" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row v-if="state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF" class="mt10" :gutter="20">
- <el-col :span="12" class="mb16">
- <el-form-item label="外购来源单位"
- :prop="state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF ? 'comeFromUnit' : ''">
- <el-input :disabled="state.dialog.type === 'view'" v-model="state.form.comeFromUnit" />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row class="mt10" :gutter="20" v-if="state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF">
- <el-col :span="12" class="mb16">
- <el-form-item label="生产许可证副本" prop="licenseNumberFile"
- :required="state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF">
- <el-upload v-model:file-list="licenseNumberFileList" class="upload-demo" :action="uploadUrl" :limit="1"
- style="width: 100%" :before-upload="beforeAvatarFileUpload" :disabled="state.dialog.type === 'view'"
- :on-preview="handlePreview" :on-remove="() => handleRemove(UploadFileType.LICENSE_NUMBER)"
- :on-success="(res: any, file: UploadFile) => handleSuccess(res, UploadFileType.LICENSE_NUMBER, file)">
- <el-button :disabled="state.dialog.type === 'view'" type="primary">点击上传</el-button>
- <div class="el-upload__tip ml10">支持格式:jpg png pdf等,单个文件不超过20MB</div>
- </el-upload>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row class="mt10" :gutter="20" v-if="state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF">
- <el-col :span="12" class="mb16">
- <el-form-item label="近三个月动物质量检测证明" prop="animalTestDateFile"
- :required="state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF">
- <el-upload v-model:file-list="animalTestDateFileList" class="upload-demo" :action="uploadUrl" :limit="1"
- style="width: 100%" :before-upload="beforeAvatarFileUpload" :on-preview="handlePreview"
- :disabled="state.dialog.type === 'view'"
- :on-remove="() => handleRemove(UploadFileType.ANIMAL_TEST_DATE)"
- :on-success="(res: any, file: UploadFile) => handleSuccess(res, UploadFileType.ANIMAL_TEST_DATE, file)">
- <el-button :disabled="state.dialog.type === 'view'" type="primary">点击上传</el-button>
- <div class="el-upload__tip ml10">支持格式:jpg png pdf等,单个文件不超过20MB</div>
- </el-upload>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row class="mt10" :gutter="20" v-if="state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF">
- <el-col :span="12" class="mb16">
- <el-form-item label="基因鉴定报告" prop="geneIdentificationFile">
- <el-upload v-model:file-list="geneIdentificationFileList" class="upload-demo" :action="uploadUrl"
- :limit="1" style="width: 100%" :before-upload="beforeAvatarFileUpload" :on-preview="handlePreview"
- :disabled="state.dialog.type === 'view'"
- :on-remove="() => handleRemove(UploadFileType.GENE_IDENTIFICATION_FILE)"
- :on-success="(res: any, file: UploadFile) => handleSuccess(res, UploadFileType.GENE_IDENTIFICATION_FILE, file)">
- <el-button :disabled="state.dialog.type === 'view'" type="primary">点击上传</el-button>
- <div class="el-upload__tip ml10">支持格式:jpg png pdf等,单个文件不超过20MB</div>
- </el-upload>
- </el-form-item>
- </el-col>
- </el-row>
- <LaText class="mb16 mt20" size="16" type="important" bold>特殊要求和附件</LaText>
- <el-row class="mt10" :gutter="20">
- <el-col :span="12" class="mb16">
- <el-form-item label="是否有特殊饲养要求" prop="hasFeedingSpecial">
- <el-radio-group :disabled="state.dialog.type === 'view'" v-model="state.form.hasFeedingSpecial">
- <el-radio :label="FeedingSpecial.HAVE_FEEDING_SPECIAL" size="large">有</el-radio>
- <el-radio :label="FeedingSpecial.NO_FEEDING_SPECIAL" size="large">无</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="12" class="mb16" v-if="state.form.hasFeedingSpecial === FeedingSpecial.HAVE_FEEDING_SPECIAL">
- <el-form-item label="特殊饲养要求" prop="feedingSpecialDesc" required>
- <el-input :disabled="state.dialog.type === 'view'" placeholder="输入特殊饲养要求,如每天更换垫料等"
- v-model="state.form.feedingSpecialDesc" />
- </el-form-item>
- </el-col>
- </el-row>
- <!-- <el-row class="mt10" :gutter="20">
- <el-col :span="12">
- <el-form-item label="笼位预约表" prop="cageAppointFile">
- <el-upload
- v-model:file-list="cageAppointFileList"
- class="upload-demo"
- :action="uploadUrl"
- :limit="1"
- style="width: 100%"
- :before-upload="beforeAvatarFileUpload"
- :on-preview="handlePreview"
- :disabled="state.dialog.type === 'view'"
- :on-remove="() => handleRemove(UploadFileType.CAGE_APPOINT_FILE)"
- :on-success="(res: any, file: UploadFile) => handleSuccess(res, UploadFileType.CAGE_APPOINT_FILE, file)"
- >
- <el-button :disabled="state.dialog.type === 'view'" type="primary">点击上传</el-button>
- <div class="el-upload__tip ml10">支持格式:jpg png pdf等,单个文件不超过20MB</div>
- </el-upload>
- </el-form-item>
- </el-col>
- </el-row> -->
- <el-row class="mt10" :gutter="20">
- <el-col :span="12" class="mb16">
- <el-form-item label="实验动物福利伦理审查申请表" prop="ethicsCheckFile" required>
- <el-upload v-model:file-list="ethicsCheckFileList" class="upload-demo" :action="uploadUrl" :limit="1"
- style="width: 100%" :before-upload="beforeAvatarFileUpload" :on-preview="handlePreview"
- :disabled="state.dialog.type === 'view'"
- :on-remove="() => handleRemove(UploadFileType.ETHICS_CHECK_FILE)"
- :on-success="(res: any, file: UploadFile) => handleSuccess(res, UploadFileType.ETHICS_CHECK_FILE, file)">
- <el-button :disabled="state.dialog.type === 'view'" type="primary">点击上传</el-button>
- <div class="el-upload__tip ml10">支持格式:jpg png pdf等,单个文件不超过20MB</div>
- </el-upload>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row class="mt10" :gutter="20">
- <el-col :span="12" class="mb16">
- <el-form-item label="实验动物福利伦理审查意见表" prop="ethicsAdviceFile" required>
- <el-upload v-model:file-list="ethicsAdviceFileList" class="upload-demo" :action="uploadUrl" :limit="1"
- style="width: 100%" :before-upload="beforeAvatarFileUpload" :on-preview="handlePreview"
- :disabled="state.dialog.type === 'view'"
- :on-remove="() => handleRemove(UploadFileType.ETHICS_ADVICE_FILE)"
- :on-success="(res: any, file: UploadFile) => handleSuccess(res, UploadFileType.ETHICS_ADVICE_FILE, file)">
- <el-button :disabled="state.dialog.type === 'view'" type="primary">点击上传</el-button>
- <div class="el-upload__tip ml10">支持格式:jpg png pdf等,单个文件不超过20MB</div>
- </el-upload>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row v-if="state.dialog.type === 'view'">
- <el-col :span="24" class="mb16">
- <LaText class="mb16 mt20" size="16" type="important" bold>审批流</LaText>
- <FlowTable :id="state.form.id" :businessCode="state.form.id + ''" defCode="plat_cage_applications" />
- </el-col>
- </el-row>
- <el-row class="mt10" :gutter="20">
- <el-col :span="24" class="mt30 mb16">
- <el-checkbox :disabled="state.dialog.type === 'view'" v-model="safePromiseStatus">
- {{ SafePromise }}
- </el-checkbox>
- </el-col>
- </el-row>
- </el-form>
- <template #footer>
- <span v-if="state.dialog.type === 'add'" class="dialog-footer">
- <el-button type="info" @click="onCancel" size="default">取 消</el-button>
- <el-button color="#2c78ff" @click="onSubmit()" size="default">提交</el-button>
- </span>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup lang="ts" name="systemProDialog">
- import { reactive, ref, computed, defineAsyncComponent, watch } from 'vue';
- import to from 'await-to-js';
- import { ElMessage } from 'element-plus';
- import { storeToRefs } from 'pinia';
- import dayjs from 'dayjs';
- import { UploadFile } from 'element-plus/es/components';
- import { usePlatAnimalCageApplicationApi } from 'labsop-api/src/api/platform/animal';
- import {
- LeavelList,
- ProcurementChannels,
- UploadFileType,
- FeedingSpecial,
- SafePromise,
- DateFormat,
- } from '/@/constants/pageConstants';
- import { deepClone } from '/@/utils/other';
- import { useUserInfo } from '/@/stores/userInfo';
- const uploadUrl = (import.meta as any).env.VITE_UPLOAD;
- const stores = useUserInfo();
- const { userInfos } = storeToRefs(stores);
- const FlowTable = defineAsyncComponent(() => import('/@/components/flow/flow-table.vue'));
- // 定义子组件向父组件传值/事件
- const emit = defineEmits(['refresh']);
- const platAnimalCageApplicationApi = usePlatAnimalCageApplicationApi();
- const expertDialogFormRef = ref();
- const projectGroupList = ref<any[]>([]);
- const projects = ref<any[]>([]);
- const animalNumber = computed(() => {
- const maleNumber = state.form.maleNumber || 0;
- const famaleNumber = state.form.famaleNumber || 0;
- return maleNumber + famaleNumber;
- });
- const animalTypeList = ref<any[]>([]);
- const licenseNumberFileList = ref<UploadFile[]>([]);
- const animalTestDateFileList = ref<UploadFile[]>([]);
- const geneIdentificationFileList = ref<UploadFile[]>([]);
- const cageAppointFileList = ref<UploadFile[]>([]);
- const ethicsCheckFileList = ref<UploadFile[]>([]);
- const ethicsAdviceFileList = ref<UploadFile[]>([]);
- const safePromiseStatus = ref<boolean>(false);
- const rules = {
- projectGroupId: { required: true, message: '不能为空', trigger: 'change' },
- categoryName: { required: true, message: '不能为空', trigger: 'change' },
- number: { required: true, message: '不能为空', trigger: 'change' },
- startDate: { required: true, message: '不能为空', trigger: 'change' },
- comeTime: {
- validator: (rule: any, value: any, callback: any) => {
- // 只有在自行购买时才验证动物到达时间
- if (state.form.buyFrom === ProcurementChannels.PURCHASED_BY_MYSELF && (!value || value === '')) {
- callback(new Error('动物到达时间不能为空'));
- } else {
- callback();
- }
- },
- trigger: 'change',
- },
- // maleNumber: { required: true, message: '不能为空', trigger: 'change' },
- // weight: { required: true, message: '不能为空', trigger: 'change' },
- buyFrom: { required: true, message: '不能为空', trigger: 'change' },
- comeFromUnit: { required: true, message: '不能为空', trigger: 'change' },
- variety: { required: true, message: '不能为空', trigger: 'change' },
- categoryId: { required: true, message: '不能为空', trigger: 'change' },
- feedingDay: { required: true, message: '不能为空', trigger: 'change' },
- level: { required: true, message: '不能为空', trigger: 'change' },
- // feedingSpecialDesc: { required: true, message: '不能为空', trigger: 'change' },
- // ethicsCheckFile: { required: true, message: '不能为空', trigger: 'change' },
- // ethicsAdviceFile: { required: true, message: '不能为空', trigger: 'change' },
- licenseNumberFile: {
- validator: (rule: any, value: any, callback: any) => {
- // 只有在动物房代购时才验证这些字段
- if (state.form.buyFrom === ProcurementChannels.PURCHASED_BY_OTHERS && (!value || value.length === 0)) {
- callback(new Error('生产许可证副本不能为空'));
- } else {
- callback();
- }
- },
- trigger: 'change',
- },
- animalTestDateFile: {
- validator: (rule: any, value: any, callback: any) => {
- // 只有在动物房代购时才验证这些字段
- if (state.form.buyFrom === ProcurementChannels.PURCHASED_BY_OTHERS && (!value || value.length === 0)) {
- callback(new Error('动物质检证明不能为空'));
- } else {
- callback();
- }
- },
- trigger: 'change',
- },
- ethicsCheckFile: {
- validator: (rule: any, value: any, callback: any) => {
- if (!value || value.length === 0) {
- callback(new Error('实验动物福利伦理审查申请表不能为空'));
- } else {
- callback();
- }
- },
- trigger: 'change',
- },
- ethicsAdviceFile: {
- validator: (rule: any, value: any, callback: any) => {
- if (!value || value.length === 0) {
- callback(new Error('实验动物福利伦理审查意见表不能为空'));
- } else {
- callback();
- }
- },
- trigger: 'change',
- },
- feedingSpecialDesc: {
- validator: (rule: any, value: any, callback: any) => {
- // 只有在有特殊饲养要求时才验证特殊饲养要求描述
- if (state.form.hasFeedingSpecial === FeedingSpecial.HAVE_FEEDING_SPECIAL && (!value || value.trim() === '')) {
- callback(new Error('特殊饲养要求不能为空'));
- } else {
- callback();
- }
- },
- trigger: 'change',
- },
- age: {
- validator: (rule: any, value: any, callback: any) => {
- if (!value || value.min === null || value.max === null) {
- callback(new Error('周龄范围不能为空'));
- } else if (value.min > value.max) {
- callback(new Error('最小周龄不能大于最大周龄'));
- } else {
- callback();
- }
- },
- trigger: 'change',
- },
- weight: {
- validator: (rule: any, value: any, callback: any) => {
- if (!value || value.min === null || value.max === null) {
- callback(new Error('体重范围不能为空'));
- } else if (value.min > value.max) {
- callback(new Error('最小体重不能大于最大体重'));
- } else {
- callback();
- }
- },
- trigger: 'change',
- },
- };
- const defaultFormFields = {
- id: 0,
- projectGroupName: '',
- projectGroupId: null,
- categoryName: '',
- categoryId: null,
- level: null,
- number: 1,
- startDate: '',
- maleNumber: 0,
- famaleNumber: 0,
- totalNumber: 0,
- weight: { min: 0, max: 0 },
- age: { min: 0, max: 0 },
- feedingDay: 0,
- userName: '',
- deptId: null,
- deptName: '',
- phone: '',
- buyFrom: ProcurementChannels.PURCHASED_BY_OTHERS,
- comeTime: '',
- comeFromUnit: '',
- licenseNumberFile: [] as { name: string; url: string }[],
- animalTestDateFile: [] as { name: string; url: string }[],
- geneIdentificationFile: [] as { name: string; url: string }[],
- hasFeedingSpecial: FeedingSpecial.HAVE_FEEDING_SPECIAL,
- feedingSpecialDesc: '',
- cageAppointFile: [] as { name: string; url: string }[],
- ethicsCheckFile: [] as { name: string; url: string }[],
- ethicsAdviceFile: [] as { name: string; url: string }[],
- };
- const state = reactive({
- form: defaultFormFields,
- safePromise: false,
- safeRead: false,
- dialog: {
- isShowDialog: false,
- type: '',
- title: '',
- submitTxt: '',
- },
- });
- watch(
- () => [state.form.maleNumber, state.form.famaleNumber],
- ([maleNumber, famaleNumber]) => {
- state.form.totalNumber = (maleNumber || 0) + (famaleNumber || 0);
- },
- { immediate: true }
- );
- 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 isValidJsonArray = (str: string) => {
- try {
- const parsed = JSON.parse(str);
- return Array.isArray(parsed);
- } catch (e) {
- return false;
- }
- };
- const parseRangeField = (str: string) => {
- try {
- if (!str) return { min: 0, max: 0 };
- // 处理双重转义的情况
- const cleanStr = str.replace(/\\"/g, '"').replace(/^"|"$/g, '');
- const parsed = JSON.parse(cleanStr);
- return {
- min: parsed.min || 0,
- max: parsed.max || 0
- };
- } catch (e) {
- console.warn('解析范围字段失败:', str, e);
- return { min: 0, max: 0 };
- }
- };
- // 打开弹窗
- const openDialog = async (type: 'add' | 'view', row?: any) => {
- await getDicts();
- state.dialog.type = type;
- state.dialog.title = '笼位申请';
- if (type === 'view' && row) {
- // 处理范围字段的JSON字符串
- const processedRow = {
- ...row,
- age: parseRangeField(row.age),
- weight: parseRangeField(row.weight)
- };
- state.form = processedRow;
- licenseNumberFileList.value = isValidJsonArray(row.licenseNumberFile) ? JSON.parse(row.licenseNumberFile) : [];
- animalTestDateFileList.value = isValidJsonArray(row.animalTestDateFile) ? JSON.parse(row.animalTestDateFile) : [];
- geneIdentificationFileList.value = isValidJsonArray(row.geneIdentificationFile)
- ? JSON.parse(row.geneIdentificationFile)
- : [];
- cageAppointFileList.value = isValidJsonArray(row.cageAppointFile) ? JSON.parse(row.cageAppointFile) : [];
- ethicsCheckFileList.value = isValidJsonArray(row.ethicsCheckFile) ? JSON.parse(row.ethicsCheckFile) : [];
- ethicsAdviceFileList.value = isValidJsonArray(row.ethicsAdviceFile) ? JSON.parse(row.ethicsAdviceFile) : [];
- safePromiseStatus.value = true;
- } else if (type === 'add') {
- // 回显并写入当前人的部门与联系方式,用于提交
- state.form.deptId = userInfos.value?.deptId || null;
- state.form.deptName = userInfos.value?.deptName || '';
- state.form.phone = userInfos.value?.phone || '';
- }
- state.dialog.isShowDialog = true;
- };
- // 关闭弹窗
- const closeDialog = () => {
- state.form = defaultFormFields;
- licenseNumberFileList.value = [];
- animalTestDateFileList.value = [];
- geneIdentificationFileList.value = [];
- cageAppointFileList.value = [];
- ethicsCheckFileList.value = [];
- ethicsAdviceFileList.value = [];
- safePromiseStatus.value = false;
- state.dialog.isShowDialog = false;
- };
- // 取消
- const onCancel = () => {
- closeDialog();
- };
- const beforeAvatarFileUpload = (file: { size: number }) => {
- let isLt10m = file.size / 1024 / 1024 / 20 < 1;
- if (!isLt10m) {
- ElMessage.error('上传文件大小不能超过 20MB!');
- return false;
- }
- return true;
- };
- 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.GENE_IDENTIFICATION_FILE) {
- geneIdentificationFileList.value = [];
- state.form.geneIdentificationFile = [];
- } else if (type === UploadFileType.CAGE_APPOINT_FILE) {
- cageAppointFileList.value = [];
- state.form.cageAppointFile = [];
- } else if (type === UploadFileType.ETHICS_CHECK_FILE) {
- ethicsCheckFileList.value = [];
- state.form.ethicsCheckFile = [];
- } else if (type === UploadFileType.ETHICS_ADVICE_FILE) {
- ethicsAdviceFileList.value = [];
- state.form.ethicsAdviceFile = [];
- }
- };
- const handleSuccess = (res: { Data: string }, type: UploadFileType, file: UploadFile) => {
- console.log('ressss', res, file);
- if (type === UploadFileType.LICENSE_NUMBER) {
- state.form.licenseNumberFile = [{ name: file.name, url: res?.Data }];
- } else if (type === UploadFileType.ANIMAL_TEST_DATE) {
- state.form.animalTestDateFile = [{ name: file.name, url: res?.Data }];
- } else if (type === UploadFileType.GENE_IDENTIFICATION_FILE) {
- state.form.geneIdentificationFile = [{ name: file.name, url: res?.Data }];
- } else if (type === UploadFileType.CAGE_APPOINT_FILE) {
- state.form.cageAppointFile = [{ name: file.name, url: res?.Data }];
- } else if (type === UploadFileType.ETHICS_CHECK_FILE) {
- state.form.ethicsCheckFile = [{ name: file.name, url: res?.Data }];
- } else if (type === UploadFileType.ETHICS_ADVICE_FILE) {
- state.form.ethicsAdviceFile = [{ name: file.name, url: res?.Data }];
- }
- };
- const handlePreview = (file: UploadFile) => {
- if (file.url) {
- window.open(file.url, '_blank');
- }
- };
- // 提交
- const onSubmit = async () => {
- expertDialogFormRef.value.validate(async (valid: boolean) => {
- if (!valid) return;
- if (!safePromiseStatus.value) {
- ElMessage.error('请阅读并勾选安全承诺!');
- return;
- }
- if (!state.form.maleNumber && !state.form.famaleNumber) {
- ElMessage.error('请添加雄性或雌性数量!');
- return;
- }
- // json 字符串化
- state.form.age= JSON.stringify(state.form.age);
- state.form.weight = JSON.stringify(state.form.weight);
- const params = {
- ...deepClone(state.form),
- categoryId: state.form.categoryId != null ? String(state.form.categoryId) : null,
- 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(DateFormat),
- comeTime: state.form.comeTime ? dayjs(state.form.comeTime).format(DateFormat) : '',
- // 将范围对象转换为JSON字符串
- age: JSON.stringify(state.form.age),
- weight: JSON.stringify(state.form.weight),
- licenseNumberFile: JSON.stringify(state.form.licenseNumberFile),
- animalTestDateFile: JSON.stringify(state.form.animalTestDateFile),
- geneIdentificationFile: JSON.stringify(state.form.geneIdentificationFile),
- cageAppointFile: JSON.stringify(state.form.cageAppointFile),
- ethicsCheckFile: JSON.stringify(state.form.ethicsCheckFile),
- ethicsAdviceFile: JSON.stringify(state.form.ethicsAdviceFile),
- };
- 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;
- ElMessage.success('操作成功');
- closeDialog();
- emit('refresh');
- });
- };
- // 暴露变量
- defineExpose({
- openDialog,
- });
- </script>
- <style lang="scss" scoped>
- .application-dialog-container {
- .el-select {
- width: 100%;
- }
- }
- h4 {
- font-size: 18px;
- }
- ul {
- padding-left: 20px;
- }
- .text {
- p {
- text-indent: 2em;
- }
- }
- .el-upload+.el-button {
- vertical-align: top;
- }
- :deep(.el-checkbox) {
- white-space: pre-wrap;
- }
- </style>
|