风控、专家委员会相关

V0.1
yujialong 1 year ago
parent 3034fabaa7
commit a9c89fcdd1
  1. 4
      src/api/bank.ts
  2. BIN
      src/assets/images/icon7-1.png
  3. 5
      src/layout/components/AppHeader.vue
  4. 16
      src/layout/components/AppSidebar/Menu.vue
  5. 20
      src/store/useProduct.ts
  6. 116
      src/styles/form.scss
  7. 45
      src/views/product/Add.vue
  8. 131
      src/views/product/Approve.vue
  9. 17
      src/views/product/CardList.vue
  10. 123
      src/views/product/Config.vue
  11. 59
      src/views/product/Detail.vue
  12. 130
      src/views/product/Info.vue
  13. 88
      src/views/product/List.vue

@ -13,3 +13,7 @@ export const productElement = async (id: number): Promise<any> => (await axios.p
export const findById = async (id: number): Promise<any> => (await axios.post(`/product/product/bank/products/findById?id=${id}`)).data;
export const save = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/product/bank/products/save`, data)).data;
export const riskSave = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/managerOfRiskControl/bankRiskControlAllocation/save`, data)).data;
export const riskUpdate = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/managerOfRiskControl/bankRiskControlAllocation/update`, data)).data;
export const riskById = async (id: number): Promise<any> => (await axios.post(`/product/managerOfRiskControl/bankRiskControlAllocation/findById?id=${id}`)).data;
export const examineAndApprove = async (id: number | string, opinionDescription: string, status: number, approvalTime: string): Promise<any> =>
(await axios.post(`/product/product/bank/products/examineAndApprove?id=${id}&opinionDescription=${opinionDescription}&status=${status}&approvalTime=${approvalTime}`)).data;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -2,8 +2,9 @@
<div class="flex justify-between items-center w-full py-6 px-5 overflow-hidden bg-transparent">
<logo :collapse="collapse" />
<div>
<el-button @click="switchRole(1)">切换产品经理</el-button>
<el-button @click="switchRole(2)">切换风控经理</el-button>
<el-button @click="switchRole(41)">切换产品经理</el-button>
<el-button @click="switchRole(42)">切换风控经理</el-button>
<el-button @click="switchRole(43)">切换专家委员会</el-button>
</div>
<div class="inline-flex items-center">
<img class="mr-3 cursor-pointer"

@ -1,6 +1,6 @@
<template>
<ul class="switch px-7 mt-5">
<template v-if="isProduct">
<template v-if="role == 41">
<li :class="{ active: active == 1 }"
@click="toPage('/product?type=0&i=1')">
<img class="icon"
@ -22,7 +22,7 @@
<p class="text">企业产品</p>
</li>
</template>
<template v-else>
<template v-else-if="role == 42">
<li :class="{ active: active == 1 }">
<img class="icon"
src="@/assets/images/icon1.png"
@ -60,6 +60,16 @@
<p class="text">贷后管理模型</p>
</li>
</template>
<li v-else
class="active">
<img class="icon"
src="@/assets/images/icon6.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon7-1.png"
alt="" />
<p class="text">审批产品</p>
</li>
</ul>
</template>
@ -71,7 +81,7 @@ import { isShowMenu } from '@/store/useCurrentUser';
const router = useRouter();
const route = useRoute();
const active = computed(() => route.query.i);
const isProduct = computed(() => route.query.role == 1 || !route.query.role);
const role = computed(() => route.query.role || 41);
//
const toPage = (path: string) => {

@ -13,28 +13,36 @@ const state = reactive<Product>({
name: '产品进度',
},
{
id: 1,
id: 295,
name: '配置风控',
},
{
id: 2,
id: 296,
name: '待审批',
},
{
id: 3,
id: 297,
name: '审批通过',
},
{
id: 4,
id: 298,
name: '审批不通过',
},
{
id: 5,
id: 299,
name: '审批打回',
},
],
});
export const productState = readonly(state);
// 专家委员会产品进度(去除配置风控)
export const getExpertStatus = (): Record<string, any>[] => {
const newStatus = JSON.parse(JSON.stringify(state.status));
newStatus.splice(1, 1);
return newStatus;
};
// 返回产品进度名称
export const getStatus = (id: number | string): string => {
return state.status.find((e) => e.id === id).name;
return state.status.find((e) => e.id === id)?.name;
};

@ -1,19 +1,10 @@
.forms {
&.step-form {
.step-name {
padding-top: 5px;
}
}
.form {
@apply max-h-[calc(100vh-270px)] overflow-auto;
.step {
position: relative;
padding-left: 42px;
@apply relative pl-[42px];
&:before {
@apply absolute top-0 left-0 w-[30px] h-[30px];
content: '';
position: absolute;
top: 0;
left: 0;
width: 30px;
height: 30px;
background: url(../assets/images/config1.png) no-repeat;
}
&:nth-child(2):before {
@ -33,88 +24,39 @@
}
&:after {
content: '';
position: absolute;
top: 40px;
left: 14px;
width: 2px;
height: 87%;
background: #006bff;
@apply absolute top-[40px] left-[14px] w-[2px] h-[87%] bg-[#006bff];
}
}
.step-name {
font-size: 14px;
font-weight: 600;
color: #006bff;
}
.line {
display: flex;
margin-bottom: 30px;
.label {
margin-right: 5px;
font-size: 14px;
font-weight: 600;
line-height: 32px;
}
.field-name {
font-size: 14px;
font-weight: 600;
line-height: 32px;
color: #333;
}
.tips {
font-size: 14px;
color: #686868;
}
.fields {
flex: 1;
}
.num-inputs {
display: flex;
align-items: center;
.el-input {
width: 200px;
}
.split {
margin: 0 10px;
color: #ccc;
}
.unit {
margin-left: 10px;
font-size: 14px;
color: #333;
}
}
}
.text {
font-size: 14px;
color: #333;
line-height: 32px;
@apply pl-[5px] text-sm font-semibold text-[#006bff];
}
.submit {
padding: 15px 22px;
font-size: 14px;
line-height: 1;
color: #fff;
background: #006bff;
border-radius: 12px;
cursor: pointer;
&:hover {
opacity: 0.9;
}
:deep(.el-form-item__label) {
@apply font-semibold text-sm leading-[32px] text-black;
}
}
.info {
.step-name {
@apply mb-3 text-sm font-semibold text-[#006bff];
.field-name {
@apply mb-3 text-sm font-semibold leading-[32px] text-[#333];
}
.line {
@apply flex mb-2;
.tips {
@apply text-sm text-[#686868];
}
.label {
@apply mr-1 text-sm font-semibold text-[#333] leading-[32px];
.num-inputs {
@apply flex items-center;
.el-input {
@apply w-[200px];
}
.split {
@apply mx-2.5 text-white;
}
.unit {
@apply ml-2.5 text-sm text-[#333];
}
}
.text {
@apply text-sm text-[#333] leading-[32px];
}
.submit {
@apply py-[15px] px-[22px] mt-5 text-sm leading-none text-white bg-[#006bff] rounded-xl cursor-pointer;
&:hover {
@apply opacity-90;
}
}

@ -63,11 +63,11 @@
<template v-else>
<p class="field-name">选择本产品的贷款对象</p>
<div class="flex items-center mb-2">
<el-checkbox-group class="mt-1"
v-model="form.age">
<el-checkbox label="年龄" />
</el-checkbox-group>
<div class="num-inputs ml-7">
<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>
@ -239,6 +239,7 @@ interface RuleForm {
maximumAge: any;
maximumAnnualInterestRate: any;
maximumTermOfLoan: any;
age: boolean;
minimumAge: any;
minimumAprOnLoan: any;
minimumLoan: any;
@ -269,6 +270,7 @@ const form = reactive<RuleForm>({
maximumAge: '',
maximumAnnualInterestRate: '',
maximumTermOfLoan: '',
age: false,
minimumAge: '',
minimumAprOnLoan: '',
minimumLoan: '',
@ -311,7 +313,7 @@ const submit = async (formEl: FormInstance | undefined) => {
param.currentWorkingLife = param.currentWorkingLife.join();
param.educationalRequirements = param.educationalRequirements.join();
param.modeRepayment = param.modeRepayment.join();
param.providentFundAndSocialSecurity = param.providentFundAndSocialSecurity ? 13 : '';
param.providentFundAndSocialSecurity = param.providentFundAndSocialSecurity ? 1 : '';
param.whetherToSupportEarlyRepayment = param.whetherToSupportEarlyRepayment ? 58 : '';
//
param.addBankProductsGuarantyStyleReqList = [];
@ -389,34 +391,5 @@ onMounted(() => {
</script>
<style lang="scss" scoped>
.form {
:deep(.el-form-item__label) {
@apply font-semibold text-sm text-black;
}
.field-name {
@apply mb-3 text-sm font-semibold text-[#333];
}
.tips {
@apply text-sm text-[#686868];
}
.num-inputs {
@apply flex items-center;
.el-input {
@apply w-[200px];
}
.split {
@apply mx-2.5 text-white;
}
.unit {
@apply ml-2.5 text-sm text-[#333];
}
}
.submit {
@apply py-[15px] px-[22px] text-sm leading-none text-white bg-[#006bff] rounded-xl cursor-pointer;
&:hover {
@apply opacity-90;
}
}
}
@import url(../../styles/form.scss);
</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年-MM月-DD日');
// 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}`; // 1id/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>

@ -41,13 +41,12 @@
<!-- <component :is="Config"
v-model="form"></component> -->
<config v-if="action === 'config'"
@getList="getList"
v-model="form"></config>
<detail v-if="action === 'detail'"
v-model="form"></detail>
@getList="getList"></config>
<detail v-if="action === 'detail'"></detail>
<add v-else-if="action === 'add'"
@getList="getList"
v-model="form"></add>
@getList="getList"></add>
<approve v-else-if="action === 'approve'"
@getList="getList"></approve>
</div>
</div>
</template>
@ -63,16 +62,14 @@ 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 action = ref<any>('');
const list = ref<Array<any>>([]);
const form = ref<any>({
cl: '',
});
const loading = ref<boolean>(false);
const productType = computed(() => +route.query.type); // /
const productType = computed(() => route.query.type); // /
const id = computed(() => +route.query.id);
//
const getList = async (first: any) => {

@ -4,20 +4,6 @@
@tab-click="tabChange">
<el-tab-pane label="配置风控"
name="tab1">
<!-- <div class="audit">
<div class="line">
<span class="field">审批意见</span>
<span class="status">待审批</span>
</div>
<div class="line">
<span class="field">意见描述</span>
习近平总书记在二十届中央政治局第六次集体学习时强调党的二十大报告在总结历史经验基础上提出并阐述了
个结合六个必须坚持等推进理论创新的科学方法为继续推进党的理论创新提供了根本遵循这一重要论述两个结合
六个必须坚持一同列为推进理论创新的科学方法深刻阐明了两个结合作为认识世界
</div>
<p class="mb-2 text-sm text-[#333] text-right">审查日期2022-02-02</p>
<p class="mb-2 text-sm text-[#333] text-right">审查员公瑾</p>
</div> -->
<el-form ref="formRef"
:model="form"
@ -190,7 +176,7 @@
<div class="flex-1">
<div class="flex items-center mb-3">
<el-checkbox v-model="form.interestRatePricingModelCheck"
label="个人额度模型" />
:label="(detail.productType ? '企业' : '个人') + '额度模型'" />
<el-select v-show="form.interestRatePricingModelCheck"
class="ml-5"
v-model="form.interestRatePricingModel"
@ -202,7 +188,7 @@
</el-select>
</div>
<el-checkbox v-model="form.individualInterestRateModel"
:label="103">个人利率模型</el-checkbox>
:label="103">{{ detail.productType ? '企业' : '个人' }}利率模型</el-checkbox>
</div>
</el-form-item>
</div>
@ -337,15 +323,7 @@
</el-tab-pane>
<el-tab-pane label="产品要素"
name="tab2">
<div class="info mt-2">
<h6 class="step-name mb-4">办理账户</h6>
<p class="text">根据个人客户的信用状况为其提供的一种短期融资便利产品借款人在我行核定的额度金额内可循环周转使用贷款</p>
<h6 class="step-name mt-5">产品要素</h6>
<div class="line">
<label class="label">产品名称</label>
<p class="text">根据个人客户的信用状况为其提供的一种短期融资便利产品借款人在我行核定的额度金额内可循环周转使用贷款</p>
</div>
</div>
<info />
</el-tab-pane>
</el-tabs>
</div>
@ -359,6 +337,7 @@ import { findById, riskSave } from '@/api/bank';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import { useRouter, useRoute } from 'vue-router';
import { handleId } from '@/utils/common';
import Info from './Info.vue';
const emit = defineEmits(['getList']);
interface RuleForm {
@ -644,97 +623,5 @@ const addRecord = async (data: Record<string, any>, newId: number) => {
</script>
<style lang="scss" scoped>
// @import url(../../styles/form.scss);
.audit {
padding: 20px 16px;
margin-bottom: 30px;
background: #f9fafc;
border-radius: 10px;
.line {
margin-bottom: 18px;
font-size: 14px;
line-height: 1.6;
}
.field {
font-size: 14px;
font-weight: 600;
}
}
.form {
@apply max-h-[calc(100vh-270px)] overflow-auto;
.step {
@apply relative pl-[42px];
&:before {
@apply absolute top-0 left-0 w-[30px] h-[30px];
content: '';
background: url(../../assets/images/config1.png) no-repeat;
}
&:nth-child(2):before {
background-image: url(../../assets/images/config2.png);
}
&:nth-child(3):before {
background-image: url(../../assets/images/config3.png);
}
&:nth-child(4):before {
background-image: url(../../assets/images/config4.png);
}
&:nth-child(5):before {
background-image: url(../../assets/images/config5.png);
}
&:nth-child(6):before {
background-image: url(../../assets/images/config6.png);
}
&:after {
content: '';
@apply absolute top-[40px] left-[14px] w-[2px] h-[87%] bg-[#006bff];
}
}
.step-name {
@apply pl-[5px] text-sm font-semibold text-[#006bff];
}
:deep(.el-form-item__label) {
@apply font-semibold text-sm leading-[32px] text-black;
}
.field-name {
@apply mb-3 text-sm font-semibold leading-[32px] text-[#333];
}
.tips {
@apply text-sm text-[#686868];
}
.num-inputs {
@apply flex items-center;
.el-input {
@apply w-[200px];
}
.split {
@apply mx-2.5 text-white;
}
.unit {
@apply ml-2.5 text-sm text-[#333];
}
}
}
.submit {
@apply py-[15px] px-[22px] mt-5 text-sm leading-none text-white bg-[#006bff] rounded-xl cursor-pointer;
&:hover {
@apply opacity-90;
}
}
.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];
}
}
@import url(../../styles/form.scss);
</style>

@ -4,33 +4,7 @@
@tab-click="tabChange">
<el-tab-pane label="产品要素"
name="tab1">
<div class="info mt-2">
<h6 class="step-name">产品定义</h6>
<p class="text">{{ info.productDefinition }}</p>
<h6 class="step-name mt-5">产品要素</h6>
<div class="line">
<p class="text">{{ info.productName }}</p>
</div>
<div class="line">
<p class="text">贷款币种人民币</p>
</div>
<div v-if="info.loanPurpose"
class="line">
<p class="text">{{ info.loanPurpose }}</p>
</div>
<div v-if="info.guarantyStyleList"
class="line">
<p class="text">{{ info.guarantyStyleList }}</p>
</div>
<div v-if="info.lengthOfMaturity"
class="line">
<p class="text">{{ info.lengthOfMaturity }}</p>
</div>
<div v-if="info.loanCommitment"
class="line">
<p class="text">{{ info.loanCommitment }}</p>
</div>
</div>
<info />
</el-tab-pane>
</el-tabs>
</div>
@ -38,44 +12,15 @@
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import type { TabsPaneContext } from 'element-plus';
import { productElement } from '@/api/bank';
import { useRouter, useRoute } from 'vue-router';
import Info from './Info.vue';
defineProps({ modelValue: { type: Object, required: true } });
defineEmits({ 'update:form': null });
const router = useRouter();
const route = useRoute();
const id = computed(() => +route.query.id);
const curTab = ref<string>('tab1');
const info = ref<any>({});
// tab
const tabChange = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event);
};
//
const getDetail = async () => {
if (id.value) {
try {
const { data } = await productElement(id.value);
info.value = data;
} finally {
}
}
};
watch(
() => route.query,
() => {
getDetail();
},
{
immediate: true,
},
);
onMounted(() => {});
</script>
<style lang="scss" scoped>

@ -0,0 +1,130 @@
<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="role == 43">
<h6 class="step-name mt-5">材料要求</h6>
<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 role = computed(() => route.query.role || 41); // 123
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 = info.value.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 {
padding: 20px 16px;
margin-bottom: 30px;
background: #f9fafc;
border-radius: 10px;
.line {
margin-bottom: 18px;
font-size: 14px;
line-height: 1.6;
}
.field {
font-size: 14px;
font-weight: 600;
}
}
</style>

@ -4,7 +4,7 @@
<search v-model="params.keyWord"
@change="initList"></search>
<div class="filter">
<el-checkbox-group v-if="role == 2"
<el-checkbox-group v-if="params.roleId == 42"
class="mr-5"
v-model="productTypes">
<el-checkbox :label="0">个人</el-checkbox>
@ -30,7 +30,7 @@
<el-select v-model="params.status"
placeholder="产品进度"
size="large">
<el-option v-for="item in paces"
<el-option v-for="item in params.roleId == 43 ? getExpertStatus() : productState.status"
:key="item.id"
:label="item.name"
:value="item.id" />
@ -39,7 +39,7 @@
alt=""
class="icon" />
</div>
<div v-if="role == 1"
<div v-if="params.roleId == 41"
class="add-btn"
@click="toAdd">
<img src="@/assets/images/plus.png"
@ -61,9 +61,9 @@
label="产品名称"></el-table-column>
<el-table-column prop="productNumber"
label="产品编号"></el-table-column>
<el-table-column v-if="role == 2"
<el-table-column v-if="params.roleId != 41"
prop="loanCeiling"
label="贷款对象">
:label="params.roleId == 42 ? '贷款对象' : '产品对象'">
<template #default="{ row }">
{{ row.productType ? '企业' : '个人' }}
</template>
@ -88,13 +88,12 @@
<el-table-column prop="id"
label="操作">
<template #default="{ row }">
<el-button type="text"
size="small"
@click="toDetail(`/product/cardList/config`, row.id)">配置{{ role == 1 ? '要素' : '风控' }}</el-button>
<el-button type="text"
@click="toDetail(`/product/cardList/detail`, row.id)"
size="small">产品详情</el-button>
<el-popconfirm v-if="role == 1"
<template v-if="params.roleId != 43">
<el-button type="text"
size="small"
@click="toDetail(`/product/cardList/config`, row.id)">配置{{ params.roleId == 41 ? '要素' : '风控' }}</el-button>
</template>
<el-popconfirm v-if="params.roleId == 41"
title="您确定删除吗?"
@confirm.stop="handleDelete(row.id)">
<template #reference>
@ -103,6 +102,20 @@
@click.stop="stop">删除</el-button>
</template>
</el-popconfirm>
<!-- 专家委员会 && 非待审批 展示审批结果 -->
<el-button v-if="params.roleId == 43 && row.status != 296"
type="text"
@click="toDetail(`/product/cardList/detail`, row.id)"
size="small">审批结果</el-button>
<!-- 产品经理 || 风控经理 && 非审批打回 展示产品详情 -->
<el-button v-if="params.roleId != 43 && row.status != 299"
type="text"
@click="toDetail(`/product/cardList/detail`, row.id)"
size="small">产品详情</el-button>
<el-button v-if="params.roleId == 43 && row.status == 296"
type="text"
size="small"
@click="toDetail(`/product/cardList/approve`, row.id)">审批</el-button>
</template></el-table-column>
</el-table>
<el-pagination v-model:currentPage="currentPage"
@ -129,7 +142,7 @@ import { getProcessInformationBasedOnRoles } from '@/api/judgment';
import { bankingProductsList, batchDeletion } from '@/api/bank';
import Search from '@/components/Search.vue';
import { useRouter, useRoute } from 'vue-router';
import { getStatus } from '@/store/useProduct';
import { productState, getExpertStatus, getStatus } from '@/store/useProduct';
const { t } = useI18n();
const router = useRouter();
@ -141,47 +154,21 @@ const params = reactive({
keyWord: '',
productType: computed(() => {
let val = <number | string>'';
if (route.query.role == 2) {
if (productTypes.value.length === 1) val = productTypes.value[0];
return val;
if (params.roleId == 42 && productTypes.value.length === 1) {
val = productTypes.value[0];
} else if (params.roleId == 41) {
val = +route.query.type;
}
return +route.query.type;
return val;
}),
status: '',
roleId: computed(() => +route.query.role || 41),
});
// params.productType = computed(() => (route.query.role == 2 ? '' : +route.query.type));
const role = computed(() => route.query.role || 1); // 12
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);
const total = ref<number>(0);
const table = ref<any>();
const guarantees = ref<Array<any>>([]);
const paces = ref<Array<any>>([
{
id: '',
name: '产品进度',
},
{
id: 1,
name: '配置风控',
},
{
id: 2,
name: '待审批',
},
{
id: 3,
name: '审批通过',
},
{
id: 4,
name: '审批不通过',
},
{
id: 5,
name: '审批打回',
},
]);
const list = ref<Array<any>>([]);
const loading = ref<boolean>(false);
//
@ -215,10 +202,6 @@ onMounted(() => {
});
watch([params, () => route.query], initList);
// watch(productTypes, (val) => {
// console.log('🚀 ~ file: List.vue:207 ~ watch ~ val:', val);
// params.productType = val.length === 2 ? '' :
// });
const handleSort = ({ column, prop, order }: { column: any; prop: string; order: string }) => {
params.createDateSort = order === 'descending' ? 'desc' : order === 'ascending' ? 'asc' : '';
getList();
@ -236,13 +219,17 @@ const toDetail = async (path: string, id: number) => {
path,
query: {
...route.query,
type: params.productType,
id,
},
});
};
//
const toCardList = () => {
router.push('/product/cardList/config');
router.push({
path: '/product/cardList/config',
query: route.query,
});
};
const handleDelete = async (id: number) => {
@ -271,7 +258,6 @@ const handleDelete = async (id: number) => {
@apply inline-flex items-center h-[36px] px-[24px] text-sm text-white rounded-[18px] cursor-pointer;
background: linear-gradient(-36deg, #006bff, #2ab1ff);
border: 1px solid #ffffff;
cursor: pointer;
.icon {
@apply mr-[8px];
}

Loading…
Cancel
Save