选择关卡、角色等

V0.1
yujialong 1 year ago
parent 222946ce19
commit e39ab950f3
  1. 4
      .env
  2. 4
      src/api/bank.ts
  3. 36
      src/api/model.ts
  4. BIN
      src/assets/images/role/2.png
  5. BIN
      src/assets/images/role/3.png
  6. BIN
      src/assets/images/role/4.png
  7. BIN
      src/assets/images/role/5.png
  8. BIN
      src/assets/images/role/6.png
  9. BIN
      src/assets/images/role/7.png
  10. BIN
      src/assets/images/role/8.png
  11. BIN
      src/assets/images/role/committee.png
  12. BIN
      src/assets/images/role/committee1.png
  13. BIN
      src/assets/images/role/first.png
  14. BIN
      src/assets/images/role/icon/选择关卡/连接线/竖直.png
  15. BIN
      src/assets/images/role/icon/选择角色/个人客户经理_hig.png
  16. BIN
      src/assets/images/role/icon/选择角色/个人客户经理_nor.png
  17. BIN
      src/assets/images/role/icon/选择角色/企业客户经理_hig.png
  18. BIN
      src/assets/images/role/icon/选择角色/企业客户经理_nor.png
  19. BIN
      src/assets/images/role/icon/选择角色/保险产品经理_hig.png
  20. BIN
      src/assets/images/role/icon/选择角色/保险产品经理_nor.png
  21. BIN
      src/assets/images/role/icon/选择角色/保险市场_hig.png
  22. BIN
      src/assets/images/role/icon/选择角色/保险市场_nor.png
  23. BIN
      src/assets/images/role/icon/选择角色/信息员_hig.png
  24. BIN
      src/assets/images/role/icon/选择角色/信息员_nor.png
  25. BIN
      src/assets/images/role/icon/选择角色/信贷审批员_hig.png
  26. BIN
      src/assets/images/role/icon/选择角色/信贷审批员_nor.png
  27. BIN
      src/assets/images/role/icon/选择角色/信贷审查员_hig.png
  28. BIN
      src/assets/images/role/icon/选择角色/信贷审查员_nor.png
  29. BIN
      src/assets/images/role/icon/选择角色/基金产品经理_hig.png
  30. BIN
      src/assets/images/role/icon/选择角色/基金产品经理_nor.png
  31. BIN
      src/assets/images/role/icon/选择角色/基金市场_hig.png
  32. BIN
      src/assets/images/role/icon/选择角色/基金市场_nor.png
  33. BIN
      src/assets/images/role/icon/选择角色/弹窗/文件.png
  34. BIN
      src/assets/images/role/icon/选择角色/弹窗/日期.png
  35. BIN
      src/assets/images/role/icon/选择角色/我的商品_hig.png
  36. BIN
      src/assets/images/role/icon/选择角色/我的商品_nor.png
  37. BIN
      src/assets/images/role/icon/选择角色/放贷专员_hig.png
  38. BIN
      src/assets/images/role/icon/选择角色/放贷专员_nor.png
  39. BIN
      src/assets/images/role/icon/选择角色/时间_hig.png
  40. BIN
      src/assets/images/role/icon/选择角色/柜面人员_hig.png
  41. BIN
      src/assets/images/role/icon/选择角色/柜面人员_nor.png
  42. BIN
      src/assets/images/role/icon/选择角色/申请表_hig.png
  43. BIN
      src/assets/images/role/icon/选择角色/申请表_nor.png
  44. BIN
      src/assets/images/role/icon/选择角色/贷后管理员_hig.png
  45. BIN
      src/assets/images/role/icon/选择角色/贷后管理员_nor.png
  46. BIN
      src/assets/images/role/icon/选择角色/银行市场_hig.png
  47. BIN
      src/assets/images/role/icon/选择角色/银行市场_nor.png
  48. BIN
      src/assets/images/role/product.png
  49. BIN
      src/assets/images/role/product1.png
  50. BIN
      src/assets/images/role/riskControl.png
  51. BIN
      src/assets/images/role/riskControl1.png
  52. BIN
      src/assets/images/role/second.png
  53. BIN
      src/assets/images/role/third.png
  54. 93
      src/components/Panel/index.vue
  55. 39
      src/layout/components/AppHeader.vue
  56. 5
      src/store/useCurrentUser.ts
  57. 16
      src/utils/request.ts
  58. 28
      src/views/Home.vue
  59. 53
      src/views/Role.vue
  60. 3
      src/views/product/bank/Add.vue
  61. 17
      src/views/product/bank/CardList.vue
  62. 3
      src/views/product/bank/Config.vue
  63. 128
      src/views/product/strategy/150.vue
  64. 257
      src/views/product/strategy/151.vue
  65. 532
      src/views/product/strategy/Add.vue
  66. 131
      src/views/product/strategy/Approve.vue
  67. 22
      src/views/product/strategy/CardList.vue
  68. 21
      src/views/product/strategy/Detail.vue
  69. 181
      src/views/product/strategy/Info.vue

@ -2,7 +2,7 @@ VITE_APP_TITLE=金融产品设计及数字化营销沙盘
VITE_PORT=9520 VITE_PORT=9520
VITE_PROXY=http://192.168.31.125:8080 VITE_PROXY=http://192.168.31.125:8080
VITE_PUBLIC_PATH=./ VITE_PUBLIC_PATH=./
#VITE_BASE_API=http://192.168.31.217:9000 VITE_BASE_API=http://192.168.31.217:9000
VITE_BASE_API=http://121.37.12.51 # VITE_BASE_API=http://121.37.12.51
VITE_I18N_LOCALE=zh-cn VITE_I18N_LOCALE=zh-cn
VITE_I18N_FALLBACK_LOCALE=zh-cn VITE_I18N_FALLBACK_LOCALE=zh-cn

@ -18,7 +18,3 @@ export const riskById = async (id: number): Promise<any> => (await axios.post(`/
export const examineAndApprove = async (id: number | string, opinionDescription: string, status: number, approvalTime: string): Promise<any> => 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; (await axios.post(`/product/product/bank/products/examineAndApprove?id=${id}&opinionDescription=${opinionDescription}&status=${status}&approvalTime=${approvalTime}`)).data;
export const update = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/product/bank/products/update`, data)).data; export const update = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/product/bank/products/update`, data)).data;
export const accessStrategyGovernmentBlacklistFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyGovernmentBlacklist/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyGovernmentBlacklist = async (data: Record<string, any>[]): Promise<any> =>
(await axios.post(`/product/accessStrategyGovernmentBlacklist/saveOrUpdate`), data).data;

@ -0,0 +1,36 @@
import axios from '@/utils/request';
export const accessStrategyGovernmentBlacklistFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyGovernmentBlacklist/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyGovernmentBlacklistSave = async (data: Record<string, any>[]): Promise<any> =>
(await axios.post(`/product/accessStrategyGovernmentBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyEnterpriseBlacklistFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyEnterpriseBlacklist/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyEnterpriseBlacklistSave = async (data: Record<string, any>[]): Promise<any> =>
(await axios.post(`/product/accessStrategyEnterpriseBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyAntiFraudStrategyFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyAntiFraudStrategy/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyAntiFraudStrategySave = async (data: Record<string, any>[]): Promise<any> =>
(await axios.post(`/product/accessStrategyAntiFraudStrategy/saveOrUpdate`, data)).data;
export const accessStrategyBusinessBlacklistFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyBusinessBlacklist/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyBusinessBlacklistSave = async (data: Record<string, any>[]): Promise<any> =>
(await axios.post(`/product/accessStrategyBusinessBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyCreditBlacklistFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyCreditBlacklist/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyCreditBlacklistSave = async (data: Record<string, any>[]): Promise<any> =>
(await axios.post(`/product/accessStrategyCreditBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyInlineBlacklistFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyInlineBlacklist/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyInlineBlacklistSave = async (data: Record<string, any>[]): Promise<any> =>
(await axios.post(`/product/accessStrategyInlineBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyNegativeIndustryStrategyFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyNegativeIndustryStrategy/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyNegativeIndustryStrategySave = async (data: Record<string, any>[]): Promise<any> =>
(await axios.post(`/product/accessStrategyNegativeIndustryStrategy/saveOrUpdate`, data)).data;

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1016 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 960 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1013 B

@ -17,7 +17,7 @@
style="margin-left: 10px"></i> style="margin-left: 10px"></i>
</el-tooltip> </el-tooltip>
</div> </div>
<el-select v-model="projectId" <el-select v-model="param.projectId"
placeholder="请选择" placeholder="请选择"
class="select" class="select"
:disabled="per != 0" :disabled="per != 0"
@ -96,13 +96,13 @@
label="分值" label="分值"
width="60" width="60"
align="center"></el-table-column> align="center"></el-table-column>
<template v-if="!competitionId"> <template v-if="!param.competitionId">
<el-table-column label="结果" <el-table-column label="结果"
width="60" width="60"
align="center"> align="center">
<template v-slot="scope"> <template v-slot="scope">
<template v-if="isSubmit"> <template v-if="isSubmit">
<template v-if="!competitionId"> <template v-if="!param.competitionId">
<i v-if="scope.row.finishedResult" <i v-if="scope.row.finishedResult"
class="el-icon-check right"></i> class="el-icon-check right"></i>
<i v-else <i v-else
@ -117,7 +117,7 @@
width="60" width="60"
align="center"> align="center">
<template v-slot="scope"> <template v-slot="scope">
<template v-if="isSubmit">{{ competitionId ? '-' : scope.row.examScore }}</template> <template v-if="isSubmit">{{ param.competitionId ? '-' : scope.row.examScore }}</template>
</template> </template>
</el-table-column> </el-table-column>
</template> </template>
@ -196,29 +196,27 @@
<div class="toggle-panel absolute w-[40px] h-[175px] bg-[url('@/assets/images/panel/right.png')] bg-[length:100%_100%] bg-no-repeat cursor-pointer" <div class="toggle-panel absolute w-[40px] h-[175px] bg-[url('@/assets/images/panel/right.png')] bg-[length:100%_100%] bg-no-repeat cursor-pointer"
:class="{ active: visible }" :class="{ active: visible }"
@click="visible = !visible"> @click="visible = !visible"></div>
</div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, toRefs } from 'vue'; import { ref, reactive, onMounted, toRefs } from 'vue';
import { pageStuAssessment, getProjectBySystemId, getProjectDetail, getDetailById, getCompetition } from '@/api/system'; import { pageStuAssessment, getProjectBySystemId, getProjectDetail, getDetailById, getCompetition } from '@/api/system';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { ElMessage, ElMessageBox } from 'element-plus'; import { ElMessage, ElMessageBox } from 'element-plus';
import Cookie from 'js-cookie'; import Cookies from 'js-cookie';
import { mavonEditor } from 'mavon-editor';
import util from '@/libs/util'; import util from '@/libs/util';
import Setting from '@/setting'; import Setting from '@/setting';
// import { mavonEditor } from 'mavon-editor' import 'mavon-editor/dist/css/index.css';
// import 'mavon-editor/dist/css/index.css'
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const projectId = ref<string | number>(+route.query.projectId); const param = reactive<Record<string, any>>(route.query);
const { systemId, classId, cid, assessmentId, competitionId, stageId, teamId, mallId } = toRefs(route.query);
const curSystemId = ref<number>(1); const curSystemId = ref<number>(1);
const per = ref<number>(0); // (0 1 2) const per = ref<number>(0); // (0 1 2)
const isSubmit = ref<boolean>(Cookie.get('st-isSubmit') === 'true'); // const isSubmit = ref<boolean>(Cookies.get('st-isSubmit') === 'true'); //
const entryTime = ref<any>(new Date()); const entryTime = ref<any>(new Date());
const visible = ref<boolean>(true); const visible = ref<boolean>(true);
const grade = ref<string | number>('00'); const grade = ref<string | number>('00');
@ -230,7 +228,7 @@ const minutes = ref<number | string>(0);
const hour = ref<number | string>(0); const hour = ref<number | string>(0);
const projectList = ref<Record<string, any>[]>([]); const projectList = ref<Record<string, any>[]>([]);
const pd = ref<Record<string, any>>({}); const pd = ref<Record<string, any>>({});
const hintOpen = ref<string>(''); const hintOpen = ref<boolean>(false);
const points = ref<Record<string, any>[]>([]); const points = ref<Record<string, any>[]>([]);
const judgmentId = ref<string | number>(''); const judgmentId = ref<string | number>('');
const curReq = ref<Record<string, any>[]>([]); const curReq = ref<Record<string, any>[]>([]);
@ -239,15 +237,42 @@ const pannelTab = ref<string>('first');
const isSelected = ref<boolean>(false); // true const isSelected = ref<boolean>(false); // true
const statusTimer = ref<any>(null); const statusTimer = ref<any>(null);
const reportId = ref<string | number>(''); const reportId = ref<string | number>('');
let countVal = <any>''; const countVal = ref<any>('');
if (param.token) {
// urlcookiecookie
param.token && Cookies.set('sand-token', param.token);
param.projectId && Cookies.set('sand-projectId', param.projectId);
param.systemId && Cookies.set('sand-systemId', param.systemId);
param.classId && Cookies.set('sand-classId', param.classId);
param.cid && Cookies.set('sand-cid', param.cid);
param.assessmentId && Cookies.set('sand-assessmentId', param.assessmentId);
param.competitionId && Cookies.set('sand-competitionId', param.competitionId);
param.stageId && Cookies.set('sand-stageId', param.stageId);
param.teamId && Cookies.set('sand-teamId', param.teamId);
param.mallId && Cookies.set('sand-mallId', param.mallId);
param.endTime && Cookies.set('sand-referrer', param.endTime);
param.referrer && Cookies.set('sand-referrer', param.referrer);
} else {
param.systemId = Cookies.get('sand-systemId');
param.projectId = Cookies.get('sand-projectId');
param.classId = Cookies.get('sand-classId');
param.cid = Cookies.get('sand-cid');
param.assessmentId = Cookies.get('sand-assessmentId');
param.competitionId = Cookies.get('sand-competitionId');
param.stageId = Cookies.get('sand-stageId');
param.teamId = Cookies.get('sand-teamId');
param.mallId = Cookies.get('sand-mallId');
param.endTime = Cookies.get('sand-endTime');
}
if (param.projectId) param.projectId = +param.projectId;
onMounted(() => { onMounted(() => {
per.value = assessmentId?.value ? 1 : competitionId?.value ? 2 : 0; per.value = param.assessmentId ? 1 : param.competitionId ? 2 : 0;
if (assessmentId.value) { if (param.assessmentId) {
getAssList(); getAssList();
} else { } else {
getList(); getList();
if (competitionId?.value) { if (param.competitionId) {
clearInterval(statusTimer); clearInterval(statusTimer);
statusTimer.value = setInterval((_) => { statusTimer.value = setInterval((_) => {
getCompetitionStatus(); getCompetitionStatus();
@ -259,23 +284,21 @@ onMounted(() => {
// //
const getList = async () => { const getList = async () => {
const data = { const data = {
systemId: systemId.value, systemId: param.systemId,
cId: cid?.value ?? '', cId: param.cid ?? '',
mallId: mallId?.value, mallId: param.mallId,
permissions: per.value, permissions: per.value,
}; };
const { projects } = await getProjectBySystemId(data); const { projects } = await getProjectBySystemId(data);
projectList.value = projects; projectList.value = projects;
console.log('🚀 ~ file: index.vue:280 ~ getList ~ projectList.value:', projectList.value); if (!per.value && !param.projectId) param.projectId = projects[0]?.projectId ?? 0; //
if (!per.value && !projectId.value) projectId.value = projects[0]?.projectId ?? 0; //
getProDetail(); getProDetail();
}; };
// //
const getProDetail = () => { const getProDetail = async () => {
return new Promise(async (resolve, reject) => {
const res = await getProjectDetail({ const res = await getProjectDetail({
projectId: projectId.value, projectId: param.projectId,
stuAssessent: 1, stuAssessent: 1,
}); });
const points = res.projectJudgmentVos; const points = res.projectJudgmentVos;
@ -284,7 +307,7 @@ const getProDetail = () => {
if (per.value) { if (per.value) {
projectList.value = [ projectList.value = [
{ {
projectId: projectId.value, projectId: param.projectId,
projectName: project.projectName, projectName: project.projectName,
}, },
]; ];
@ -298,19 +321,17 @@ const getProDetail = () => {
const isPrac = per.value === 0; // const isPrac = per.value === 0; //
text.value = isPrac ? '已用' : '剩余'; text.value = isPrac ? '已用' : '剩余';
// //
if (!competitionId.value) { if (!param.competitionId) {
countVal = isPrac ? 0 : (new Date(endTime.value).getTime() - Date.now()) / 1000; // 0 countVal.value = isPrac ? 0 : (new Date(param.endTime).getTime() - Date.now()) / 1000; // 0
startCount(); startCount();
} }
resolve();
});
}; };
// isSubmit // isSubmit
// setSubmit(status) { // setSubmit(status) {
// this.isSubmit = status; // this.isSubmit = status;
// newmain.$emit('isSubmit', status); // newmain.$emit('isSubmit', status);
// Cookie.set('admin-isSubmit', status); // Cookies.set('admin-isSubmit', status);
// }, // },
// //
const getAssList = async () => { const getAssList = async () => {
@ -320,7 +341,7 @@ const getAssList = async () => {
}); });
let done = false; let done = false;
// reportIdclassIdclassId // reportIdclassIdclassId
if (list.find((e) => e.assessmentId == assessmentId.value && e.reportId && e.classId == classId.value)) { if (list.find((e) => e.assessmentId == param.assessmentId && e.reportId && e.classId == param.classId)) {
done = true; done = true;
setSubmit(true); setSubmit(true);
ElMessage.error('你已经提交过该考核!'); ElMessage.error('你已经提交过该考核!');
@ -336,7 +357,7 @@ const getAssList = async () => {
const getAssStatus = async () => { const getAssStatus = async () => {
// //
if (!isSubmit.value) { if (!isSubmit.value) {
const { data } = await getDetailById(assessmentId.value); const { data } = await getDetailById(param.assessmentId);
const done = data ? data.status === 2 : false; // (0 1 2) const done = data ? data.status === 2 : false; // (0 1 2)
// //
if (done) { if (done) {
@ -353,10 +374,10 @@ const getAssStatus = async () => {
const getCompetitionStatus = async () => { const getCompetitionStatus = async () => {
// //
if (!isSubmit.value) { if (!isSubmit.value) {
const { competition } = await getCompetition(competitionId.value); const { competition } = await getCompetition(param.competitionId);
const stages = competition.competitionStage; const stages = competition.competitionStage;
if (stages) { if (stages) {
const stage = stages.find((e) => e.stageId == stageId.value); const stage = stages.find((e) => e.stageId == param.stageId);
const endTime = new Date(stage.endTime).getTime(); const endTime = new Date(stage.endTime).getTime();
const now = Date.now(); const now = Date.now();
// //

@ -1,21 +1,31 @@
<template> <template>
<div class="flex justify-between items-center w-full py-6 px-5 overflow-hidden bg-transparent"> <div class="flex justify-between items-center w-full py-6 px-5 overflow-hidden bg-transparent">
<logo :collapse="collapse" /> <logo :collapse="collapse" />
<div>
<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"> <div class="inline-flex items-center">
<el-tooltip effect="light"
content="退出实训"
placement="bottom">
<img class="mr-3 cursor-pointer" <img class="mr-3 cursor-pointer"
src="@/assets/images/2.png" src="@/assets/images/2.png"
alt="" /> alt=""
@click="logout" />
</el-tooltip>
<el-tooltip effect="light"
content="返回关卡"
placement="bottom">
<img class="mr-3 cursor-pointer" <img class="mr-3 cursor-pointer"
src="@/assets/images/3.png" src="@/assets/images/3.png"
alt="" /> alt=""
@click="toLevel" />
</el-tooltip>
<el-tooltip effect="light"
content="返回选择角色"
placement="bottom">
<img class="cursor-pointer" <img class="cursor-pointer"
src="@/assets/images/4.png" src="@/assets/images/4.png"
alt="" /> alt=""
@click="toRole" />
</el-tooltip>
</div> </div>
</div> </div>
</template> </template>
@ -23,11 +33,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, computed } from 'vue'; import { ref, onMounted, computed } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { setCookieLocale, getSessionSiteId, setSessionSiteId } from '@/utils/common';
import { toTree, flatTree } from '@/utils/tree';
// import { querySiteList } from '@/api/bank';
import { currentUser, perm, logout } from '@/store/useCurrentUser'; import { currentUser, perm, logout } from '@/store/useCurrentUser';
import { appState, toggleSidebar } from '@/store/useAppState'; import Cookies from 'js-cookie';
import Logo from './Logo.vue'; import Logo from './Logo.vue';
const router = useRouter(); const router = useRouter();
@ -42,6 +49,14 @@ const handleLogout = () => {
// router.push(`/login?redirect=${route.fullPath}`); // router.push(`/login?redirect=${route.fullPath}`);
window.location.reload(); window.location.reload();
}; };
//
const toLevel = () => {
router.push('/');
};
//
const toRole = () => {
router.push(`/role?levelId=${Cookies.get('sand-level')}`);
};
const passwordFormVisible = ref<boolean>(false); const passwordFormVisible = ref<boolean>(false);
</script> </script>

@ -1,6 +1,7 @@
import { reactive, readonly } from 'vue'; import { reactive, readonly } from 'vue';
import { RouteRecordRaw } from 'vue-router'; import { RouteRecordRaw } from 'vue-router';
import { setAccessToken, removeAccessToken, setAccessAt, setSessionTimeout, removeSessionTimeout } from '@/utils/auth'; import { removeAccessToken } from '@/utils/auth';
import Cookies from 'js-cookie';
export interface CurrentUser { export interface CurrentUser {
username?: string; username?: string;
@ -14,7 +15,7 @@ const state = reactive<CurrentUser>({});
export const logout = (): void => { export const logout = (): void => {
removeAccessToken(); removeAccessToken();
removeSessionTimeout(); window.location.href = decodeURIComponent(Cookies.get('sand-referrer'));
}; };
export const hasCurrentUser = (): boolean => state.username !== undefined; export const hasCurrentUser = (): boolean => state.username !== undefined;

@ -1,9 +1,8 @@
import { h } from 'vue'; import { h } from 'vue';
import axios from 'axios'; import axios from 'axios';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox, ElMessage } from 'element-plus';
import { getAuthHeaders, setAccessAt } from '@/utils/auth'; import { getAuthHeaders, setAccessAt } from '@/utils/auth';
import { getSiteHeaders } from '@/utils/common';
import i18n from '@/i18n'; import i18n from '@/i18n';
const service = axios.create({ const service = axios.create({
@ -44,18 +43,7 @@ service.interceptors.response.use(
message: h('div', null, [h('p', { class: 'text-lg' }, t('error.forbidden')), h('p', { class: 'mt-2' }, message)]), message: h('div', null, [h('p', { class: 'text-lg' }, t('error.forbidden')), h('p', { class: 'mt-2' }, message)]),
}); });
} else { } else {
ElMessageBox({ ElMessage.error(message);
title: t('error.title'),
message: h('div', null, [
h('h', null, [h('span', { class: 'text-4xl' }, status), h('span', { class: ['ml-2', 'text-xl'] }, error)]),
h('p', { class: 'mt-2' }, dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')),
h('p', { class: 'mt-2' }, path),
h('p', { class: 'mt-2' }, message),
h('p', { class: 'mt-2' }, exception),
h('pre', { class: 'mt-2' }, [h('code', { class: ['whitespace-pre-wrap'] }, trace)]),
]),
customClass: 'msgbox-error',
});
} }
return Promise.reject(error); return Promise.reject(error);
}, },

@ -2,15 +2,14 @@
<div class="flex justify-between items-center h-[64px] px-5 bg-white"> <div class="flex justify-between items-center h-[64px] px-5 bg-white">
<h1>金融产品设计及数字化营销沙盘系统</h1> <h1>金融产品设计及数字化营销沙盘系统</h1>
<div class="inline-flex items-center"> <div class="inline-flex items-center">
<el-tooltip effect="light"
content="退出实训"
placement="bottom">
<img class="mr-3 cursor-pointer" <img class="mr-3 cursor-pointer"
src="@/assets/images/level/1.png" src="@/assets/images/level/1.png"
alt="" /> alt=""
<img class="mr-3 cursor-pointer" @click="logout" />
src="@/assets/images/level/2.png" </el-tooltip>
alt="" />
<img class="cursor-pointer"
src="@/assets/images/level/3.png"
alt="" />
</div> </div>
</div> </div>
<div class="relative min-h-[calc(100vh-64px)] pt-5 pl-5 bg-[url('@/assets/images/level/4.png')] bg-[length:100%_100%] bg-no-repeat"> <div class="relative min-h-[calc(100vh-64px)] pt-5 pl-5 bg-[url('@/assets/images/level/4.png')] bg-[length:100%_100%] bg-no-repeat">
@ -68,9 +67,12 @@ import { checkPointList } from '@/api/judgment';
import Panel from '@/components/Panel/index.vue'; import Panel from '@/components/Panel/index.vue';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { logout } from '@/store/useCurrentUser';
import Cookies from 'js-cookie';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const { token, referrer } = route.query;
const collected = ref<boolean>(false); const collected = ref<boolean>(false);
const curLevel = ref<number | string>(''); const curLevel = ref<number | string>('');
const levels = ref<Record<string, any>[]>([]); const levels = ref<Record<string, any>[]>([]);
@ -85,15 +87,17 @@ const selecLevel = (item: Record<string, any>) => {
}; };
// //
const toRole = () => { const toRole = () => {
curLevel.value if (curLevel.value) {
? router.push({ Cookies.set('sand-level', curLevel.value);
router.push({
path: `/role`, path: `/role`,
query: { query: {
...route.query,
levelId: curLevel.value, levelId: curLevel.value,
}, },
}) });
: ElMessage.error('请选择关卡!'); } else {
ElMessage.error('请选择关卡!');
}
}; };
onMounted(() => { onMounted(() => {
getLevel(); getLevel();

@ -1,6 +1,36 @@
<template> <template>
<div class="min-h-[100vh] bg-[url('@/assets/images/role/bg.png')] bg-[length:100%_auto] bg-no-repeat"></div> <div class="flex justify-between items-center h-[64px] px-5 bg-white">
<div class="fixed top-4 right-[80px]"> <h1>金融产品设计及数字化营销沙盘系统</h1>
<div class="inline-flex items-center">
<el-tooltip effect="light"
content="退出实训"
placement="bottom">
<img class="mr-3 cursor-pointer"
src="@/assets/images/level/1.png"
alt=""
@click="logout" />
</el-tooltip>
<el-tooltip effect="light"
content="返回关卡"
placement="bottom">
<img class="mr-3 cursor-pointer"
src="@/assets/images/level/2.png"
alt=""
@click="toLevel" />
</el-tooltip>
</div>
</div>
<div class="relative min-h-[calc(100vh-64px)] bg-[url('@/assets/images/role/bg.png')] bg-[length:100%_auto] bg-no-repeat">
<div class="absolute top-5 left-[18px] w-[204px] h-[68px] bg-[url('@/assets/images/role/2.png')] bg-[length:100%_100%] bg-no-repeat"></div>
<div class="role top-[310px] left-[340px] bg-[url('@/assets/images/role/product.png')] hover:bg-[url('@/assets/images/role/product1.png')]"
@click="selecRole(41)"></div>
<div class="role top-[220px] left-[490px] bg-[url('@/assets/images/role/committee.png')] hover:bg-[url('@/assets/images/role/committee1.png')]"
@click="selecRole(42)"></div>
<div class="role top-[140px] left-[630px] bg-[url('@/assets/images/role/riskControl.png')] hover:bg-[url('@/assets/images/role/riskControl1.png')]"
@click="selecRole(43)"></div>
</div>
<div class="fixed top-[80px] right-[80px]">
<div class="flex items-center h-[60px] px-4 rounded-tl-[20px] rounded-tr-[20px]" <div class="flex items-center h-[60px] px-4 rounded-tl-[20px] rounded-tr-[20px]"
style="background: linear-gradient(180deg, #7ebaff 0%, #0076ff 100%)"> style="background: linear-gradient(180deg, #7ebaff 0%, #0076ff 100%)">
<div class="w-[112px] h-[28px] bg-[url('@/assets/images/role/1.png')] bg-[length:100%_100%] bg-no-repeat"></div> <div class="w-[112px] h-[28px] bg-[url('@/assets/images/role/1.png')] bg-[length:100%_100%] bg-no-repeat"></div>
@ -43,7 +73,11 @@
import { ref, onMounted } from 'vue'; import { ref, onMounted } from 'vue';
import { checkPointList } from '@/api/judgment'; import { checkPointList } from '@/api/judgment';
import Panel from '@/components/Panel/index.vue'; import Panel from '@/components/Panel/index.vue';
import { useRouter, useRoute } from 'vue-router';
import { logout } from '@/store/useCurrentUser';
const router = useRouter();
const route = useRoute();
const collected = ref<boolean>(false); const collected = ref<boolean>(false);
const curLevel = ref<number | string>(''); const curLevel = ref<number | string>('');
const levels = ref<Record<string, any>[]>([]); const levels = ref<Record<string, any>[]>([]);
@ -116,12 +150,16 @@ const getLevel = async () => {
const { data } = await checkPointList(1); const { data } = await checkPointList(1);
levels.value = data; levels.value = data;
}; };
// //
const selecLevel = (item: Record<string, any>) => { const selecRole = (id: number) => {
curLevel.value = item.id; router.push(`/product/index?type=0&i=1&role=${id}`);
};
//
const toLevel = () => {
router.push('/');
}; };
onMounted(() => { onMounted(() => {
getLevel(); // getLevel();
}); });
</script> </script>
@ -168,4 +206,7 @@ onMounted(() => {
} }
} }
} }
.role {
@apply absolute w-[172px] h-[48px] bg-[length:100%_100%] bg-no-repeat cursor-pointer transition;
}
</style> </style>

@ -310,6 +310,7 @@ import { useRouter, useRoute } from 'vue-router';
import { handleId } from '@/utils/common'; import { handleId } from '@/utils/common';
import { getStatus } from '@/store/useProduct'; import { getStatus } from '@/store/useProduct';
import Info from './Info.vue'; import Info from './Info.vue';
import Cookies from 'js-cookie';
const emit = defineEmits(['getList']); const emit = defineEmits(['getList']);
interface RuleForm { interface RuleForm {
@ -465,7 +466,7 @@ const submit = async (formEl: FormInstance | undefined) => {
// //
const addRecord = async (data: Record<string, any>, newId: number) => { const addRecord = async (data: Record<string, any>, newId: number) => {
const isEnterprise = data.productType === 1; const isEnterprise = data.productType === 1;
const preIds = `1,2,41,${data.productType ? 45 : 44},${newId}`; // 1id/44/45 const preIds = `1,${Cookies.get('sand-level')},41,${data.productType ? 45 : 44},${newId}`; // 1id/44/45
const lcRule = <Record<string, any>[]>[ const lcRule = <Record<string, any>[]>[
handleId(48, 1, data.productDefinition, preIds + ',48', 3), handleId(48, 1, data.productDefinition, preIds + ',48', 3),
handleId(49, 2, data.productName, preIds + ',49', 3), handleId(49, 2, data.productName, preIds + ',49', 3),

@ -39,30 +39,19 @@
</ul> </ul>
</div> </div>
<div class="right flex-1 px-5 pt-2"> <div class="right flex-1 px-5 pt-2">
<!-- <component :is="Config" <component :is="defineAsyncComponent(() => import('./' + action + '.vue'))"
v-model="form"></component> --> @getList="getList"></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>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'; import { computed, onMounted, ref, watch, defineAsyncComponent } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { Plus } from '@element-plus/icons-vue'; import { Plus } from '@element-plus/icons-vue';
import { bankingProductsList, batchDeletion } 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 { 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 router = useRouter();
const route = useRoute(); const route = useRoute();

@ -348,6 +348,7 @@ import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment'
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { handleId } from '@/utils/common'; import { handleId } from '@/utils/common';
import Info from './Info.vue'; import Info from './Info.vue';
import Cookies from 'js-cookie';
const emit = defineEmits(['getList']); const emit = defineEmits(['getList']);
interface RuleForm { interface RuleForm {
@ -547,7 +548,7 @@ const submit = async (formEl: FormInstance | undefined) => {
// //
const addRecord = async (data: Record<string, any>, newId: number) => { const addRecord = async (data: Record<string, any>, newId: number) => {
const isEnterprise = info.value.productType === 1; const isEnterprise = info.value.productType === 1;
const preIds = `1,2,42,${data.productType ? 71 : 70},${newId}`; // 1id/70/71 const preIds = `1,${Cookies.get('sand-level')},42,${data.productType ? 71 : 70},${newId}`; // 1id/70/71
const lcRule = <Record<string, any>[]>[]; const lcRule = <Record<string, any>[]>[];
// //

@ -38,10 +38,8 @@
<div class="w-[90px] "> <div class="w-[90px] ">
<el-select class="mx-2" <el-select class="mx-2"
v-model="row.had"> v-model="row.had">
<el-option label="有" <el-option value="有" />
value="1" /> <el-option value="无" />
<el-option label="无"
value="2" />
</el-select> </el-select>
</div> </div>
<span class="ml-2 whitespace-nowrap">缴纳过社保或公积金</span> <span class="ml-2 whitespace-nowrap">缴纳过社保或公积金</span>
@ -62,10 +60,8 @@
<span class="ml-2 whitespace-nowrap">,</span> <span class="ml-2 whitespace-nowrap">,</span>
<el-select class="w-[80px] ml-2" <el-select class="w-[80px] ml-2"
v-model="row.had"> v-model="row.had">
<el-option label="有" <el-option value="有" />
value="1" /> <el-option value="无" />
<el-option label="无"
value="2" />
</el-select> </el-select>
<span class="ml-2 whitespace-nowrap">固定资产</span> <span class="ml-2 whitespace-nowrap">固定资产</span>
</template> </template>
@ -117,13 +113,14 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, computed, watch, onMounted } from 'vue'; import { ref, computed, watch, onMounted } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { accessStrategyGovernmentBlacklistFind, accessStrategyGovernmentBlacklist } from '@/api/bank'; import { accessStrategyGovernmentBlacklistFind, accessStrategyGovernmentBlacklistSave } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment'; import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import type { TableColumnCtx } from 'element-plus'; import type { TableColumnCtx } from 'element-plus';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { handleId } from '@/utils/common'; import { handleId } from '@/utils/common';
import Cookies from 'js-cookie';
const emit = defineEmits(['getList']); const emit = defineEmits(['getList']);
@ -169,7 +166,6 @@ const getConfig = async () => {
had: '', had: '',
num: '', num: '',
ruleOne: '', ruleOne: '',
ruleThree: '',
ruleTwo: '', ruleTwo: '',
stRecordId: e.id, stRecordId: e.id,
}; };
@ -181,7 +177,6 @@ const getConfig = async () => {
} }
}); });
form.value = result; form.value = result;
console.log('🚀 ~ file: CardList.vue:68 ~ getList ~ list.value:', form.value);
}; };
// //
const getDetail = async () => { const getDetail = async () => {
@ -234,8 +229,8 @@ const span = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
onMounted(() => {}); onMounted(() => {});
// //
const submit = async () => { const submit = async () => {
const param = JSON.parse(JSON.stringify(form.value)); let param = JSON.parse(JSON.stringify(form.value));
param.map((e) => { param.map((e, i) => {
e.corporateMajorityHitRejected = +e.corporateMajorityHitRejected; e.corporateMajorityHitRejected = +e.corporateMajorityHitRejected;
e.mateHitRejected = +e.mateHitRejected; e.mateHitRejected = +e.mateHitRejected;
e.otherFamilyMembersHitRejected = +e.otherFamilyMembersHitRejected; e.otherFamilyMembersHitRejected = +e.otherFamilyMembersHitRejected;
@ -243,12 +238,26 @@ const submit = async () => {
e.personalHitBlacklist = +e.personalHitBlacklist; e.personalHitBlacklist = +e.personalHitBlacklist;
if (e.stRecordId == 161 || e.stRecordId == 164) { if (e.stRecordId == 161 || e.stRecordId == 164) {
if (e.span) { if (e.span) {
//
param[i - 1].ruleTwo = e.symbol + e.num;
} else { } else {
e.ruleOne = e.symbol + e.num; e.ruleOne = e.symbol + e.num;
} }
} else if (e.stRecordId == 167) {
if (e.span) {
//
param[i - 1].ruleTwo = e.had;
} else {
e.ruleOne = e.symbol + e.num + ',' + e.had;
} }
}
});
param = param.filter((e) => !e.span);
const recordParam = JSON.parse(JSON.stringify(param));
param.map((e) => {
delete e.recordChildren;
}); });
const { message } = await accessStrategyGovernmentBlacklist(param); const { message } = await accessStrategyGovernmentBlacklistSave(recordParam);
// addRecord(param, message); // addRecord(param, message);
ElMessage.success('提交成功!'); ElMessage.success('提交成功!');
@ -256,83 +265,28 @@ const submit = async () => {
}; };
// //
const addRecord = async (data: Record<string, any>, newId: number) => { const addRecord = async (data: Record<string, any>, newId: number) => {
const isEnterprise = info.value.productType === 1; const preIds = `1,${Cookies.get('sand-level')},42,${newId}`; // 1id
const preIds = `1,2,42,${newId}`; // 1id const rule = <Record<string, any>[]>[];
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( data.map((e, i) => {
handleId(132, 56, data.dueDiligenceMode, preIds + ',115,132', 1), if (e.stRecordId == 161 || e.stRecordId == 164) {
handleId(133, 57, data.dueDiligenceContent, preIds + ',115,133', 1), e.recordChildren.map((n, j) => {
handleId(134, 58, data.reviewContent, preIds + ',116,134', 1), rule.push(handleId(n.id, e.subjectId, j ? e.ruleTwo : e.ruleOne, preIds + ',' + e.id + ',' + n.id, 5));
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));
} }
const temp = [];
e.personalHitBlacklist && temp.push(300);
e.mateHitRejected && temp.push(301);
e.parentsHitRejected && temp.push(302);
e.otherFamilyMembersHitRejected && temp.push(303);
e.corporateMajorityHitRejected && temp.push(304);
rule.push(handleId(e.id, e.subjectId, temp.join(), preIds + ',' + e.id, 1));
});
await addOperation({ await addOperation({
parentId: preIds, parentId: preIds,
lcJudgmentRuleReq: lcRule, lcJudgmentRuleReq: rule,
projectId: 1, projectId: 1,
}); });
}; };

@ -0,0 +1,257 @@
<template>
<el-table class="c-table"
:data="form"
:max-height="height"
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 value="有" />
<el-option value="无" />
</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 value="有" />
<el-option value="无" />
</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="160"
align="center">
<template #default="{ row }">
<el-checkbox v-model="row.personalHitBlacklist"></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, computed, watch, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { accessStrategyGovernmentBlacklistFind, accessStrategyGovernmentBlacklistSave } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import type { TableColumnCtx } from 'element-plus';
import { useRouter, useRoute } from 'vue-router';
import { handleId } from '@/utils/common';
import Cookies from 'js-cookie';
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: '',
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;
};
//
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;
}
onMounted(() => {});
//
const submit = async () => {
let param = JSON.parse(JSON.stringify(form.value));
param.map((e, i) => {
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) {
//
param[i - 1].ruleTwo = e.symbol + e.num;
} else {
e.ruleOne = e.symbol + e.num;
}
} else if (e.stRecordId == 167) {
if (e.span) {
//
param[i - 1].ruleTwo = e.had;
} else {
e.ruleOne = e.symbol + e.num + ',' + e.had;
}
}
});
param = param.filter((e) => !e.span);
const recordParam = JSON.parse(JSON.stringify(param));
param.map((e) => {
delete e.recordChildren;
});
const { message } = await accessStrategyGovernmentBlacklistSave(recordParam);
// addRecord(param, message);
ElMessage.success('提交成功!');
emit('getList', 1);
};
//
const addRecord = async (data: Record<string, any>, newId: number) => {
const preIds = `1,${Cookies.get('sand-level')},42,${newId}`; // 1id
const rule = <Record<string, any>[]>[];
data.map((e, i) => {
if (e.stRecordId == 161 || e.stRecordId == 164) {
e.recordChildren.map((n, j) => {
rule.push(handleId(n.id, e.subjectId, j ? e.ruleTwo : e.ruleOne, preIds + ',' + e.id + ',' + n.id, 5));
});
}
const temp = [];
e.personalHitBlacklist && temp.push(300);
e.mateHitRejected && temp.push(301);
e.parentsHitRejected && temp.push(302);
e.otherFamilyMembersHitRejected && temp.push(303);
e.corporateMajorityHitRejected && temp.push(304);
rule.push(handleId(e.id, e.subjectId, temp.join(), preIds + ',' + e.id, 1));
});
await addOperation({
parentId: preIds,
lcJudgmentRuleReq: rule,
projectId: 1,
});
};
</script>
<style lang="scss" scoped>
@import url(../../../styles/form.scss);
.c-table {
:deep(.el-input__inner) {
@apply px-2;
}
}
</style>

@ -1,532 +0,0 @@
<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}`; // 1id/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>

@ -1,131 +0,0 @@
<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}`; // 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>

@ -18,15 +18,8 @@
</ul> </ul>
</div> </div>
<div class="right flex-1 px-5 pt-2"> <div class="right flex-1 px-5 pt-2">
<!-- <component :is="Config" <component :is="defineAsyncComponent(() => import('./' + id + '.vue'))"
v-model="form"></component> --> @getList="getList"></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>
</div> </div>
</el-tab-pane> </el-tab-pane>
@ -39,18 +32,10 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, ref, watch } from 'vue'; import { computed, onMounted, ref, watch, defineAsyncComponent } from 'vue';
import { ElMessage } from 'element-plus';
import { Plus } from '@element-plus/icons-vue';
import type { TabsPaneContext } from 'element-plus'; import type { TabsPaneContext } from 'element-plus';
import { bankingProductsList, batchDeletion } from '@/api/bank';
import { getProcessInformationBasedOnRoles } from '@/api/judgment'; import { getProcessInformationBasedOnRoles } from '@/api/judgment';
import { useRouter, useRoute } from 'vue-router'; 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 router = useRouter();
const route = useRoute(); const route = useRoute();
@ -61,6 +46,7 @@ const loading = ref<boolean>(false);
const productType = computed(() => route.query.type); // / const productType = computed(() => route.query.type); // /
const role = computed(() => +route.query.role || 41); const role = computed(() => +route.query.role || 41);
const id = computed(() => +route.query.id); const id = computed(() => +route.query.id);
// //
const getList = async () => { const getList = async () => {
const { process } = await getProcessInformationBasedOnRoles(67); const { process } = await getProcessInformationBasedOnRoles(67);

@ -1,21 +0,0 @@
<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>

@ -1,181 +0,0 @@
<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…
Cancel
Save