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