parent
cda5fee482
commit
16855109ff
20 changed files with 1408 additions and 66 deletions
@ -1,28 +0,0 @@ |
|||||||
<template> |
|
||||||
<div> |
|
||||||
<el-tabs v-model="curTab" |
|
||||||
@tab-click="tabChange"> |
|
||||||
<el-tab-pane label="产品要素" |
|
||||||
name="tab1"> |
|
||||||
<info /> |
|
||||||
</el-tab-pane> |
|
||||||
</el-tabs> |
|
||||||
</div> |
|
||||||
</template> |
|
||||||
|
|
||||||
<script setup lang="ts"> |
|
||||||
import { ref, computed, watch, onMounted } from 'vue'; |
|
||||||
import type { TabsPaneContext } from 'element-plus'; |
|
||||||
import Info from './Info.vue'; |
|
||||||
|
|
||||||
const curTab = ref<string>('tab1'); |
|
||||||
|
|
||||||
// tab切换回调 |
|
||||||
const tabChange = (tab: TabsPaneContext, event: Event) => { |
|
||||||
console.log(tab, event); |
|
||||||
}; |
|
||||||
</script> |
|
||||||
|
|
||||||
<style lang="scss" scoped> |
|
||||||
@import url(../../styles/form.scss); |
|
||||||
</style> |
|
@ -0,0 +1,21 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-tabs v-model="curTab"> |
||||||
|
<el-tab-pane label="产品要素" |
||||||
|
name="tab1"> |
||||||
|
<info /> |
||||||
|
</el-tab-pane> |
||||||
|
</el-tabs> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { ref } from 'vue'; |
||||||
|
import Info from './Info.vue'; |
||||||
|
|
||||||
|
const curTab = ref<string>('tab1'); |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
@import url(../../../styles/form.scss); |
||||||
|
</style> |
@ -0,0 +1,532 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-tabs v-model="curTab" |
||||||
|
@tab-click="tabChange"> |
||||||
|
<el-tab-pane :label="id ? '产品要素' : '新增产品'" |
||||||
|
name="tab1"> |
||||||
|
<div v-if="info" |
||||||
|
class="audit"> |
||||||
|
<div class="line"> |
||||||
|
<span class="field">审批意见:</span> |
||||||
|
<span class="status">{{ getStatus(+info?.status) }}</span> |
||||||
|
</div> |
||||||
|
<div class="line"> |
||||||
|
<span class="field">意见描述:</span> |
||||||
|
{{ info.opinionDescription }} |
||||||
|
</div> |
||||||
|
<p class="mb-2 text-sm text-[#333] text-right">审查日期:{{ info.approvalTime }}</p> |
||||||
|
<p class="mb-2 text-sm text-[#333] text-right">审查员:公瑾</p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<el-form ref="formRef" |
||||||
|
:model="form" |
||||||
|
:rules="rules" |
||||||
|
label-width="100px" |
||||||
|
label-suffix=":" |
||||||
|
class="form" |
||||||
|
status-icon> |
||||||
|
<el-form-item label="产品定义" |
||||||
|
prop="productDefinition"> |
||||||
|
<el-input type="textarea" |
||||||
|
placeholder="用一段话简单介绍一下这个产品或者描述产品的设计理念。例如:本产品根据个人客户的信用状况,为其提供的一种短期融资便利产品,借款人可在额度金额内可循环周转使用贷款。" |
||||||
|
maxlength="200" |
||||||
|
v-model="form.productDefinition"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="产品名称" |
||||||
|
prop="productName"> |
||||||
|
<el-input placeholder="取个有吸引力的产品名,限20字。" |
||||||
|
maxlength="20" |
||||||
|
v-model="form.productName"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="产品币种" |
||||||
|
prop="productCurrency"> |
||||||
|
<el-select v-model="form.productCurrency" |
||||||
|
placeholder="请选择"> |
||||||
|
<el-option label="人民币" |
||||||
|
:value="1" /> |
||||||
|
</el-select> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="贷款对象" |
||||||
|
required> |
||||||
|
<div class="flex-1"> |
||||||
|
<!-- 企业 --> |
||||||
|
<template v-if="form.productType"> |
||||||
|
<div class="flex items-center"> |
||||||
|
<span class="mr-3 text-[#333] text-sm">企业类型</span> |
||||||
|
<el-select v-model="form.productObject" |
||||||
|
placeholder="请选择"> |
||||||
|
<el-option v-for="(item, i) in config.find((e: any) => e.name === '企业产品-贷款对象')?.recordChildren[0]?.subject?.itemList" |
||||||
|
:key="i" |
||||||
|
:label="item.options" |
||||||
|
:value="item.itemId" /> |
||||||
|
</el-select> |
||||||
|
</div> |
||||||
|
<div class="flex items-center mt-4"> |
||||||
|
<span class="mr-3 text-[#333] text-sm">借款人年龄</span> |
||||||
|
<div class="num-inputs ml-7"> |
||||||
|
<el-input placeholder="最小年龄" |
||||||
|
v-model.number="form.minimumAge"></el-input> |
||||||
|
<span class="split">-</span> |
||||||
|
<el-input placeholder="最大年龄" |
||||||
|
v-model.number="form.maximumAge"></el-input> |
||||||
|
<span class="unit">周岁</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<!-- 个人 --> |
||||||
|
<template v-else> |
||||||
|
<p class="field-name">选择本产品的贷款对象。</p> |
||||||
|
<div class="flex items-center mb-2"> |
||||||
|
<el-checkbox class="mt-1" |
||||||
|
v-model="form.age" |
||||||
|
label="年龄" /> |
||||||
|
<div v-if="form.age" |
||||||
|
class="num-inputs ml-7"> |
||||||
|
<el-input placeholder="最小年龄" |
||||||
|
v-model.number="form.minimumAge"></el-input> |
||||||
|
<span class="split">-</span> |
||||||
|
<el-input placeholder="最大年龄" |
||||||
|
v-model.number="form.maximumAge"></el-input> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="flex items-center mb-2"> |
||||||
|
<el-checkbox v-model="form.edu" |
||||||
|
label="学历要求"></el-checkbox> |
||||||
|
<el-checkbox-group v-if="form.edu" |
||||||
|
class="mt-2 ml-5" |
||||||
|
v-model="form.educationalRequirements"> |
||||||
|
<el-checkbox v-for="(item, i) in config.find((e: any) => e.name === '个人产品-贷款对象')?.recordChildren[1]?.subject?.itemList" |
||||||
|
:key="i" |
||||||
|
:label="item.itemId">{{ item.options }}</el-checkbox> |
||||||
|
</el-checkbox-group> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="flex items-center mb-2"> |
||||||
|
<el-checkbox v-model="form.curWL" |
||||||
|
label="工作年限"></el-checkbox> |
||||||
|
<el-checkbox-group v-if="form.curWL" |
||||||
|
class="mt-2 ml-5" |
||||||
|
v-model="form.currentWorkingLife"> |
||||||
|
<el-checkbox v-for="(item, i) in config.find((e: any) => e.name === '个人产品-贷款对象')?.recordChildren[2]?.subject?.itemList" |
||||||
|
:key="i" |
||||||
|
:label="item.itemId">{{ item.options }}</el-checkbox> |
||||||
|
</el-checkbox-group> |
||||||
|
</div> |
||||||
|
<el-checkbox v-model="form.providentFundAndSocialSecurity" |
||||||
|
label="公积金/社保"></el-checkbox> |
||||||
|
</template> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="贷款用途" |
||||||
|
prop="loanPurpose" |
||||||
|
:rules="[ |
||||||
|
{ required: true, message: '请选择贷款用途', trigger: 'change' }, |
||||||
|
{ |
||||||
|
asyncValidator: async (rule, value, callback) => { |
||||||
|
if (value === 107 && !form.otherPurposesOfLoan) { |
||||||
|
callback('请输入其他贷款用途') |
||||||
|
} else { |
||||||
|
callback() |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
]"> |
||||||
|
<div class="flex-1"> |
||||||
|
<p class="field-name">选择本产品贷款资金的用途。</p> |
||||||
|
<el-radio-group v-model="form.loanPurpose"> |
||||||
|
<template v-if="form.productType"> |
||||||
|
<el-radio v-for="(item, i) in config.find((e: any) => e.name === '企业产品-贷款用途')?.subject?.itemList" |
||||||
|
:key="i" |
||||||
|
:label="item.itemId">{{ item.options }}</el-radio> |
||||||
|
</template> |
||||||
|
<template v-else> |
||||||
|
<el-radio v-for="(item, i) in config.find((e: any) => e.name === '个人产品-贷款用途')?.recordChildren" |
||||||
|
:key="i" |
||||||
|
:label="item.id">{{ item.name }}</el-radio> |
||||||
|
</template> |
||||||
|
</el-radio-group> |
||||||
|
<el-input v-if="form?.loanPurpose === 107" |
||||||
|
class="w-[300px] ml-5" |
||||||
|
placeholder="请描述其他贷款用途可用于哪些方面。" |
||||||
|
maxlength="10" |
||||||
|
v-model="form.otherPurposesOfLoan"></el-input> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="担保方式" |
||||||
|
prop="bankGuaranteeTypeIds" |
||||||
|
:rules="[ |
||||||
|
{ required: true, message: '请选择担保方式', trigger: 'change' }, |
||||||
|
{ |
||||||
|
asyncValidator: async (rule, value, callback) => { |
||||||
|
if (value.includes(110) && !value.find((e: any) => e > 22 && e < 33)) { |
||||||
|
callback('请选择抵押物') |
||||||
|
} else if (value.includes(111) && !value.find((e: any) => e > 32 && e < 38)) { |
||||||
|
callback('请选择质押贷') |
||||||
|
} else { |
||||||
|
callback() |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
]"> |
||||||
|
<div class="flex-1"> |
||||||
|
<p class="field-name">选择本产品的担保种类。</p> |
||||||
|
<div v-for="(item, i) in config.find((e: any) => e.name === '担保方式')?.recordChildren" |
||||||
|
:key="i" |
||||||
|
class="mb-2"> |
||||||
|
<el-checkbox-group v-model="form.bankGuaranteeTypeIds"> |
||||||
|
<el-checkbox :label="item.id">{{ item.name }}</el-checkbox> |
||||||
|
<el-checkbox v-show="(item.id === 110 && form.bankGuaranteeTypeIds.includes(110)) || (item.id === 111 && form.bankGuaranteeTypeIds.includes(111))" |
||||||
|
v-for="(child, j) in item?.subject?.itemList" |
||||||
|
:key="j" |
||||||
|
:label="child.itemId">{{ child.options }}</el-checkbox> |
||||||
|
</el-checkbox-group> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="贷款额度" |
||||||
|
prop="minimumLoan" |
||||||
|
:rules="[ |
||||||
|
{ required: true, message: '请输入贷款额度', trigger: 'blur' }, |
||||||
|
{ |
||||||
|
asyncValidator: async (rule, value, callback) => { |
||||||
|
const max = form.loanCeiling |
||||||
|
if (isNaN(value) || value < 0 || max === '' || isNaN(max) || max < 0 || value > max) { |
||||||
|
callback('请输入合理的贷款额度') |
||||||
|
} else { |
||||||
|
callback() |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
]"> |
||||||
|
<div class="flex-1"> |
||||||
|
<div class="num-inputs"> |
||||||
|
<el-input placeholder="最小额度" |
||||||
|
min="0" |
||||||
|
v-model.number="form.minimumLoan"></el-input> |
||||||
|
<span class="split">-</span> |
||||||
|
<el-input placeholder="最高额度" |
||||||
|
min="0" |
||||||
|
v-model.number="form.loanCeiling"></el-input> |
||||||
|
<span class="unit">万元</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="贷款利率" |
||||||
|
prop="minimumAprOnLoan" |
||||||
|
:rules="[ |
||||||
|
{ required: true, message: '请输入贷款利率', trigger: 'blur' }, |
||||||
|
{ |
||||||
|
asyncValidator: async (rule, value, callback) => { |
||||||
|
const max = form.maximumAnnualInterestRate |
||||||
|
if (isNaN(value) || value < 0 || max === '' || isNaN(max) || max < 0 || value > max) { |
||||||
|
callback('请输入合理的贷款利率') |
||||||
|
} else { |
||||||
|
callback() |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
]"> |
||||||
|
<div class="flex-1"> |
||||||
|
<div class="num-inputs"> |
||||||
|
<el-input placeholder="最小年利率" |
||||||
|
min="0" |
||||||
|
v-model.number="form.minimumAprOnLoan"></el-input> |
||||||
|
<span class="split">-</span> |
||||||
|
<el-input placeholder="最高年利率" |
||||||
|
min="0" |
||||||
|
v-model.number="form.maximumAnnualInterestRate"></el-input> |
||||||
|
<span class="unit">%</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="贷款期限" |
||||||
|
prop="minimumTermOfLoan" |
||||||
|
:rules="[ |
||||||
|
{ required: true, message: '请输入贷款期限', trigger: 'blur' }, |
||||||
|
{ |
||||||
|
asyncValidator: async (rule, value, callback) => { |
||||||
|
const max = form.maximumTermOfLoan |
||||||
|
if (isNaN(value) || value < 0 || max === '' || isNaN(max) || max < 0 || value > max) { |
||||||
|
callback('请输入合理的贷款期限') |
||||||
|
} else { |
||||||
|
callback() |
||||||
|
} |
||||||
|
}, |
||||||
|
}, |
||||||
|
]"> |
||||||
|
<div class="flex-1"> |
||||||
|
<div class="num-inputs"> |
||||||
|
<el-input placeholder="最小期限" |
||||||
|
min="0" |
||||||
|
v-model.number="form.minimumTermOfLoan"></el-input> |
||||||
|
<span class="split">-</span> |
||||||
|
<el-input placeholder="最大期限" |
||||||
|
min="0" |
||||||
|
v-model.number="form.maximumTermOfLoan"></el-input> |
||||||
|
<span class="unit">月</span> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="还款方式" |
||||||
|
prop="modeRepayment"> |
||||||
|
<div class="flex-1"> |
||||||
|
<p class="field-name">选择本产品可以选择的还款方式。</p> |
||||||
|
<el-checkbox-group v-model="form.modeRepayment"> |
||||||
|
<el-checkbox v-for="(item, i) in config.find((e: any) => e.name === '还款方式')?.subject?.itemList" |
||||||
|
:key="i" |
||||||
|
:label="item.itemId">{{ item.options }}</el-checkbox> |
||||||
|
</el-checkbox-group> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="提前还款" |
||||||
|
prop="whetherToSupportEarlyRepayment"> |
||||||
|
<div class="flex-1 flex items-center"> |
||||||
|
<el-switch v-model="form.whetherToSupportEarlyRepayment" /> |
||||||
|
<p class="tips ml-4">本产品是否支持提前还款。</p> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<div class="flex justify-end"> |
||||||
|
<div class="submit" |
||||||
|
@click="submit(formRef)">完成,提交风控经理</div> |
||||||
|
</div> |
||||||
|
</el-form> |
||||||
|
</el-tab-pane> |
||||||
|
<el-tab-pane v-if="id" |
||||||
|
label="产品风控" |
||||||
|
name="tab2"> |
||||||
|
<info /> |
||||||
|
</el-tab-pane> |
||||||
|
</el-tabs> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { ref, reactive, computed, watch, onMounted, defineEmits } from 'vue'; |
||||||
|
import { ElMessage } from 'element-plus'; |
||||||
|
import type { TabsPaneContext, FormInstance, FormRules } from 'element-plus'; |
||||||
|
import { findById, save, update } from '@/api/bank'; |
||||||
|
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment'; |
||||||
|
import { useRouter, useRoute } from 'vue-router'; |
||||||
|
import { handleId } from '@/utils/common'; |
||||||
|
import { getStatus } from '@/store/useProduct'; |
||||||
|
import Info from './Info.vue'; |
||||||
|
|
||||||
|
const emit = defineEmits(['getList']); |
||||||
|
interface RuleForm { |
||||||
|
productDefinition: string; |
||||||
|
productName: string; |
||||||
|
productCurrency: number; |
||||||
|
bankGuaranteeTypeIds: any[]; |
||||||
|
currentWorkingLife?: any; |
||||||
|
educationalRequirements?: any; |
||||||
|
loanCeiling: any; |
||||||
|
loanPurpose: any; |
||||||
|
productObject: any; |
||||||
|
maximumAge: any; |
||||||
|
maximumAnnualInterestRate: any; |
||||||
|
maximumTermOfLoan: any; |
||||||
|
age: boolean; |
||||||
|
minimumAge: any; |
||||||
|
minimumAprOnLoan: any; |
||||||
|
minimumLoan: any; |
||||||
|
minimumTermOfLoan: any; |
||||||
|
modeRepayment?: any; |
||||||
|
otherPurposesOfLoan: string; |
||||||
|
productObject: any; |
||||||
|
productType: number; |
||||||
|
providentFundAndSocialSecurity: any; |
||||||
|
whetherToSupportEarlyRepayment?: any; |
||||||
|
} |
||||||
|
|
||||||
|
const router = useRouter(); |
||||||
|
const route = useRoute(); |
||||||
|
const id = computed(() => route.query.id); |
||||||
|
const curTab = ref<string>('tab1'); |
||||||
|
const config = ref<any[]>([]); |
||||||
|
const info = ref<Record<string, any>>(null); |
||||||
|
const formRef = ref<FormInstance>(); |
||||||
|
const form = reactive<RuleForm>({ |
||||||
|
productDefinition: '', |
||||||
|
productName: '', |
||||||
|
productCurrency: 1, |
||||||
|
bankGuaranteeTypeIds: [], |
||||||
|
currentWorkingLife: [], |
||||||
|
educationalRequirements: [], |
||||||
|
loanCeiling: '', |
||||||
|
loanPurpose: '', |
||||||
|
productObject: '', |
||||||
|
maximumAge: '', |
||||||
|
maximumAnnualInterestRate: '', |
||||||
|
maximumTermOfLoan: '', |
||||||
|
age: false, |
||||||
|
minimumAge: '', |
||||||
|
minimumAprOnLoan: '', |
||||||
|
minimumLoan: '', |
||||||
|
minimumTermOfLoan: '', |
||||||
|
modeRepayment: [], |
||||||
|
otherPurposesOfLoan: '', |
||||||
|
productObject: '', |
||||||
|
productType: computed(() => +route.query.type), |
||||||
|
providentFundAndSocialSecurity: false, |
||||||
|
whetherToSupportEarlyRepayment: false, |
||||||
|
}); |
||||||
|
const rules = reactive<FormRules<RuleForm>>({ |
||||||
|
productDefinition: [{ required: true, message: '请输入产品定义', trigger: 'blur' }], |
||||||
|
productName: [{ required: true, message: '请输入产品名称', trigger: 'blur' }], |
||||||
|
productCurrency: [{ required: true, message: '请选择产品币种', trigger: 'change' }], |
||||||
|
modeRepayment: [{ required: true, message: '请选择还款方式', trigger: 'change' }], |
||||||
|
}); |
||||||
|
|
||||||
|
// tab切换回调 |
||||||
|
const tabChange = (tab: TabsPaneContext, event: Event) => { |
||||||
|
console.log(tab, event); |
||||||
|
}; |
||||||
|
// 配置项 |
||||||
|
const getConfig = async () => { |
||||||
|
const { process } = await getProcessInformationBasedOnRoles(form.productType === 1 ? 45 : 44); |
||||||
|
config.value = process; |
||||||
|
}; |
||||||
|
// 详情 |
||||||
|
const getDetail = async () => { |
||||||
|
if (id.value) { |
||||||
|
try { |
||||||
|
const { data } = await findById(id.value); |
||||||
|
info.value = data; |
||||||
|
} finally { |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
watch( |
||||||
|
() => route.query, |
||||||
|
() => { |
||||||
|
getDetail(); |
||||||
|
}, |
||||||
|
{ |
||||||
|
immediate: true, |
||||||
|
}, |
||||||
|
); |
||||||
|
// 提交 |
||||||
|
const submit = async (formEl: FormInstance | undefined) => { |
||||||
|
if (!formEl) return; |
||||||
|
await formEl.validate(async (valid, fields) => { |
||||||
|
if (valid) { |
||||||
|
try { |
||||||
|
const param = JSON.parse(JSON.stringify(form)); |
||||||
|
|
||||||
|
// 企业 |
||||||
|
if (param.productType) { |
||||||
|
if (!param.productObject) return ElMessage.error('请选择企业类型'); |
||||||
|
} |
||||||
|
if ((!param.productType && param.age) || param.productType) { |
||||||
|
if (!param.minimumAge) return ElMessage.error('请输入最小年龄'); |
||||||
|
if (!param.maximumAge) return ElMessage.error('请输入最大年龄'); |
||||||
|
if (param.minimumAge < 0 || param.minimumAge > 999 || param.maximumAge < 0 || param.maximumAge > 999) return ElMessage.error('请输入合理的年龄'); |
||||||
|
if (param.minimumAge > param.maximumAge) return ElMessage.error('最小年龄不得大于最大年龄'); |
||||||
|
} |
||||||
|
|
||||||
|
// 个人 |
||||||
|
if (!param.productType) { |
||||||
|
if (param.edu && !param.educationalRequirements.length) return ElMessage.error('请选择学历要求'); |
||||||
|
if (param.curWL && !param.currentWorkingLife.length) return ElMessage.error('请选择工作年限'); |
||||||
|
if (param.curWL && !param.currentWorkingLife.length) return ElMessage.error('请选择工作年限'); |
||||||
|
} |
||||||
|
|
||||||
|
param.currentWorkingLife = param.currentWorkingLife.join(); |
||||||
|
param.educationalRequirements = param.educationalRequirements.join(); |
||||||
|
param.modeRepayment = param.modeRepayment.join(); |
||||||
|
param.providentFundAndSocialSecurity = param.providentFundAndSocialSecurity ? 1 : ''; |
||||||
|
param.whetherToSupportEarlyRepayment = param.whetherToSupportEarlyRepayment ? 58 : ''; |
||||||
|
// 担保方式 |
||||||
|
param.addBankProductsGuarantyStyleReqList = []; |
||||||
|
param.bankGuaranteeTypeIds.forEach((e: number) => { |
||||||
|
param.addBankProductsGuarantyStyleReqList.push({ |
||||||
|
bankGuaranteeTypeId: (e > 22 && e < 33) || (e > 32 && e < 38) ? e : '', |
||||||
|
pid: e > 22 && e < 33 ? 110 : e > 32 && e < 38 ? 111 : e, |
||||||
|
}); |
||||||
|
}); |
||||||
|
if (id.value) { |
||||||
|
param.id = id.value; |
||||||
|
param.status = 295; |
||||||
|
await update(param); |
||||||
|
addRecord(param, id.value); |
||||||
|
} else { |
||||||
|
const { message } = await save(param); |
||||||
|
addRecord(param, message); |
||||||
|
} |
||||||
|
ElMessage.success('提交成功!'); |
||||||
|
emit('getList', 1); |
||||||
|
} finally { |
||||||
|
} |
||||||
|
} else { |
||||||
|
console.log('error submit!', fields); |
||||||
|
} |
||||||
|
}); |
||||||
|
}; |
||||||
|
// 新增判分记录 |
||||||
|
const addRecord = async (data: Record<string, any>, newId: number) => { |
||||||
|
const isEnterprise = data.productType === 1; |
||||||
|
const preIds = `1,2,41,${data.productType ? 45 : 44},${newId}`; // 1,关卡id,角色(这个页面是产品经理新增产品),个人/企业(44/45) |
||||||
|
const lcRule = <Record<string, any>[]>[ |
||||||
|
handleId(48, 1, data.productDefinition, preIds + ',48', 3), |
||||||
|
handleId(49, 2, data.productName, preIds + ',49', 3), |
||||||
|
handleId(50, 3, 1, preIds + ',50', 1), |
||||||
|
]; |
||||||
|
|
||||||
|
// 贷款用途 |
||||||
|
if (isEnterprise) { |
||||||
|
// 企业 |
||||||
|
lcRule.push( |
||||||
|
handleId(62, 7, data.productObject, preIds + ',61,62', 1), |
||||||
|
handleId(63, 8, '[' + data.minimumAge + ',' + data.maximumAge + ']' + '', preIds + ',61,63', 5), |
||||||
|
handleId(65, 19, data.loanPurpose, preIds + ',65', 1), |
||||||
|
); |
||||||
|
} else { |
||||||
|
// 个人 |
||||||
|
data.age && lcRule.push(handleId(100, 41, '[' + data.minimumAge + ',' + data.maximumAge + ']' + '', preIds + ',51,100', 5)); |
||||||
|
data.edu && lcRule.push(handleId(101, 42, data.educationalRequirements, preIds + ',51,101', 1)); |
||||||
|
data.curWL && lcRule.push(handleId(102, 43, data.currentWorkingLife, preIds + ',51,102', 1)); |
||||||
|
data.providentFundAndSocialSecurity && lcRule.push(handleId(103, '', '', preIds + ',51,103', '')); // 公积金社保 |
||||||
|
|
||||||
|
lcRule.push( |
||||||
|
data.loanPurpose === 107 ? handleId(107, 11, data.otherPurposesOfLoan, preIds + ',52,107', 3) : handleId(data.loanPurpose, '', '', preIds + ',52,' + data.loanPurpose, 1), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
// 担保方式 |
||||||
|
data.bankGuaranteeTypeIds.includes(108) && lcRule.push(handleId(108, '', '', preIds + ',53,108', '')); |
||||||
|
data.bankGuaranteeTypeIds.includes(109) && lcRule.push(handleId(109, '', '', preIds + ',53,109', '')); |
||||||
|
data.bankGuaranteeTypeIds.includes(110) && lcRule.push(handleId(110, 13, data.bankGuaranteeTypeIds.filter((e: number) => e > 22 && e < 33).join(), preIds + ',53,110', 1)); |
||||||
|
data.bankGuaranteeTypeIds.includes(111) && lcRule.push(handleId(111, 14, data.bankGuaranteeTypeIds.filter((e: number) => e > 32 && e < 38).join(), preIds + ',53,111', 1)); |
||||||
|
|
||||||
|
lcRule.push( |
||||||
|
handleId(54, 15, '[' + data.minimumLoan + ',' + data.loanCeiling + ']', preIds + ',54', 5), |
||||||
|
handleId(55, 16, '[' + data.minimumAprOnLoan + ',' + data.maximumAnnualInterestRate + ']', preIds + ',55', 5), |
||||||
|
handleId(56, 17, '[' + data.minimumTermOfLoan + ',' + data.maximumTermOfLoan + ']', preIds + ',56', 5), |
||||||
|
handleId(57, 18, data.modeRepayment, preIds + ',57', 1), |
||||||
|
); |
||||||
|
|
||||||
|
data.whetherToSupportEarlyRepayment && lcRule.push(handleId(58, '', '', preIds + ',58', '')); |
||||||
|
|
||||||
|
await addOperation({ |
||||||
|
parentId: preIds, |
||||||
|
lcJudgmentRuleReq: lcRule, |
||||||
|
projectId: 1, |
||||||
|
}); |
||||||
|
}; |
||||||
|
onMounted(() => { |
||||||
|
getConfig(); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
@import url(../../../styles/form.scss); |
||||||
|
.audit { |
||||||
|
@apply py-5 px-4 mb-[30px] bg-[#f9fafc] rounded-[10px]; |
||||||
|
.line { |
||||||
|
@apply mb-[18px] text-sm leading-[1.6]; |
||||||
|
} |
||||||
|
.field { |
||||||
|
@apply text-sm font-semibold; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,131 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-tabs v-model="curTab" |
||||||
|
@tab-click="tabChange"> |
||||||
|
<el-tab-pane label="产品审批" |
||||||
|
name="tab1"> |
||||||
|
<info /> |
||||||
|
<el-form ref="formRef" |
||||||
|
:model="form" |
||||||
|
:rules="rules" |
||||||
|
label-width="100px" |
||||||
|
label-suffix=":" |
||||||
|
class="form pt-5 mt-5 border-t border-t-solid border-t-[#EDF1F5]" |
||||||
|
status-icon> |
||||||
|
<el-form-item label="审批意见" |
||||||
|
prop="status"> |
||||||
|
<el-select v-model="form.status" |
||||||
|
placeholder="请选择"> |
||||||
|
<el-option v-for="(item, i) in config[0]?.subject?.itemList.slice(2)" |
||||||
|
:key="i" |
||||||
|
:label="item.options" |
||||||
|
:value="item.itemId" /> |
||||||
|
</el-select> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="意见描述" |
||||||
|
prop="opinionDescription"> |
||||||
|
<el-input type="textarea" |
||||||
|
placeholder="审批意见500字以内。" |
||||||
|
maxlength="500" |
||||||
|
v-model="form.opinionDescription"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<div class="flex justify-end"> |
||||||
|
<div class="submit" |
||||||
|
@click="submit(formRef)">审批</div> |
||||||
|
</div> |
||||||
|
</el-form> |
||||||
|
</el-tab-pane> |
||||||
|
</el-tabs> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { ref, computed, reactive, watch, onMounted } from 'vue'; |
||||||
|
import { ElMessage } from 'element-plus'; |
||||||
|
import type { TabsPaneContext, FormInstance, FormRules } from 'element-plus'; |
||||||
|
import { useRouter, useRoute } from 'vue-router'; |
||||||
|
import Info from './Info.vue'; |
||||||
|
import { findById, examineAndApprove } from '@/api/bank'; |
||||||
|
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment'; |
||||||
|
import dayjs from 'dayjs'; |
||||||
|
|
||||||
|
const emit = defineEmits(['getList']); |
||||||
|
interface RuleForm { |
||||||
|
id: any; |
||||||
|
status: any; |
||||||
|
opinionDescription?: string; |
||||||
|
} |
||||||
|
const router = useRouter(); |
||||||
|
const route = useRoute(); |
||||||
|
const curTab = ref<string>('tab1'); |
||||||
|
const info = ref<any>({}); |
||||||
|
const config = ref<any[]>([]); |
||||||
|
const formRef = ref<FormInstance>(); |
||||||
|
const form = reactive<RuleForm>({ |
||||||
|
id: computed(() => +route.query.id), |
||||||
|
status: '', |
||||||
|
opinionDescription: '', |
||||||
|
}); |
||||||
|
const rules = reactive<FormRules<RuleForm>>({ |
||||||
|
status: [{ required: true, message: '请选择审批意见', trigger: 'change' }], |
||||||
|
opinionDescription: [{ required: true, message: '请输入意见描述', trigger: 'blur' }], |
||||||
|
}); |
||||||
|
|
||||||
|
// tab切换回调 |
||||||
|
const tabChange = (tab: TabsPaneContext, event: Event) => { |
||||||
|
console.log(tab, event); |
||||||
|
}; |
||||||
|
// 配置项 |
||||||
|
const getConfig = async () => { |
||||||
|
const { process } = await getProcessInformationBasedOnRoles(43); // 专家委员会43 |
||||||
|
config.value = process; |
||||||
|
}; |
||||||
|
watch( |
||||||
|
() => route.query, |
||||||
|
() => { |
||||||
|
// getDetail(); |
||||||
|
}, |
||||||
|
{ |
||||||
|
immediate: true, |
||||||
|
}, |
||||||
|
); |
||||||
|
// 提交 |
||||||
|
const submit = async (formEl: FormInstance | undefined) => { |
||||||
|
if (!formEl) return; |
||||||
|
await formEl.validate(async (valid, fields) => { |
||||||
|
if (valid) { |
||||||
|
try { |
||||||
|
const param = JSON.parse(JSON.stringify(form)); |
||||||
|
param.approvalTime = dayjs(new Date()).format('YYYY年-M月-D日'); |
||||||
|
|
||||||
|
// const { message } = await examineAndApprove(param); |
||||||
|
const { message } = await examineAndApprove(param.id, param.opinionDescription, param.status, param.approvalTime); |
||||||
|
// addRecord(param, message); |
||||||
|
ElMessage.success('提交成功!'); |
||||||
|
emit('getList', 1); |
||||||
|
} finally { |
||||||
|
} |
||||||
|
} else { |
||||||
|
console.log('error submit!', fields); |
||||||
|
} |
||||||
|
}); |
||||||
|
}; |
||||||
|
// 新增判分记录 |
||||||
|
const addRecord = async (data: Record<string, any>, newId: number) => { |
||||||
|
const preIds = `1,2,43,${data.productType ? 45 : 44},${newId}`; // 1,关卡id,角色(这个页面是专家委员会审批),个人/企业(44/45) |
||||||
|
const lcRule = <Record<string, any>[]>[handleId(145, 69, data.status, preIds + ',145', 1), handleId(146, 70, data.opinionDescription, preIds + ',146', 3)]; |
||||||
|
|
||||||
|
await addOperation({ |
||||||
|
parentId: preIds, |
||||||
|
lcJudgmentRuleReq: lcRule, |
||||||
|
projectId: 1, |
||||||
|
}); |
||||||
|
}; |
||||||
|
onMounted(() => { |
||||||
|
getConfig(); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
@import url(../../../styles/form.scss); |
||||||
|
</style> |
@ -0,0 +1,133 @@ |
|||||||
|
<template> |
||||||
|
<div class="block" |
||||||
|
style="padding-top: 0"> |
||||||
|
<el-tabs v-model="curTab" |
||||||
|
@tab-click="tabChange"> |
||||||
|
<el-tab-pane label="准入策略" |
||||||
|
name="tab1"> |
||||||
|
<div class="flex"> |
||||||
|
<div class="left w-[241px] pr-5 py-4"> |
||||||
|
<ul class="products"> |
||||||
|
<li v-for="(item, i) in list[0]?.recordChildren" |
||||||
|
:key="i" |
||||||
|
:class="{ active: item.id === id }" |
||||||
|
@click="switchProduct(item.id)"> |
||||||
|
<h6>{{ item.name }}</h6> |
||||||
|
<!-- <p class="type">{{ item.productNumber + ' ' + item.guarantyStyle }}</p> --> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
<div class="right flex-1 px-5 pt-2"> |
||||||
|
<!-- <component :is="Config" |
||||||
|
v-model="form"></component> --> |
||||||
|
<config v-if="action === 'config'" |
||||||
|
@getList="getList"></config> |
||||||
|
<detail v-if="action === 'detail'"></detail> |
||||||
|
<add v-else-if="action === 'add'" |
||||||
|
@getList="getList"></add> |
||||||
|
<approve v-else-if="action === 'approve'" |
||||||
|
@getList="getList"></approve> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-tab-pane> |
||||||
|
<el-tab-pane label="信用评分策略" |
||||||
|
name="tab2"> </el-tab-pane> |
||||||
|
<el-tab-pane label="风险度策略" |
||||||
|
name="tab3"> </el-tab-pane> |
||||||
|
</el-tabs> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { computed, onMounted, ref, watch } from 'vue'; |
||||||
|
import { ElMessage } from 'element-plus'; |
||||||
|
import { Plus } from '@element-plus/icons-vue'; |
||||||
|
import type { TabsPaneContext } from 'element-plus'; |
||||||
|
import { bankingProductsList, batchDeletion } from '@/api/bank'; |
||||||
|
import { getProcessInformationBasedOnRoles } from '@/api/judgment'; |
||||||
|
import { useRouter, useRoute } from 'vue-router'; |
||||||
|
import { getStatus } from '@/store/useProduct'; |
||||||
|
import Config from './Config.vue'; |
||||||
|
import Detail from './Detail.vue'; |
||||||
|
import Add from './Add.vue'; |
||||||
|
import Approve from './Approve.vue'; |
||||||
|
|
||||||
|
const router = useRouter(); |
||||||
|
const route = useRoute(); |
||||||
|
const curTab = ref<string>('tab1'); |
||||||
|
const action = ref<any>(''); |
||||||
|
const list = ref<Array<any>>([]); |
||||||
|
const loading = ref<boolean>(false); |
||||||
|
const productType = computed(() => route.query.type); // 个人/企业 |
||||||
|
const role = computed(() => +route.query.role || 41); |
||||||
|
const id = computed(() => +route.query.id); |
||||||
|
// 列表 |
||||||
|
const getList = async () => { |
||||||
|
const { process } = await getProcessInformationBasedOnRoles(67); |
||||||
|
id.value || |
||||||
|
router.push({ |
||||||
|
path: `/product/strategy/config`, |
||||||
|
query: { |
||||||
|
...route.query, |
||||||
|
id: process[0].recordChildren[0].id, |
||||||
|
}, |
||||||
|
}); |
||||||
|
list.value = process; |
||||||
|
}; |
||||||
|
onMounted(() => { |
||||||
|
getList(); |
||||||
|
}); |
||||||
|
|
||||||
|
watch( |
||||||
|
route, |
||||||
|
(route: any) => { |
||||||
|
action.value = route.params.action; |
||||||
|
}, |
||||||
|
{ |
||||||
|
immediate: true, |
||||||
|
}, |
||||||
|
); |
||||||
|
// 产品切换 |
||||||
|
const switchProduct = (id: number) => { |
||||||
|
router.push({ |
||||||
|
path: `/product/strategy/config`, |
||||||
|
query: { |
||||||
|
...route.query, |
||||||
|
id, |
||||||
|
}, |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
// tab切换回调 |
||||||
|
const tabChange = (tab: TabsPaneContext, event: Event) => { |
||||||
|
console.log(tab, event); |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
.left { |
||||||
|
border-right: 1px solid #e9eff2; |
||||||
|
} |
||||||
|
.products { |
||||||
|
li { |
||||||
|
@apply relative p-5 mb-5 rounded-[10px] cursor-pointer border border-solid; |
||||||
|
background: url(../../assets/images/10.png) 0 0/100% 100% no-repeat; |
||||||
|
&.active { |
||||||
|
@apply border-[#CAE0FF]; |
||||||
|
} |
||||||
|
} |
||||||
|
.del { |
||||||
|
@apply absolute top-0 right-0; |
||||||
|
} |
||||||
|
h6 { |
||||||
|
@apply text-[#14436b]; |
||||||
|
} |
||||||
|
.type, |
||||||
|
.status { |
||||||
|
@apply my-[15px] text-sm text-[#333]; |
||||||
|
} |
||||||
|
.date { |
||||||
|
@apply text-sm text-[#8798a9]; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,348 @@ |
|||||||
|
<template> |
||||||
|
<el-table class="c-table" |
||||||
|
:data="form" |
||||||
|
:max-height="height" |
||||||
|
:span-method="span" |
||||||
|
border> |
||||||
|
<el-table-column prop="name" |
||||||
|
label="指标" |
||||||
|
min-width="150" |
||||||
|
align="center"> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="规则" |
||||||
|
min-width="250" |
||||||
|
align="center"> |
||||||
|
<template #default="{ row }"> |
||||||
|
<!-- 大病报销 || 贫困户 --> |
||||||
|
<div v-if="row.stRecordId == 161 || row.stRecordId == 164" |
||||||
|
class="flex items-center"> |
||||||
|
<span class="whitespace-nowrap">{{ row?.recordChildren[row.span ? 1 : 0]?.name }}</span> |
||||||
|
<div class="w-[90px] "> |
||||||
|
<el-select class="mx-2" |
||||||
|
v-model="row.symbol"> |
||||||
|
<el-option v-for="item in symbols" |
||||||
|
:key="item" |
||||||
|
:label="item.name" |
||||||
|
:value="item.name" /> |
||||||
|
</el-select> |
||||||
|
</div> |
||||||
|
<el-input class="w-[80px]" |
||||||
|
v-model="row.num"></el-input> |
||||||
|
<span class="ml-2 whitespace-nowrap">万元</span> |
||||||
|
</div> |
||||||
|
<!-- 大龄未婚 --> |
||||||
|
<div v-else-if="row.stRecordId == 167" |
||||||
|
class="flex items-center"> |
||||||
|
<template v-if="row.span"> |
||||||
|
<span class="whitespace-nowrap">且近一年</span> |
||||||
|
<div class="w-[90px] "> |
||||||
|
<el-select class="mx-2" |
||||||
|
v-model="row.had"> |
||||||
|
<el-option label="有" |
||||||
|
value="1" /> |
||||||
|
<el-option label="无" |
||||||
|
value="2" /> |
||||||
|
</el-select> |
||||||
|
</div> |
||||||
|
<span class="ml-2 whitespace-nowrap">缴纳过社保或公积金</span> |
||||||
|
</template> |
||||||
|
<template v-else> |
||||||
|
<span class="whitespace-nowrap">未婚,且年龄</span> |
||||||
|
<div class="w-[90px] "> |
||||||
|
<el-select class="mx-2" |
||||||
|
v-model="row.symbol"> |
||||||
|
<el-option v-for="item in symbols" |
||||||
|
:key="item" |
||||||
|
:label="item.name" |
||||||
|
:value="item.name" /> |
||||||
|
</el-select> |
||||||
|
</div> |
||||||
|
<el-input class="w-[80px]" |
||||||
|
v-model="row.num"></el-input> |
||||||
|
<span class="ml-2 whitespace-nowrap">,</span> |
||||||
|
<el-select class="w-[80px] ml-2" |
||||||
|
v-model="row.had"> |
||||||
|
<el-option label="有" |
||||||
|
value="1" /> |
||||||
|
<el-option label="无" |
||||||
|
value="2" /> |
||||||
|
</el-select> |
||||||
|
<span class="ml-2 whitespace-nowrap">固定资产</span> |
||||||
|
</template> |
||||||
|
</div> |
||||||
|
<span v-else>{{ '命中' + row.name }}</span> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="本人命中进黑名单" |
||||||
|
width="140" |
||||||
|
align="center"> |
||||||
|
<template #default="{ row }"> |
||||||
|
<el-checkbox v-model="row.personalHitBlacklist"></el-checkbox> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="配偶命中拒入" |
||||||
|
width="140" |
||||||
|
align="center"> |
||||||
|
<template #default="{ row }"> |
||||||
|
<el-checkbox v-model="row.mateHitRejected"></el-checkbox> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="父母/子女命中拒入" |
||||||
|
width="150" |
||||||
|
align="center"> |
||||||
|
<template #default="{ row }"> |
||||||
|
<el-checkbox v-model="row.parentsHitRejected"></el-checkbox> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="其它家庭成员命中拒入" |
||||||
|
width="170" |
||||||
|
align="center"> |
||||||
|
<template #default="{ row }"> |
||||||
|
<el-checkbox v-model="row.otherFamilyMembersHitRejected"></el-checkbox> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column label="企业大股东命中拒入" |
||||||
|
width="160" |
||||||
|
align="center"> |
||||||
|
<template #default="{ row }"> |
||||||
|
<el-checkbox v-model="row.corporateMajorityHitRejected"></el-checkbox> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
</el-table> |
||||||
|
|
||||||
|
<div class="flex justify-end"> |
||||||
|
<div class="submit" |
||||||
|
@click="submit">确认完成配置</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { ref, reactive, computed, watch, onMounted } from 'vue'; |
||||||
|
import { ElMessage } from 'element-plus'; |
||||||
|
import { accessStrategyGovernmentBlacklistFind, accessStrategyGovernmentBlacklist } from '@/api/bank'; |
||||||
|
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment'; |
||||||
|
import type { TableColumnCtx } from 'element-plus'; |
||||||
|
import { useRouter, useRoute } from 'vue-router'; |
||||||
|
import { handleId } from '@/utils/common'; |
||||||
|
|
||||||
|
const emit = defineEmits(['getList']); |
||||||
|
|
||||||
|
const router = useRouter(); |
||||||
|
const route = useRoute(); |
||||||
|
const id = computed(() => +route.query.id); |
||||||
|
const form = ref<Record<string, any>[]>([]); |
||||||
|
const height = window.innerHeight - 270; |
||||||
|
const symbols = <Record<string, any>[]>[ |
||||||
|
{ |
||||||
|
name: '>=', |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '<', |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '>', |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '==', |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '<=', |
||||||
|
}, |
||||||
|
]; |
||||||
|
// 配置项 |
||||||
|
const getConfig = async () => { |
||||||
|
const { process } = await getProcessInformationBasedOnRoles(150); |
||||||
|
const result = []; |
||||||
|
process.map((e) => { |
||||||
|
let temp = { |
||||||
|
checkpointId: 1, |
||||||
|
projectId: 1, |
||||||
|
name: e.name, |
||||||
|
recordChildren: e.recordChildren, |
||||||
|
isRule: isRule(e.id) ? 1 : 0, |
||||||
|
corporateMajorityHitRejected: false, |
||||||
|
mateHitRejected: false, |
||||||
|
otherFamilyMembersHitRejected: false, |
||||||
|
parentsHitRejected: false, |
||||||
|
personalHitBlacklist: false, |
||||||
|
symbol: '>=', |
||||||
|
had: '', |
||||||
|
num: '', |
||||||
|
ruleOne: '', |
||||||
|
ruleThree: '', |
||||||
|
ruleTwo: '', |
||||||
|
stRecordId: e.id, |
||||||
|
}; |
||||||
|
result.push(temp); |
||||||
|
if (isRule(e.id)) { |
||||||
|
temp = JSON.parse(JSON.stringify(temp)); |
||||||
|
temp.span = 1; |
||||||
|
result.push(temp); |
||||||
|
} |
||||||
|
}); |
||||||
|
form.value = result; |
||||||
|
console.log('🚀 ~ file: CardList.vue:68 ~ getList ~ list.value:', form.value); |
||||||
|
}; |
||||||
|
// 详情 |
||||||
|
const getDetail = async () => { |
||||||
|
if (id.value) { |
||||||
|
try { |
||||||
|
const { data } = await accessStrategyGovernmentBlacklistFind(1, 1); |
||||||
|
// info.value = data; |
||||||
|
getConfig(); |
||||||
|
} finally { |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
watch( |
||||||
|
() => route.query, |
||||||
|
() => { |
||||||
|
// getDetail(); |
||||||
|
getConfig(); |
||||||
|
}, |
||||||
|
{ |
||||||
|
immediate: true, |
||||||
|
}, |
||||||
|
); |
||||||
|
|
||||||
|
// 判断是否是3个有输入框的指标 |
||||||
|
const isRule = (rule: number): boolean => { |
||||||
|
return rule === 161 || rule === 164 || rule === 167; |
||||||
|
}; |
||||||
|
interface SpanMethodProps { |
||||||
|
row: Record<string, any>; |
||||||
|
column: TableColumnCtx<Record<string, any>>; |
||||||
|
rowIndex: number; |
||||||
|
columnIndex: number; |
||||||
|
} |
||||||
|
// 表格合并 |
||||||
|
const span = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => { |
||||||
|
if (columnIndex === 0 || columnIndex === 2 || columnIndex === 3 || columnIndex === 4 || columnIndex === 5 || columnIndex === 6) { |
||||||
|
if (rowIndex === 4 || rowIndex === 6 || rowIndex === 8) { |
||||||
|
return { |
||||||
|
rowspan: 2, |
||||||
|
colspan: 1, |
||||||
|
}; |
||||||
|
} else if (rowIndex === 5 || rowIndex === 7 || rowIndex === 9) { |
||||||
|
return { |
||||||
|
rowspan: 0, |
||||||
|
colspan: 0, |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
onMounted(() => {}); |
||||||
|
// 提交 |
||||||
|
const submit = async () => { |
||||||
|
const param = JSON.parse(JSON.stringify(form.value)); |
||||||
|
param.map((e) => { |
||||||
|
e.corporateMajorityHitRejected = +e.corporateMajorityHitRejected; |
||||||
|
e.mateHitRejected = +e.mateHitRejected; |
||||||
|
e.otherFamilyMembersHitRejected = +e.otherFamilyMembersHitRejected; |
||||||
|
e.parentsHitRejected = +e.parentsHitRejected; |
||||||
|
e.personalHitBlacklist = +e.personalHitBlacklist; |
||||||
|
if (e.stRecordId == 161 || e.stRecordId == 164) { |
||||||
|
if (e.span) { |
||||||
|
} else { |
||||||
|
e.ruleOne = e.symbol + e.num; |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
const { message } = await accessStrategyGovernmentBlacklist(param); |
||||||
|
// addRecord(param, message); |
||||||
|
|
||||||
|
ElMessage.success('提交成功!'); |
||||||
|
emit('getList', 1); |
||||||
|
}; |
||||||
|
// 新增判分记录 |
||||||
|
const addRecord = async (data: Record<string, any>, newId: number) => { |
||||||
|
const isEnterprise = info.value.productType === 1; |
||||||
|
const preIds = `1,2,42,${newId}`; // 1,关卡id,角色(这个页面是风控经理策略) |
||||||
|
const lcRule = <Record<string, any>[]>[]; |
||||||
|
|
||||||
|
// 企业 |
||||||
|
if (isEnterprise) { |
||||||
|
lcRule.push( |
||||||
|
handleId(120, 44, data.accountMaterials, preIds + ',112,120', 1), |
||||||
|
handleId(121, 45, 162, preIds + ',112,121', 1), |
||||||
|
handleId(122, 46, data.loanApplicationMethod, preIds + ',113,122', 1), |
||||||
|
handleId(123, 47, data.borrowerMaterial, preIds + ',113,123', 1), |
||||||
|
handleId(124, 48, data.collateral, preIds + ',113,124', 1), |
||||||
|
handleId(125, 49, data.businessMaterials, preIds + ',113,125', 1), |
||||||
|
handleId(126, 50, data.supplementaryMaterials, preIds + ',113,126', 1), |
||||||
|
|
||||||
|
handleId(127, 51, data.runBatchObject, preIds + ',114,127', 1), |
||||||
|
handleId(128, 52, data.accessStrategy, preIds + ',114,128', 1), |
||||||
|
); |
||||||
|
data.personalCreditScoringStrategiesCheck && lcRule.push(handleId(129, 53, '240,' + data.personalCreditScoringStrategies, preIds + ',114,129', 1)); |
||||||
|
data.corporateCreditScoringStrategiesCheck && lcRule.push(handleId(129, 53, '241,' + data.corporateCreditScoringStrategies, preIds + ',114,129', 1)); |
||||||
|
|
||||||
|
lcRule.push(handleId(130, 54, data.riskDegreeStrategy, preIds + ',114,130', 1)); |
||||||
|
data.interestRatePricingModelCheck && lcRule.push(handleId(131, 55, '247,' + data.interestRatePricingModel, preIds + ',114,131', 1)); |
||||||
|
data.individualInterestRateModel && lcRule.push(handleId(131, 55, data.individualInterestRateModel, preIds + ',114,131', 1)); |
||||||
|
|
||||||
|
lcRule.push( |
||||||
|
handleId(132, 56, data.dueDiligenceMode, preIds + ',115,132', 1), |
||||||
|
handleId(133, 57, data.dueDiligenceContent, preIds + ',115,133', 1), |
||||||
|
handleId(134, 58, data.reviewContent, preIds + ',116,134', 1), |
||||||
|
handleId(135, 59, data.reviewSignature, preIds + ',116,135', 1), |
||||||
|
handleId(136, 60, data.reviewApproveContent, preIds + ',117,136', 1), |
||||||
|
handleId(137, 61, data.approvalSignature, preIds + ',117,137', 1), |
||||||
|
handleId(138, 62, data.contractMaterials, preIds + ',118,138', 1), |
||||||
|
); |
||||||
|
data.loanContract && lcRule.push(handleId(139, 63, data.loanContract, preIds + ',118,139', 1)); |
||||||
|
data.mortgageContract && lcRule.push(handleId(139, 63, data.mortgageContract, preIds + ',118,139', 1)); |
||||||
|
data.pledgeContract && lcRule.push(handleId(139, 63, data.pledgeContract, preIds + ',118,139', 1)); |
||||||
|
data.guaranteeContract && lcRule.push(handleId(139, 63, data.guaranteeContract, preIds + ',118,139', 1)); |
||||||
|
lcRule.push(handleId(140, 64, data.selectionStrategy, preIds + ',119,140', 1)); |
||||||
|
} else { |
||||||
|
lcRule.push( |
||||||
|
handleId(75, 20, data.accountMaterials, preIds + ',72,75', 1), |
||||||
|
handleId(76, 21, 46, preIds + ',72,76', 1), |
||||||
|
handleId(77, 22, data.loanApplicationMethod, preIds + ',73,77', 1), |
||||||
|
handleId(78, 23, data.borrowerMaterial, preIds + ',73,78', 1), |
||||||
|
handleId(79, 24, data.mateMaterial, preIds + ',73,79', 1), |
||||||
|
handleId(80, 25, data.businessMaterials, preIds + ',73,80', 1), |
||||||
|
handleId(81, 26, data.supplementaryMaterials, preIds + ',73,81', 1), |
||||||
|
handleId(82, 27, data.runBatchObject, preIds + ',74,82', 1), |
||||||
|
handleId(83, 28, data.accessStrategy, preIds + ',74,83', 1), |
||||||
|
); |
||||||
|
data.personalCreditScoringStrategiesCheck && lcRule.push(handleId(84, 29, '94,' + data.personalCreditScoringStrategies, preIds + ',74,84', 1)); |
||||||
|
data.corporateCreditScoringStrategiesCheck && lcRule.push(handleId(84, 29, '95,' + data.corporateCreditScoringStrategies, preIds + ',74,84', 1)); |
||||||
|
|
||||||
|
lcRule.push(handleId(85, 30, data.riskDegreeStrategy, preIds + ',74,85', 1)); |
||||||
|
data.interestRatePricingModelCheck && lcRule.push(handleId(86, 31, '102,' + data.interestRatePricingModel, preIds + ',74,86', 1)); |
||||||
|
data.individualInterestRateModel && lcRule.push(handleId(86, 31, data.individualInterestRateModel, preIds + ',74,86', 1)); |
||||||
|
|
||||||
|
lcRule.push( |
||||||
|
handleId(88, 32, data.dueDiligenceMode, preIds + ',87,88', 1), |
||||||
|
handleId(89, 33, data.dueDiligenceContent, preIds + ',87,89', 1), |
||||||
|
handleId(91, 34, data.reviewContent, preIds + ',90,91', 1), |
||||||
|
handleId(92, 35, data.reviewSignature, preIds + ',90,92', 1), |
||||||
|
handleId(94, 36, data.reviewApproveContent, preIds + ',93,94', 1), |
||||||
|
handleId(95, 37, data.approvalSignature, preIds + ',93,95', 1), |
||||||
|
handleId(97, 38, data.contractMaterials, preIds + ',96,97', 1), |
||||||
|
); |
||||||
|
data.loanContract && lcRule.push(handleId(98, 39, data.loanContract, preIds + ',96,98', 1)); |
||||||
|
data.mortgageContract && lcRule.push(handleId(98, 39, data.mortgageContract, preIds + ',96,98', 1)); |
||||||
|
data.pledgeContract && lcRule.push(handleId(98, 39, data.pledgeContract, preIds + ',96,98', 1)); |
||||||
|
data.guaranteeContract && lcRule.push(handleId(98, 39, data.guaranteeContract, preIds + ',96,98', 1)); |
||||||
|
lcRule.push(handleId(99, 40, data.selectionStrategy, preIds + ',99', 1)); |
||||||
|
} |
||||||
|
|
||||||
|
await addOperation({ |
||||||
|
parentId: preIds, |
||||||
|
lcJudgmentRuleReq: lcRule, |
||||||
|
projectId: 1, |
||||||
|
}); |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
@import url(../../../styles/form.scss); |
||||||
|
.c-table { |
||||||
|
:deep(.el-input__inner) { |
||||||
|
@apply px-2; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,21 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-tabs v-model="curTab"> |
||||||
|
<el-tab-pane label="产品要素" |
||||||
|
name="tab1"> |
||||||
|
<info /> |
||||||
|
</el-tab-pane> |
||||||
|
</el-tabs> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { ref } from 'vue'; |
||||||
|
import Info from './Info.vue'; |
||||||
|
|
||||||
|
const curTab = ref<string>('tab1'); |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
@import url(../../../styles/form.scss); |
||||||
|
</style> |
@ -0,0 +1,181 @@ |
|||||||
|
<template> |
||||||
|
<div v-if="info.approvalTime" |
||||||
|
class="audit"> |
||||||
|
<div class="line"> |
||||||
|
<span class="field">审批意见:</span> |
||||||
|
<span class="status">{{ getStatus(+info?.status) }}</span> |
||||||
|
</div> |
||||||
|
<div class="line"> |
||||||
|
<span class="field">意见描述:</span> |
||||||
|
{{ info.opinionDescription }} |
||||||
|
</div> |
||||||
|
<p class="mb-2 text-sm text-[#333] text-right">审查日期:{{ info.approvalTime }}</p> |
||||||
|
<p class="mb-2 text-sm text-[#333] text-right">审查员:公瑾</p> |
||||||
|
</div> |
||||||
|
<div class="info mt-2"> |
||||||
|
<h6 class="step-name">一、产品定义</h6> |
||||||
|
<p class="text">{{ info.productDefinition }}</p> |
||||||
|
<h6 class="step-name mt-5">二、产品要素</h6> |
||||||
|
<p class="text">产品名称:{{ info.productName }}</p> |
||||||
|
<p class="text">贷款币种:人民币</p> |
||||||
|
<p v-if="info.loanPurpose" |
||||||
|
class="text"> |
||||||
|
贷款用途:{{ |
||||||
|
info.loanPurpose === '购房' |
||||||
|
? '可用于住房按揭贷款、二手房住房按揭贷款。' |
||||||
|
: info.loanPurpose === '消费' |
||||||
|
? '贷款用途可用于除购房之外的合法个人消费支出,不得用于投资经营,不得用于无指定用途的个人支出。' |
||||||
|
: info.loanPurpose === '经营' && !info.productType |
||||||
|
? '可用于个人或其企业生产和经营活动中临时性、季节性等流动资金周转以及购置、安装或修理小型设备和装潢经营性场所所需的人民币贷款业务。' |
||||||
|
: info.loanPurpose === '创业' |
||||||
|
? '用于创业或再创业过程中的资金需求。' |
||||||
|
: info.loanPurpose === '经营' && info.productType |
||||||
|
? '用于短期生产经营周转的可循环的人民币信用贷款业务。' |
||||||
|
: info.otherPurposesOfLoan |
||||||
|
}} |
||||||
|
</p> |
||||||
|
<p class="text">担保方式:{{ info.guarantyStyle }}</p> |
||||||
|
<p class="text">贷款期限:{{ info.minimumTermOfLoan }}月 - {{ info.maximumTermOfLoan }}月</p> |
||||||
|
<p class="text">贷款限额:{{ info.minimumLoan }}万元 - {{ info.loanCeiling }}万元</p> |
||||||
|
<p class="text">贷款利率:{{ info.minimumAprOnLoan }}% - {{ info.maximumAnnualInterestRate }}%</p> |
||||||
|
<p class="text">还款方式:{{ info.modeRepayment }}</p> |
||||||
|
<div class="text"> |
||||||
|
贷款对象: |
||||||
|
<p v-if="info.minimumAge">年龄{{ info.minimumAge }} - {{ info.maximumAge }}周岁;</p> |
||||||
|
<p v-if="info.educationalRequirements">取得{{ info.educationalRequirements }}以上学历;</p> |
||||||
|
<p v-if="info.currentWorkingLife">{{ info.currentWorkingLife }};</p> |
||||||
|
<p v-if="info.providentFundAndSocialSecurity">连续缴纳本市社保或者公积金6个月;</p> |
||||||
|
<p>持有中国银行I类账户,且已关联至手机银行,且在我行及其他金融同业无不良信用记录。</p> |
||||||
|
</div> |
||||||
|
<template v-if="riskInfo"> |
||||||
|
<h6 class="step-name mt-5">三、材料要求</h6> |
||||||
|
<p class="text">办理账户-提供材料:{{ riskInfo?.accountMaterials }}</p> |
||||||
|
<p v-if="riskInfo?.sendingAccount" |
||||||
|
class="text">办理账户-发放账户:借记卡或放款专户</p> |
||||||
|
<p v-if="riskInfo?.loanApplicationMethod" |
||||||
|
class="text">贷款申请-申请方式:{{ riskInfo?.loanApplicationMethod }}</p> |
||||||
|
<p v-if="riskInfo?.borrowerMaterial" |
||||||
|
class="text">贷款申请-提供材料-借款人材料:{{ riskInfo?.borrowerMaterial }}</p> |
||||||
|
<template v-if="info.productType"> |
||||||
|
<p v-if="riskInfo?.enterpriseMaterial" |
||||||
|
class="text">贷款申请-提供材料-企业材料:{{ riskInfo?.enterpriseMaterial }}</p> |
||||||
|
<p v-if="riskInfo?.collateral" |
||||||
|
class="text">贷款申请-提供材料-抵押物:{{ riskInfo?.collateral }}</p> |
||||||
|
</template> |
||||||
|
<template v-else> |
||||||
|
<p v-if="riskInfo?.mateMaterial" |
||||||
|
class="text">贷款申请-提供材料-配偶材料:{{ riskInfo?.mateMaterial }}</p> |
||||||
|
<p v-if="riskInfo?.businessMaterials" |
||||||
|
class="text">贷款申请-提供材料-经营类材料:{{ riskInfo?.businessMaterials }}</p> |
||||||
|
</template> |
||||||
|
<p v-if="riskInfo?.supplementaryMaterials" |
||||||
|
class="text">贷款申请-提供材料-补充材料:{{ riskInfo?.supplementaryMaterials }}</p> |
||||||
|
<p v-if="riskInfo?.runBatchObject" |
||||||
|
class="text">系统跑批准入风控策略-跑批对象:{{ riskInfo?.runBatchObject }}</p> |
||||||
|
<p v-if="riskInfo?.accessStrategy" |
||||||
|
class="text">系统跑批准入风控策略-准入策略:{{ riskInfo?.accessStrategy }}</p> |
||||||
|
<p v-if="riskInfo?.personalCreditScoringStrategies" |
||||||
|
class="text">系统跑批准入风控策略-信用评分策略:{{ riskInfo?.personalCreditScoringStrategies }}</p> |
||||||
|
<p v-if="riskInfo?.riskDegreeStrategy" |
||||||
|
class="text">系统跑批准入风控策略-风险度策略:{{ riskInfo?.riskDegreeStrategy }}</p> |
||||||
|
<p v-if="riskInfo?.interestRatePricingModel" |
||||||
|
class="text">系统跑批准入风控策略-利率定价模型-个人额度模型:{{ riskInfo?.interestRatePricingModel }}</p> |
||||||
|
<p v-if="riskInfo?.individualInterestRateModel" |
||||||
|
class="text">系统跑批准入风控策略-利率定价模型-个人利率模型</p> |
||||||
|
<p v-if="riskInfo?.dueDiligenceMode" |
||||||
|
class="text">尽职调查-尽调方式:{{ riskInfo?.dueDiligenceMode }}</p> |
||||||
|
<p v-if="riskInfo?.dueDiligenceContent" |
||||||
|
class="text">尽职调查-尽调内容:{{ riskInfo?.dueDiligenceContent }}</p> |
||||||
|
<p v-if="riskInfo?.reviewContent" |
||||||
|
class="text">贷款审查-审查内容:{{ riskInfo?.reviewContent }}</p> |
||||||
|
<p v-if="riskInfo?.reviewSignature" |
||||||
|
class="text">贷款审查-审查签字:{{ riskInfo?.reviewSignature }}</p> |
||||||
|
<p v-if="riskInfo?.reviewApproveContent" |
||||||
|
class="text">贷款审批-审批内容:{{ riskInfo?.reviewApproveContent }}</p> |
||||||
|
<p v-if="riskInfo?.approvalSignature" |
||||||
|
class="text">贷款审批-审批签字:{{ riskInfo?.approvalSignature }}</p> |
||||||
|
<p v-if="riskInfo?.contractMaterials" |
||||||
|
class="text">签订合同-提供的材料:{{ riskInfo?.contractMaterials }}</p> |
||||||
|
<p v-if="riskInfo?.loanContract" |
||||||
|
class="text">签订合同-合同模板-借贷合同:{{ riskInfo?.loanContract }}</p> |
||||||
|
<p v-if="riskInfo?.mortgageContract" |
||||||
|
class="text">签订合同-合同模板-抵押合同:{{ riskInfo?.mortgageContract }}</p> |
||||||
|
<p v-if="riskInfo?.pledgeContract" |
||||||
|
class="text">签订合同-合同模板-质押合同:{{ riskInfo?.pledgeContract }}</p> |
||||||
|
<p v-if="riskInfo?.guaranteeContract" |
||||||
|
class="text">签订合同-合同模板-担保合同:{{ riskInfo?.guaranteeContract }}</p> |
||||||
|
<p v-if="riskInfo?.selectionStrategy" |
||||||
|
class="text">贷后管理-选择策略:{{ riskInfo?.selectionStrategy }}</p> |
||||||
|
|
||||||
|
<h6 class="step-name mt-5">四、业务流程</h6> |
||||||
|
<p class="text">1、贷款人APP向智信银行公司业务部门提交借款申请,同时提交贷款用途证明文件以及有关资料;</p> |
||||||
|
<p class="text">2、智信银行对贷款人的贷款申请进行审查,同时根据实际情况要求借款人提供补充资料;</p> |
||||||
|
<p class="text">3、智信银行内部审批通过后,与贷款人签订借款合同;</p> |
||||||
|
<p class="text">4、贷款人落实有关提款前提条件,根据贷款合同提款。</p> |
||||||
|
<h6 class="step-name mt-5">五、注意要点</h6> |
||||||
|
<p class="text"> |
||||||
|
贷款人在使用款额度时,必须明确说明贷款用途。贷款人必须在获得循环贷款额度后,方可在额度与用途范围内申请贷款,受理机构仅限在原经办行,同时逐笔上报中心核批。单笔贷款金额不得超过贷款人单笔消费(或投资)总金额的80%。 |
||||||
|
</p> |
||||||
|
</template> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { ref, computed, watch, onMounted } from 'vue'; |
||||||
|
import { findById } from '@/api/bank'; |
||||||
|
import { useRouter, useRoute } from 'vue-router'; |
||||||
|
import { getStatus } from '@/store/useProduct'; |
||||||
|
|
||||||
|
const router = useRouter(); |
||||||
|
const route = useRoute(); |
||||||
|
const id = computed(() => +route.query.id); |
||||||
|
const info = ref<Record<string, any>>({}); |
||||||
|
const riskInfo = ref<Record<string, any>>(null); |
||||||
|
|
||||||
|
// 详情 |
||||||
|
const getDetail = async () => { |
||||||
|
if (id.value) { |
||||||
|
try { |
||||||
|
const { data } = await findById(id.value); |
||||||
|
info.value = data; |
||||||
|
if (info.value.riskControlDetails) riskInfo.value = data.riskControlDetails; |
||||||
|
} finally { |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
watch( |
||||||
|
() => route.query, |
||||||
|
() => { |
||||||
|
getDetail(); |
||||||
|
}, |
||||||
|
{ |
||||||
|
immediate: true, |
||||||
|
}, |
||||||
|
); |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
.info { |
||||||
|
.step-name { |
||||||
|
@apply mb-3 text-sm font-semibold text-[#006bff]; |
||||||
|
} |
||||||
|
.line { |
||||||
|
@apply flex mb-2; |
||||||
|
} |
||||||
|
.label { |
||||||
|
@apply mr-1 text-sm font-semibold text-[#333] leading-[32px]; |
||||||
|
} |
||||||
|
.text { |
||||||
|
@apply text-sm text-[#333] leading-[32px]; |
||||||
|
} |
||||||
|
} |
||||||
|
.audit { |
||||||
|
@apply py-5 px-4 mb-[30px] bg-[#f9fafc] rounded-[10px]; |
||||||
|
.line { |
||||||
|
@apply mb-[18px] text-sm leading-[1.6]; |
||||||
|
} |
||||||
|
.field { |
||||||
|
@apply text-sm font-semibold; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
Loading…
Reference in new issue