银行产品相关联调

V0.1
yujialong 1 year ago
parent aed69ad7f7
commit 3e9e1dac1e
  1. 5
      src/api/bank.ts
  2. BIN
      src/assets/images/bankDetail/1.png
  3. BIN
      src/assets/images/bankDetail/2.png
  4. BIN
      src/assets/images/bankDetail/3.png
  5. BIN
      src/assets/images/bankDetail/4.png
  6. BIN
      src/assets/images/icon5-1.png
  7. BIN
      src/assets/images/icon5.png
  8. BIN
      src/assets/images/icon6-1.png
  9. BIN
      src/assets/images/icon6.png
  10. 18
      src/components/Search.vue
  11. 157
      src/layout/components/AppSidebar/Menu.vue
  12. 57
      src/layout/components/AppSidebar/MenuItem.vue
  13. 79
      src/layout/components/AppSidebar/index.vue
  14. 8
      src/router/index.ts
  15. 40
      src/store/useProduct.ts
  16. 23
      src/styles/form.scss
  17. 170
      src/views/config/Buyer.vue
  18. 44
      src/views/config/Index.vue
  19. 119
      src/views/finance/BankDetail.vue
  20. 29
      src/views/product/Add.vue
  21. 106
      src/views/product/CardList.vue
  22. 33
      src/views/product/Config.vue
  23. 80
      src/views/product/Detail.vue
  24. 87
      src/views/product/List.vue

@ -6,3 +6,8 @@ export const updateStorage = async (data: Record<string, any>): Promise<any> =>
export const primaryTypeOfGuarantee = async (): Promise<any> => (await axios.post('/product/bankGuaranteeType/primaryTypeOfGuarantee')).data; export const primaryTypeOfGuarantee = async (): Promise<any> => (await axios.post('/product/bankGuaranteeType/primaryTypeOfGuarantee')).data;
export const bankingProductsList = async (data: Record<string, any>): Promise<any> => (await axios.post('/product/product/bank/products/bankingProductsList', data)).data; export const bankingProductsList = async (data: Record<string, any>): Promise<any> => (await axios.post('/product/product/bank/products/bankingProductsList', data)).data;
export const batchDeletion = async (data: Record<string, any>): Promise<any> => (await axios.post('/product/product/bank/products/batchDeletion', data)).data;
export const personalRiskControlConfigurationField = async (): Promise<any> =>
(await axios.post('/product/riskControlConfigurationField/personalRiskControlConfigurationField')).data;
export const productElement = async (data: Record<string, any>): Promise<any> => (await axios.post('/product/product/bank/products/productElement', data)).data;
export const findById = async (id: number): Promise<any> => (await axios.post(`/product/product/bank/products/findById?id=${id}`)).data;

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -2,7 +2,8 @@
<div class="search"> <div class="search">
<input type="text" <input type="text"
placeholder="搜索" placeholder="搜索"
maxlength="20" /> maxlength="20"
v-model="modelValue" />
<img src="@/assets/images/search.png" <img src="@/assets/images/search.png"
alt="" alt=""
class="icon" /> class="icon" />
@ -10,9 +11,22 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
defineProps({ import { watch, toRef, ref } from 'vue';
const props = defineProps({
modelValue: { type: String, required: true }, modelValue: { type: String, required: true },
}); });
const timer = ref<any>(null);
const emit = defineEmits({ 'update:modelValue': null });
watch(
() => props.modelValue,
(prop: val) => {
clearTimeout(timer.value);
timer.value = setTimeout(() => {
emit('update:modelValue', prop);
}, 500);
},
);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

@ -0,0 +1,157 @@
<template>
<ul class="switch px-7 mt-5">
<template v-if="isProduct">
<li :class="{ active: active == 1 }"
@click="toPage('/product?type=0&i=1')">
<img class="icon"
src="@/assets/images/icon5.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon5-1.png"
alt="" />
<p class="text">个人产品</p>
</li>
<li :class="{ active: active == 2 }"
@click="toPage('/product?type=1&i=2')">
<img class="icon"
src="@/assets/images/icon6.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon6-1.png"
alt="" />
<p class="text">企业产品</p>
</li>
</template>
<template v-else>
<li>
<img class="icon"
src="@/assets/images/icon1.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon1-1.png"
alt="" />
<p class="text">产品风控配置</p>
</li>
<li>
<img class="icon"
src="@/assets/images/icon2.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon2-1.png"
alt="" />
<p class="text">准入模型</p>
</li>
<li>
<img class="icon"
src="@/assets/images/icon3.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon3-1.png"
alt="" />
<p class="text">利率定价模型</p>
</li>
<li>
<img class="icon"
src="@/assets/images/icon4.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon4-1.png"
alt="" />
<p class="text">贷后管理模型</p>
</li>
</template>
</ul>
</template>
<script setup lang="ts">
import { computed, defineProps, ref, toRefs } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { isShowMenu } from '@/store/useCurrentUser';
const router = useRouter();
const route = useRoute();
const active = computed(() => route.query.i);
const isProduct = ref<any>(true);
//
const toPage = (path: string) => {
router.push(path);
};
function isExternal(path: string): boolean {
return /^(https?:|mailto:|tel:)/.test(path);
}
// const props = defineProps({ route: { type: Object, required: true }, basePath: { type: String, default: '' } });
// const { route, basePath } = toRefs(props);
// const router = useRouter();
// //
// const isShow = computed(() => !route.value.meta?.hidden);
// //
// const subMenu = computed(() => route.value.meta?.title && route.value.children);
// // title
// const targetRoute = computed(() => (!route.value.meta?.title && route.value.children?.length > 0 ? route.value.children[0] : route.value));
// const icon = computed(() => targetRoute.value.meta?.icon);
// const title = computed(() => targetRoute.value.meta?.title);
// // targetItem使使basePath
// const path = computed(() => (route.value !== targetRoute.value ? targetRoute.value.path : ''));
// const resolvePath = (routePath: string) => {
// if (isExternal(routePath)) {
// return routePath;
// }
// return `${basePath.value}/${routePath}`;
// };
// const handleClick = () => {
// const fullPath = resolvePath(path.value);
// if (isExternal(fullPath)) {
// window.open(fullPath, '_blank');
// } else {
// router.push(resolvePath(path.value));
// }
// };
</script>
<style lang="scss" scoped>
.switch {
li {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 122px;
height: 102px;
margin-bottom: 20px;
background: #ffffff;
box-shadow: 0px 0px 8px 0px rgba(162, 199, 246, 0.16);
border-radius: 10px;
cursor: pointer;
&:hover,
&.active {
background: linear-gradient(-36deg, #3c65ff, #33d1ff);
box-shadow: 0px 6px 16px 0px rgba(96, 155, 255, 0.56);
.icon {
display: none;
}
.icon-1 {
display: inline-block;
}
.text {
color: #fff;
}
}
}
img {
margin: 0 auto;
}
.icon-1 {
display: none;
}
.text {
margin-top: 10px;
font-family: MiSans;
font-weight: 600;
}
}
</style>

@ -1,57 +0,0 @@
<template>
<template v-if="isShow">
<el-sub-menu v-if="subMenu" :index="resolvePath(path)" popper-append-to-body>
<template #title>
<el-icon v-if="icon"><component :is="icon"></component></el-icon>
<span>{{ $t(title) }}</span>
</template>
<menu-item v-for="item in route.children.filter((item:any) => isShowMenu(item))" :key="item.path" :route="item" :base-path="resolvePath(item.path)" />
</el-sub-menu>
<el-menu-item v-else :index="resolvePath(path)" @click="handleClick">
<el-icon v-if="icon"><component :is="icon"></component></el-icon>
<template #title>
<span>{{ $t(title) }}</span>
</template>
</el-menu-item>
</template>
</template>
<script setup lang="ts">
import { computed, defineProps, toRefs } from 'vue';
import { useRouter } from 'vue-router';
import { isShowMenu } from '@/store/useCurrentUser';
function isExternal(path: string): boolean {
return /^(https?:|mailto:|tel:)/.test(path);
}
const props = defineProps({ route: { type: Object, required: true }, basePath: { type: String, default: '' } });
const { route, basePath } = toRefs(props);
const router = useRouter();
//
const isShow = computed(() => !route.value.meta?.hidden);
//
const subMenu = computed(() => route.value.meta?.title && route.value.children);
// title
const targetRoute = computed(() => (!route.value.meta?.title && route.value.children?.length > 0 ? route.value.children[0] : route.value));
const icon = computed(() => targetRoute.value.meta?.icon);
const title = computed(() => targetRoute.value.meta?.title);
// targetItem使使basePath
const path = computed(() => (route.value !== targetRoute.value ? targetRoute.value.path : ''));
const resolvePath = (routePath: string) => {
if (isExternal(routePath)) {
return routePath;
}
return `${basePath.value}/${routePath}`;
};
const handleClick = () => {
const fullPath = resolvePath(path.value);
if (isExternal(fullPath)) {
window.open(fullPath, '_blank');
} else {
router.push(resolvePath(path.value));
}
};
</script>

@ -9,44 +9,7 @@
<p class="my-2 text-white text-sm">产品经理</p> <p class="my-2 text-white text-sm">产品经理</p>
<p class="text-white text-xs">操作日期2018-02-06</p> <p class="text-white text-xs">操作日期2018-02-06</p>
</div> </div>
<ul class="switch px-7 mt-5"> <menus></menus>
<li>
<img class="icon"
src="@/assets/images/icon1.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon1-1.png"
alt="" />
<p class="text">产品风控配置</p>
</li>
<li>
<img class="icon"
src="@/assets/images/icon2.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon2-1.png"
alt="" />
<p class="text">准入模型</p>
</li>
<li>
<img class="icon"
src="@/assets/images/icon3.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon3-1.png"
alt="" />
<p class="text">利率定价模型</p>
</li>
<li>
<img class="icon"
src="@/assets/images/icon4.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon4-1.png"
alt="" />
<p class="text">贷后管理模型</p>
</li>
</ul>
</el-scrollbar> </el-scrollbar>
</div> </div>
</template> </template>
@ -54,6 +17,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue'; import { computed } from 'vue';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import Menus from './Menu.vue';
import { isShowMenu } from '@/store/useCurrentUser'; import { isShowMenu } from '@/store/useCurrentUser';
import { appState } from '@/store/useAppState'; import { appState } from '@/store/useAppState';
@ -84,43 +48,4 @@ const collapse = computed(() => !appState.sidebar);
.avatar { .avatar {
background: url(../../../assets/images/5.png) 0 0/100% 100% no-repeat; background: url(../../../assets/images/5.png) 0 0/100% 100% no-repeat;
} }
.switch {
li {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 122px;
height: 102px;
margin-bottom: 20px;
background: #ffffff;
box-shadow: 0px 0px 8px 0px rgba(162, 199, 246, 0.16);
border-radius: 10px;
cursor: pointer;
&:hover {
background: linear-gradient(-36deg, #3c65ff, #33d1ff);
box-shadow: 0px 6px 16px 0px rgba(96, 155, 255, 0.56);
.icon {
display: none;
}
.icon-1 {
display: inline-block;
}
.text {
color: #fff;
}
}
}
img {
margin: 0 auto;
}
.icon-1 {
display: none;
}
.text {
margin-top: 10px;
font-family: MiSans;
font-weight: 600;
}
}
</style> </style>

@ -41,8 +41,16 @@ export const routes: Array<RouteRecordRaw> = [
{ path: 'account', component: () => import('@/views/finance/Account.vue'), meta: { title: '我的账户' } }, { path: 'account', component: () => import('@/views/finance/Account.vue'), meta: { title: '我的账户' } },
{ path: 'order', component: () => import('@/views/finance/Order.vue'), meta: { title: '我的订单' } }, { path: 'order', component: () => import('@/views/finance/Order.vue'), meta: { title: '我的订单' } },
{ path: 'armory', component: () => import('@/views/finance/Armory.vue'), meta: { title: '英雄榜' } }, { path: 'armory', component: () => import('@/views/finance/Armory.vue'), meta: { title: '英雄榜' } },
{ path: 'bankDetail', component: () => import('@/views/finance/BankDetail.vue'), meta: { title: '银行产品详情' } },
], ],
}, },
{
path: '/config',
redirect: '/config/index',
component: Layout,
meta: { title: '产品经理' },
children: [{ path: 'index', component: () => import('@/views/config/Index.vue'), meta: { title: '参数配置' } }],
},
// 404 page must be placed at the end !!! // 404 page must be placed at the end !!!
{ {
path: '/:pathMatch(.*)*', path: '/:pathMatch(.*)*',

@ -0,0 +1,40 @@
import { reactive, readonly } from 'vue';
import Cookies from 'js-cookie';
export interface Product {
status?: Record<string, any>;
}
const state = reactive<Product>({
// 产品进度
status: [
{
id: '',
name: '产品进度',
},
{
id: 1,
name: '配置风控',
},
{
id: 2,
name: '待审批',
},
{
id: 3,
name: '审批通过',
},
{
id: 4,
name: '审批不通过',
},
{
id: 5,
name: '审批打回',
},
],
});
export const getStatus = (id: number | string): string => {
return state.status.find((e) => e.id === id).name;
};

@ -1,3 +1,15 @@
@mixin btn {
padding: 15px 22px;
font-size: 14px;
line-height: 1;
color: #fff;
background: #006bff;
border-radius: 12px;
cursor: pointer;
&:hover {
opacity: 0.9;
}
}
.forms { .forms {
&.step-form { &.step-form {
.step-name { .step-name {
@ -91,15 +103,6 @@
line-height: 32px; line-height: 32px;
} }
.submit { .submit {
padding: 15px 22px; @include btn;
font-size: 14px;
line-height: 1;
color: #fff;
background: #006bff;
border-radius: 12px;
cursor: pointer;
&:hover {
opacity: 0.9;
}
} }
} }

@ -0,0 +1,170 @@
<template>
<h6 class="title">城市人口及年龄参数</h6>
<el-table class="c-table"
ref="table"
v-loading="loading"
:data="list"
border
@sort-change="handleSort">
<el-table-column prop="productName"
label="城市总人口 (人)"
align="center">
<el-input maxlength="20"></el-input>
</el-table-column>
<el-table-column prop="productNumber"
label="年龄 (岁)"
align="center"></el-table-column>
<el-table-column prop="parentIds"
label="年龄占比 (%)"
align="center">
<el-input maxlength="3"></el-input>
</el-table-column>
</el-table>
<h6 class="title mt-7">学历参数</h6>
<el-table class="c-table"
ref="table"
v-loading="loading"
:data="list"
border
@sort-change="handleSort">
<el-table-column prop="productName"
label="年龄 (岁)"
align="center"> </el-table-column>
<el-table-column prop="productNumber"
label="学历"
align="center"></el-table-column>
<el-table-column prop="parentIds"
label="学历占比 (%)"
align="center">
<el-input maxlength="3"></el-input>
</el-table-column>
</el-table>
<h6 class="title mt-7">企业数量配置</h6>
<el-table class="c-table"
ref="table"
v-loading="loading"
:data="list"
border
@sort-change="handleSort">
<el-table-column prop="productName"
label="城市总人口 (人)"
align="center"> </el-table-column>
<el-table-column prop="parentIds"
label="城市总人口 (人)"
align="center">
<el-input maxlength="3"></el-input>
</el-table-column>
</el-table>
<h6 class="title mt-7">单个商品每日需求量</h6>
<el-table class="c-table"
ref="table"
v-loading="loading"
:data="list"
border
@sort-change="handleSort">
<el-table-column prop="productName"
label="买家类型"
align="center"> </el-table-column>
<el-table-column prop="parentIds"
label="买家总占比 (%)"
align="center">
<el-input maxlength="3"></el-input>
</el-table-column>
<el-table-column prop="parentIds"
label="每次需求人数占比 (%)"
align="center">
<el-input maxlength="3"></el-input>
</el-table-column>
<el-table-column prop="parentIds"
label="单个买家单次需求"
align="center">
<el-input maxlength="3"></el-input>
</el-table-column>
</el-table>
<h6 class="title mt-7">系统账户起始金额</h6>
<el-form class="w-[300px]"
:model="form"
label-width="120px"
label-suffix=":">
<el-form-item label="银行账户">
<el-input v-model="form.name">
<template #suffix> 万元 </template>
</el-input>
</el-form-item>
<el-form-item label="保险账户">
<el-input v-model="form.name">
<template #suffix> 万元 </template>
</el-input>
</el-form-item>
<el-form-item label="基金账户">
<el-input v-model="form.name">
<template #suffix> 万元 </template>
</el-input>
</el-form-item>
</el-form>
<div class="flex justify-end">
<div class="submit">保存修改</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { primaryTypeOfGuarantee, bankingProductsList } from '@/api/bank';
defineProps({ modelValue: { type: Object, required: true } });
defineEmits({ 'update:form': null });
const list = ref<Array<any>>([]);
const form = ref<Object>({});
//
const getGuarantee = async () => {
try {
const { data } = await primaryTypeOfGuarantee();
guarantees.value = data;
} finally {
}
};
onMounted(() => {
// getGuarantee();
// fetchData();
});
</script>
<style lang="scss" scoped>
@import url(../../styles/form.scss);
.title {
@apply flex items-center mb-5 text-base text-[#222D42] font-semibold;
&:before {
content: '';
@apply w-1 h-4 mr-2 bg-[#006BFF] rounded-sm;
}
}
.c-table {
@apply rounded-[10px];
:deep(th.el-table__cell) {
@apply bg-[#F8FBFC];
}
:deep(.cell) {
@apply 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;
}
}
</style>

@ -0,0 +1,44 @@
<template>
<div class="block">
<el-tabs v-model="curTab" @tab-click="tabChange">
<el-tab-pane label="系统买方" name="tab1">
<buyer></buyer>
</el-tab-pane>
<el-tab-pane label="金融市场" name="tab2"> </el-tab-pane>
<el-tab-pane label="扫单配置" name="tab3"> </el-tab-pane>
<el-tab-pane label="渠道广告" name="tab4"> </el-tab-pane>
</el-tabs>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import type { TabsPaneContext } from 'element-plus';
import { primaryTypeOfGuarantee, bankingProductsList } from '@/api/bank';
import Buyer from './Buyer.vue';
defineProps({ modelValue: { type: Object, required: true } });
defineEmits({ 'update:form': null });
const curTab = ref<string>('tab1');
// tab
const tabChange = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event);
};
//
const getGuarantee = async () => {
try {
const { data } = await primaryTypeOfGuarantee();
guarantees.value = data;
} finally {
}
};
onMounted(() => {
// getGuarantee();
// fetchData();
});
</script>
<style lang="scss" scoped></style>

@ -0,0 +1,119 @@
<template>
<div>
<back name="产品详情"></back>
<div class="flex">
<div class="item mr-[18px]">
<h6 class="text-lg font-semibold text-[#053C6A]">智信女神贷</h6>
<div class="flex justify-between mt-3 text-center">
<div>
<p class="mb-1 text-lg font-semibold text-[#00347C]">3.5-4.01%</p>
<p class="text-sm text-[#00327C]">参考利率</p>
</div>
<div>
<p class="mb-1 text-lg font-semibold text-[#00347C]">3.5-4.01%</p>
<p class="text-sm text-[#00327C]">贷款额度</p>
</div>
<div>
<p class="mb-1 text-lg font-semibold text-[#00347C]">3.5-4.01%</p>
<p class="text-sm text-[#00327C]">贷款期限</p>
</div>
</div>
</div>
<div class="item mr-[18px]">
<h6 class="text-lg font-semibold text-[#333]">产品定义</h6>
<div class="mt-3 text-sm text-[#333] leading-6">根据个人客户的信用状况为其提供的一种短期融资便利产品借款人在我行核定的额度金额内可循环周转使用贷款</div>
</div>
<div class="item">
<h6 class="text-lg font-semibold text-[#053C6A]">本产品排行</h6>
<div class="flex justify-between mt-3 text-center">
<div>
<p class="mb-1 text-lg font-semibold text-[#00347C]">3.5-4.01%</p>
<p class="text-sm text-[#00327C]">今日成交金额</p>
</div>
<div>
<p class="mb-1 text-lg font-semibold text-[#00347C]">3.5-4.01%</p>
<p class="text-sm text-[#00327C]">今日收益</p>
</div>
<div>
<p class="mb-1 text-lg font-semibold text-[#00347C]">3.5-4.01%</p>
<p class="text-sm text-[#00327C]">累计收益</p>
</div>
</div>
</div>
</div>
<div class="block flex justify-between mt-5">
<div>
<div class="line">
<span class="label">担保方式</span>
<div class="val">担保方式</div>
</div>
<div class="line">
<span class="label">贷款用途</span>
<div class="val">担保方式</div>
</div>
<div class="line">
<span class="label">担保方式</span>
<div class="val">担保方式</div>
</div>
</div>
<div class="user m-4">
<h6 class="mb-4 text-lg font-semibold text-[#01305B]">产品经理</h6>
<div class="text-center">
<img src="@/assets/images/bankDetail/4.png"
alt=""
class="mx-auto" />
<p class="mt-2 font-semibold text-[#114575]">刘秀</p>
</div>
<p class="mt-2 text-[#114575]">财经学院 金融2班</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { Plus } from '@element-plus/icons-vue';
import { primaryTypeOfGuarantee, bankingProductsList } from '@/api/bank';
import Search from '@/components/Search.vue';
import Back from '@/components/Back.vue';
const form = ref<Object>({});
//
const getGuarantee = async () => {
try {
const { data } = await primaryTypeOfGuarantee();
guarantees.value = data;
} finally {
}
};
onMounted(() => {
// getGuarantee();
// fetchData();
});
</script>
<style lang="scss" scoped>
.item {
@apply p-5;
width: calc((100% - 36px) / 3);
background: url(../../assets/images/bankDetail/2.png) 0 0/100% 100% no-repeat;
&:first-child {
background-image: url(../../assets/images/bankDetail/1.png);
}
}
.line {
@apply flex mb-3;
.label {
@apply text-sm text-[#333] font-semibold;
}
.val {
@apply text-sm text-[#333];
}
}
.user {
@apply p-4;
background: url(../../assets/images/bankDetail/3.png) 0 0/100% 100% no-repeat;
}
</style>

@ -23,7 +23,7 @@
<div class="line"> <div class="line">
<label class="label">产品币种</label> <label class="label">产品币种</label>
<div class="fields"> <div class="fields">
<el-select v-model="modelValue.status" <el-select v-model="form.coinType"
placeholder="请选择"> placeholder="请选择">
<el-option label="人民币" <el-option label="人民币"
value="1" /> value="1" />
@ -34,7 +34,7 @@
<label class="label">贷款对象</label> <label class="label">贷款对象</label>
<div class="fields"> <div class="fields">
<p class="field-name">选择本产品的贷款对象</p> <p class="field-name">选择本产品的贷款对象</p>
<el-checkbox-group v-model="modelValue.cl"> <el-checkbox-group v-model="form.cl">
<el-checkbox label="身份证" /> <el-checkbox label="身份证" />
<el-checkbox label="身份证" /> <el-checkbox label="身份证" />
</el-checkbox-group> </el-checkbox-group>
@ -44,7 +44,7 @@
<label class="label">贷款用途</label> <label class="label">贷款用途</label>
<div class="fields"> <div class="fields">
<p class="field-name">选择本产品贷款资金的用途</p> <p class="field-name">选择本产品贷款资金的用途</p>
<el-radio-group v-model="modelValue.cl"> <el-radio-group v-model="form.cl">
<el-radio :label="3">Option A</el-radio> <el-radio :label="3">Option A</el-radio>
<el-radio :label="9">Option C</el-radio> <el-radio :label="9">Option C</el-radio>
</el-radio-group> </el-radio-group>
@ -54,7 +54,7 @@
<label class="label">担保方式</label> <label class="label">担保方式</label>
<div class="fields"> <div class="fields">
<p class="field-name">选择本产品的担保种类</p> <p class="field-name">选择本产品的担保种类</p>
<el-checkbox-group v-model="modelValue.cl"> <el-checkbox-group v-model="form.cl">
<el-checkbox label="身份证" /> <el-checkbox label="身份证" />
<el-checkbox label="身份证" /> <el-checkbox label="身份证" />
</el-checkbox-group> </el-checkbox-group>
@ -103,7 +103,7 @@
<label class="label">还款方式</label> <label class="label">还款方式</label>
<div class="fields"> <div class="fields">
<p class="field-name">选择本产品可以选择的还款方式</p> <p class="field-name">选择本产品可以选择的还款方式</p>
<el-checkbox-group v-model="modelValue.cl"> <el-checkbox-group v-model="form.cl">
<el-checkbox label="身份证" /> <el-checkbox label="身份证" />
<el-checkbox label="身份证" /> <el-checkbox label="身份证" />
</el-checkbox-group> </el-checkbox-group>
@ -112,7 +112,7 @@
<div class="line"> <div class="line">
<label class="label">提前还款</label> <label class="label">提前还款</label>
<div class="fields flex items-center"> <div class="fields flex items-center">
<el-switch v-model="modelValue.cl" /> <el-switch v-model="form.cl" />
<p class="tips ml-4">本产品是否支持提前还款</p> <p class="tips ml-4">本产品是否支持提前还款</p>
</div> </div>
</div> </div>
@ -130,27 +130,28 @@
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import type { TabsPaneContext } from 'element-plus'; import type { TabsPaneContext } from 'element-plus';
import { primaryTypeOfGuarantee, bankingProductsList } from '@/api/bank'; import { personalRiskControlConfigurationField } from '@/api/bank';
defineProps({ modelValue: { type: Object, required: true } });
defineEmits({ 'update:form': null });
const curTab = ref<string>('tab1'); const curTab = ref<string>('tab1');
const config = ref<any>({});
const form = ref<any>({
coinType: 1,
});
// tab // tab
const tabChange = (tab: TabsPaneContext, event: Event) => { const tabChange = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event); console.log(tab, event);
}; };
// //
const getGuarantee = async () => { const getConfig = async () => {
try { try {
const { data } = await primaryTypeOfGuarantee(); const { data } = await personalRiskControlConfigurationField();
guarantees.value = data; config.value = data;
} finally { } finally {
} }
}; };
onMounted(() => { onMounted(() => {
// getGuarantee(); getConfig();
// fetchData(); // fetchData();
}); });
</script> </script>

@ -1,27 +1,34 @@
<template> <template>
<div class="block flex" <div class="block flex"
style="padding-top: 0"> style="padding-top: 0">
<div class="left pr-5 py-4"> <div class="left w-[241px] pr-5 py-4">
<div class="flex justify-center items-center py-2 mb-3 text-sm text-[#006BFF] bg-[rgba(0,107,255,0.1)] border border-solid border-[#006BFF] rounded-[10px] cursor-pointer"
@click="toAdd">
<el-icon class="mr-1"
:size="16"
color="#006BFF">
<Plus />
</el-icon>
新增产品
</div>
<div class="flex justify-end mb-4"> <div class="flex justify-end mb-4">
<img src="@/assets/images/fold.png" <img src="@/assets/images/fold.png"
alt="" alt=""
class="cursor-pointer" /> class="cursor-pointer" />
</div> </div>
<ul class="products"> <ul class="products">
<li> <li v-for="(item, i) in list"
:key="i"
:class="{ active: item.id === id }"
@click="switchProduct(item)">
<img src="@/assets/images/trash.png" <img src="@/assets/images/trash.png"
alt="" alt=""
class="del" /> class="del"
<h6>轻松贷</h6> @click="handleDelete(row.id)" />
<p class="type">个人信用贷</p> <h6>{{ item.productName }}</h6>
<p class="status">配置风控</p> <p class="type">{{ item.productNumber + ' ' + item.guarantyStyle }}</p>
<p class="date">创建日期2021-02-26</p> <p class="status">{{ getStatus(item.status) }}</p>
</li> <p class="date">创建日期{{ item.createTime.split(' ')[0] }}</p>
<li>
<h6>轻松贷</h6>
<p class="type">个人信用贷</p>
<p class="status">配置风控</p>
<p class="date">创建日期2021-02-26</p>
</li> </li>
</ul> </ul>
</div> </div>
@ -30,6 +37,8 @@
v-model="form"></component> --> v-model="form"></component> -->
<config v-if="action === 'config'" <config v-if="action === 'config'"
v-model="form"></config> v-model="form"></config>
<detail v-if="action === 'detail'"
v-model="form"></detail>
<add v-else-if="action === 'add'" <add v-else-if="action === 'add'"
v-model="form"></add> v-model="form"></add>
</div> </div>
@ -37,39 +46,72 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref, reactive, toRef, toRefs, watch } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { Plus } from '@element-plus/icons-vue';
import { perm } from '@/store/useCurrentUser'; import { perm } from '@/store/useCurrentUser';
import { primaryTypeOfGuarantee, bankingProductsList } from '@/api/bank'; import { bankingProductsList, batchDeletion } from '@/api/bank';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { getStatus } from '@/store/useProduct';
import Config from './Config.vue'; import Config from './Config.vue';
import Detail from './Detail.vue';
import Add from './Add.vue'; import Add from './Add.vue';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const { action } = route.params; const action = ref<any>('');
const list = ref<Array<any>>([]);
const form = ref<any>({ const form = ref<any>({
cl: '', cl: '',
}); });
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
// const productType = computed(() => +route.query.type);
const getGuarantee = async () => { const id = computed(() => +route.query.id);
//
const getList = async () => {
loading.value = true;
try { try {
const { data } = await primaryTypeOfGuarantee(); const { data } = await bankingProductsList({ pageNum: 1, pageSize: 1000, productType: productType.value });
guarantees.value = data; list.value = data.message.records;
} finally { } finally {
loading.value = false;
} }
}; };
onMounted(() => { onMounted(() => {
console.log(33, useRoute().params.action); getList();
// getGuarantee();
// fetchData();
}); });
const handleDelete = async (ids: number[]) => { watch(
await deleteUser(ids); route,
fetchData(); (route: any) => {
// ElMessage.success(t('success')); action.value = route.params.action;
},
{
immediate: true,
},
);
//
const switchProduct = (item: any) => {
router.push({
path: `/product/cardList/detail`,
query: {
...route.query,
id: item.id,
},
});
console.log(33, item);
};
//
const toAdd = () => {
router.push({
path: `/product/cardList/add`,
query: route.query,
});
};
const handleDelete = async (id: number[]) => {
await batchDeletion([id]);
getList();
ElMessage.success(t('success'));
}; };
</script> </script>
@ -79,13 +121,11 @@ const handleDelete = async (ids: number[]) => {
} }
.products { .products {
li { li {
position: relative; @apply relative p-5 mb-5 rounded-[10px] cursor-pointer border border-solid;
width: 220px;
padding: 20px;
margin-bottom: 20px;
background: url(../../assets/images/10.png) 0 0/100% 100% no-repeat; background: url(../../assets/images/10.png) 0 0/100% 100% no-repeat;
border-radius: 10px; &.active {
cursor: pointer; @apply border-[#CAE0FF];
}
} }
.del { .del {
position: absolute; position: absolute;

@ -102,32 +102,45 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue'; import { ref, computed, watch, onMounted } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import type { TabsPaneContext } from 'element-plus'; import type { TabsPaneContext } from 'element-plus';
import { primaryTypeOfGuarantee, bankingProductsList } from '@/api/bank'; import { findById } from '@/api/bank';
import { useRouter, useRoute } from 'vue-router';
defineProps({ modelValue: { type: Object, required: true } }); defineProps({ modelValue: { type: Object, required: true } });
defineEmits({ 'update:form': null }); defineEmits({ 'update:form': null });
const router = useRouter();
const route = useRoute();
const id = computed(() => +route.query.id);
const curTab = ref<string>('tab1'); const curTab = ref<string>('tab1');
const data = ref<any>();
// tab // tab
const tabChange = (tab: TabsPaneContext, event: Event) => { const tabChange = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event); console.log(tab, event);
}; };
// //
const getGuarantee = async () => { const getDetail = async () => {
if (id.value) {
try { try {
const { data } = await primaryTypeOfGuarantee(); const { data } = await findById(id.value);
guarantees.value = data; data.value = data;
} finally { } finally {
} }
}
}; };
onMounted(() => { watch(
// getGuarantee(); () => route.query,
// fetchData(); () => {
}); getDetail();
},
{
immediate: true,
},
);
onMounted(() => {});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

@ -0,0 +1,80 @@
<template>
<div>
<el-tabs v-model="curTab"
@tab-click="tabChange">
<el-tab-pane label="产品要素"
name="tab1">
<div class="forms">
<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>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import type { TabsPaneContext } from 'element-plus';
import { findById } from '@/api/bank';
import { useRouter, useRoute } from 'vue-router';
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 data = ref<any>();
// tab
const tabChange = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event);
};
//
const getDetail = async () => {
if (id.value) {
try {
const { data } = await findById(id.value);
data.value = data;
} finally {
}
}
};
watch(
() => route.query,
() => {
getDetail();
},
{
immediate: true,
},
);
onMounted(() => {});
</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;
}
}
</style>

@ -1,12 +1,14 @@
<template> <template>
<div class="block"> <div class="block">
<div class="flex justify-between items-center mb-5"> <div class="flex justify-between items-center mb-5">
<search v-model="params.keyWord"></search> <search v-model="params.keyWord"
@change="initList"></search>
<div class="filter"> <div class="filter">
<div class="select"> <div class="select">
<el-select v-model="params.guarantyStyleId" <el-select v-model="params.guarantyStyleId"
placeholder="担保方式" placeholder="担保方式"
size="large"> size="large"
@change="initList">
<el-option label="担保方式" <el-option label="担保方式"
value="" /> value="" />
<el-option v-for="item in guarantees" <el-option v-for="item in guarantees"
@ -21,7 +23,8 @@
<div class="select"> <div class="select">
<el-select v-model="params.status" <el-select v-model="params.status"
placeholder="产品进度" placeholder="产品进度"
size="large"> size="large"
@change="initList">
<el-option v-for="item in paces" <el-option v-for="item in paces"
:key="item.id" :key="item.id"
:label="item.name" :label="item.name"
@ -31,7 +34,8 @@
alt="" alt=""
class="icon" /> class="icon" />
</div> </div>
<div class="add-btn"> <div class="add-btn"
@click="toAdd">
<img src="@/assets/images/plus.png" <img src="@/assets/images/plus.png"
alt="" alt=""
class="icon" /> class="icon" />
@ -51,14 +55,22 @@
label="产品名称"></el-table-column> label="产品名称"></el-table-column>
<el-table-column prop="productNumber" <el-table-column prop="productNumber"
label="产品编号"></el-table-column> label="产品编号"></el-table-column>
<el-table-column prop="parentIds" <el-table-column prop="guarantyStyle"
label="担保方式"></el-table-column> label="担保方式"></el-table-column>
<el-table-column prop="loanCeiling" <el-table-column prop="loanCeiling"
label="最高额度/年利率/期限"></el-table-column> label="最高额度/年利率/期限">
<template #default="{ row }">
{{ row.loanCeiling + '万元/' + row.maximumAnnualInterestRate + '%/' + row.maximumTermOfLoan + '个月' }}
</template>
</el-table-column>
<el-table-column prop="createTime" <el-table-column prop="createTime"
label="创建日期"></el-table-column> label="创建日期"></el-table-column>
<el-table-column prop="status" <el-table-column prop="status"
label="产品进度"></el-table-column> label="产品进度">
<template #default="{ row }">
{{ getStatus(row.status) }}
</template>
</el-table-column>
<el-table-column prop="id" <el-table-column prop="id"
label="操作"> label="操作">
<template #default="{ row }"> <template #default="{ row }">
@ -69,7 +81,7 @@
@click="handleEdit(row.id)" @click="handleEdit(row.id)"
size="small">产品详情</el-button> size="small">产品详情</el-button>
<el-button type="text" <el-button type="text"
@click="handleEdit(row.id)" @click="handleDelete(row.id)"
size="small">删除</el-button> size="small">删除</el-button>
</template></el-table-column> </template></el-table-column>
</el-table> </el-table>
@ -78,8 +90,8 @@
:total="total" :total="total"
:page-sizes="pageSizes" :page-sizes="pageSizes"
:layout="pageLayout" :layout="pageLayout"
@size-change="fetchData()" @size-change="getList()"
@current-change="fetchData()" @current-change="getList()"
small small
background background
class="px-3 py-2 justify-end"></el-pagination> class="px-3 py-2 justify-end"></el-pagination>
@ -87,25 +99,28 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref, reactive, watch } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { perm } from '@/store/useCurrentUser'; import { perm } from '@/store/useCurrentUser';
import { pageSizes, pageLayout, toParams, resetParams } from '@/utils/common'; import { pageSizes, pageLayout, toParams, resetParams } from '@/utils/common';
import { primaryTypeOfGuarantee, bankingProductsList } from '@/api/bank'; import { primaryTypeOfGuarantee, bankingProductsList, batchDeletion } from '@/api/bank';
import Search from '@/components/Search.vue'; import Search from '@/components/Search.vue';
import { useRouter } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { getStatus } from '@/store/useProduct';
const { t } = useI18n(); const { t } = useI18n();
const params = ref<any>({ const router = useRouter();
const route = useRoute();
const params = reactive({
createDateSort: '', createDateSort: '',
guarantyStyleId: '', guarantyStyleId: '',
keyWord: '', keyWord: '',
productType: '', productType: '',
status: '', status: '',
}); });
const router = useRouter(); params.productType = computed(() => +route.query.type);
const sort = ref<any>(); const sort = ref<any>();
const currentPage = ref<number>(1); const currentPage = ref<number>(1);
const pageSize = ref<number>(10); const pageSize = ref<number>(10);
@ -113,6 +128,10 @@ const total = ref<number>(0);
const table = ref<any>(); const table = ref<any>();
const guarantees = ref<Array<any>>([]); const guarantees = ref<Array<any>>([]);
const paces = ref<Array<any>>([ const paces = ref<Array<any>>([
{
id: '',
name: '产品进度',
},
{ {
id: 1, id: 1,
name: '配置风控', name: '配置风控',
@ -135,9 +154,7 @@ const paces = ref<Array<any>>([
}, },
]); ]);
const list = ref<Array<any>>([]); const list = ref<Array<any>>([]);
const selection = ref<Array<any>>([]);
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
const beanId = ref<number>();
// //
const getGuarantee = async () => { const getGuarantee = async () => {
try { try {
@ -147,46 +164,54 @@ const getGuarantee = async () => {
} }
}; };
// //
const fetchData = async () => { const getList = async () => {
loading.value = true; loading.value = true;
try { try {
const { data } = await bankingProductsList({ pageNum: currentPage.value, pageSize: pageSize.value, ...toParams(params.value) }); const { data } = await bankingProductsList({ pageNum: currentPage.value, pageSize: pageSize.value, ...toParams(params) });
list.value = data.message.records; list.value = data.message.records;
total.value = data.message.total; total.value = data.message.total;
} finally { } finally {
loading.value = false; loading.value = false;
} }
}; };
//
const initList = async () => {
currentPage.value = 1;
getList();
};
onMounted(() => { onMounted(() => {
getGuarantee(); getGuarantee();
fetchData(); getList();
}); });
//
watch([() => params.keyWord, () => route.query.type], initList);
const handleSort = ({ column, prop, order }: { column: any; prop: string; order: string }) => { const handleSort = ({ column, prop, order }: { column: any; prop: string; order: string }) => {
if (prop) { if (prop) {
sort.value = (column.sortBy ?? prop) + (order === 'descending' ? '_desc' : ''); sort.value = (column.sortBy ?? prop) + (order === 'descending' ? '_desc' : '');
} else { } else {
sort.value = undefined; sort.value = undefined;
} }
fetchData(); getList();
};
//
const toAdd = () => {
router.push({
path: `/product/cardList/add`,
query: route.query,
});
}; };
// //
const toCardList = () => { const toCardList = () => {
router.push('/product/cardList/config'); router.push('/product/cardList/config');
}; };
const handleAdd = () => { const handleDelete = async (id: number[]) => {
beanId.value = undefined; await batchDeletion([id]);
}; getList();
const handleEdit = (id: number) => {
beanId.value = id;
};
const handleDelete = async (ids: number[]) => {
await deleteUser(ids);
fetchData();
ElMessage.success(t('success')); ElMessage.success(t('success'));
}; };
const deletable = (bean: any) => bean.id > 1;
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

Loading…
Cancel
Save