Browse Source

根据3-4月根据客户要求进行页面改造

main
likunming 2 months ago
parent
commit
8e6c8c4b8d
  1. 2
      app.irbs/build-common.gradle
  2. 458
      build.gradle
  3. 5
      irbs.cust.rating/src/main/java/irbs/cust/rating/controller/CompanyRatingController.java
  4. 19
      irbs.cust.rating/src/main/java/irbs/cust/rating/controller/FinanceReportDetailController.java
  5. 99
      irbs.cust.rating/src/main/java/irbs/cust/rating/jpa/vo/FinanceReportDetailsVo.java
  6. 2
      irbs.cust.rating/src/main/java/irbs/cust/rating/service/CompanyRatingService.java
  7. 5
      irbs.cust.rating/src/main/java/irbs/cust/rating/service/FinanceReportDetailService.java
  8. 9
      irbs.cust.rating/src/main/java/irbs/cust/rating/service/impl/BusiProcessServiceImpl.java
  9. 26
      irbs.cust.rating/src/main/java/irbs/cust/rating/service/impl/CompanyRatingServiceImpl.java
  10. 120
      irbs.cust.rating/src/main/java/irbs/cust/rating/service/impl/FinanceReportDetailServiceImpl.java
  11. 8
      irbs.cust.rating/src/main/java/irbs/cust/rating/service/impl/MainScaleVersionServiceImpl.java
  12. 8
      irbs.defaultManager/src/main/java/irbs/defaultManager/service/impl/DefaultCognizanceServiceImpl.java
  13. 8
      irbs.defaultManager/src/main/java/irbs/defaultManager/service/impl/DefaultRebirthServiceImpl.java
  14. 5
      irbs.frontend/package.json
  15. 2
      irbs.frontend/src/i18n/messages_zh_CN.json
  16. 1
      irbs.frontend/src/menus/menus.json
  17. 33
      irbs.frontend/src/routes/routes.json
  18. 36
      irbs.frontend/src/views/components/LoadingDialog.vue
  19. 30
      irbs.frontend/src/views/custRating/CustRating.ts
  20. 2
      irbs.frontend/src/views/custRating/CustRating.vue
  21. 3
      irbs.frontend/src/views/custRating/RatingLevel.vue
  22. 61
      irbs.frontend/src/views/custRating/RatingLevelSlider.vue
  23. 69
      irbs.frontend/src/views/custRating/company/AnnotationButton.vue
  24. 13
      irbs.frontend/src/views/custRating/company/Apply.vue
  25. 37
      irbs.frontend/src/views/custRating/company/Content.vue
  26. 54
      irbs.frontend/src/views/custRating/company/CustSelectDialog.vue
  27. 57
      irbs.frontend/src/views/custRating/company/CustSelectGrid.vue
  28. 21
      irbs.frontend/src/views/custRating/company/NextButton.vue
  29. 93
      irbs.frontend/src/views/custRating/company/RatingDialog.vue
  30. 9
      irbs.frontend/src/views/custRating/company/RatingGrid.vue
  31. 287
      irbs.frontend/src/views/custRating/company/RatingManager.vue
  32. 71
      irbs.frontend/src/views/custRating/company/RatingPage.vue
  33. 58
      irbs.frontend/src/views/custRating/company/Step.vue
  34. 73
      irbs.frontend/src/views/custRating/company/TestCalcButton.vue
  35. 48
      irbs.frontend/src/views/custRating/company/WorkflowButton.vue
  36. 18
      irbs.frontend/src/views/custRating/company/content/AdjustItem.vue
  37. 68
      irbs.frontend/src/views/custRating/company/content/AdjustItemGrid.vue
  38. 36
      irbs.frontend/src/views/custRating/company/content/AdjustItemIndex.vue
  39. 38
      irbs.frontend/src/views/custRating/company/content/CreditReportGrid.vue
  40. 29
      irbs.frontend/src/views/custRating/company/content/CustBaseInfo.vue
  41. 61
      irbs.frontend/src/views/custRating/company/content/CustInfo.vue
  42. 46
      irbs.frontend/src/views/custRating/company/content/DefaultCognizanceGrid.vue
  43. 45
      irbs.frontend/src/views/custRating/company/content/DefaultRebirthGrid.vue
  44. 49
      irbs.frontend/src/views/custRating/company/content/FinanceProjectCompare.vue
  45. 74
      irbs.frontend/src/views/custRating/company/content/FinanceProjectGrid.vue
  46. 146
      irbs.frontend/src/views/custRating/company/content/FinanceReportGrid.vue
  47. 39
      irbs.frontend/src/views/custRating/company/content/FinanceReportTabs.vue
  48. 29
      irbs.frontend/src/views/custRating/company/content/FirstRatingResult.vue
  49. 51
      irbs.frontend/src/views/custRating/company/content/HistRatingGrid.vue
  50. 33
      irbs.frontend/src/views/custRating/company/content/HistTab.vue
  51. 40
      irbs.frontend/src/views/custRating/company/content/Opinion.vue
  52. 44
      irbs.frontend/src/views/custRating/company/content/OpinionGrid.vue
  53. 77
      irbs.frontend/src/views/custRating/company/content/Overturn.vue
  54. 106
      irbs.frontend/src/views/custRating/company/content/QualAnalysis.vue
  55. 51
      irbs.frontend/src/views/custRating/company/content/QuanAnalysis.vue
  56. 20
      irbs.frontend/src/views/custRating/company/content/QuanQualAnalysis.vue
  57. 36
      irbs.frontend/src/views/custRating/company/content/ReportIndex.vue
  58. 34
      irbs.frontend/src/views/custRating/company/content/ReportInfo.vue
  59. 157
      irbs.frontend/src/views/custRating/company/content/ReportRating.vue
  60. 82
      irbs.frontend/src/views/custRating/company/content/Timeline.vue
  61. 37
      irbs.frontend/src/views/custRating/company/ts/ComputedManager.ts
  62. 76
      irbs.frontend/src/views/custRating/company/ts/Constant.ts
  63. 90
      irbs.frontend/src/views/custRating/company/ts/Dictionary.ts
  64. 21
      irbs.frontend/src/views/custRating/company/ts/Enum.ts
  65. 79
      irbs.frontend/src/views/custRating/company/ts/FinanceReport.ts
  66. 31
      irbs.frontend/src/views/custRating/company/ts/HistGrid.ts
  67. 179
      irbs.frontend/src/views/custRating/company/ts/Rating.ts
  68. 52
      irbs.frontend/src/views/custRating/company/ts/Refs.ts
  69. 466
      irbs.frontend/src/views/custRating/company/ts/RequestApi.ts
  70. 325
      irbs.frontend/src/views/custRating/company/ts/Step.ts
  71. 67
      irbs.frontend/src/views/custRating/company/ts/SystemParameter.ts
  72. 41
      irbs.frontend/src/views/custRating/company/ts/Utils.ts
  73. 27
      irbs.frontend/src/views/custRating/company/ts/type/StepType.ts
  74. 50
      irbs.frontend/src/views/custRating/mock/MockCmis.vue
  75. 16
      irbs.frontend/src/views/workbench/TodoTask.vue
  76. 8
      irbs.frontend/webpack.config.common.cjs
  77. 51
      irbs.frontend/webpack.config.mf.cjs
  78. 48
      irbs.frontend/webpack.env.build.cjs
  79. 9
      irbs.riskExposure/src/main/java/irbs/riskExposure/service/impl/RiskExposureFlowServiceImpl.java
  80. 5
      irbs.shrcb.poc.frontend/package.json
  81. 8
      irbs.shrcb.poc.frontend/webpack.config.common.cjs
  82. 51
      irbs.shrcb.poc.frontend/webpack.config.mf.cjs
  83. 48
      irbs.shrcb.poc.frontend/webpack.env.build.cjs
  84. 3
      settings.gradle

2
app.irbs/build-common.gradle

@ -6,7 +6,7 @@
* 2. gradle bootwar -Dtarget=undertow # undertow, target=undertow * 2. gradle bootwar -Dtarget=undertow # undertow, target=undertow
* 3. gradle bootwar -Dtarget=jetty # jetty, target=jetty * 3. gradle bootwar -Dtarget=jetty # jetty, target=jetty
*/ */
def target =System.getProperty("target") ?: "tomcat"; def target =System.getProperty("target") ?: "undertow";
System.setProperty('target',target); System.setProperty('target',target);
// targetRuntime build.gradle // targetRuntime build.gradle

458
build.gradle

@ -1,9 +1,13 @@
import org.gradle.api.artifacts.DependencyResolveDetails import org.gradle.api.artifacts.DependencyResolveDetails
import java.util.zip.GZIPOutputStream
apply from: "build-version.gradle" apply from: "build-version.gradle"
//
def isFrontendProject(currentDir){ def isFrontendProject(currentDir){
return file(currentDir.getAbsolutePath() + '/package.json').exists() && !file(currentDir.getAbsolutePath() + '/webpack.env.lib.cjs').exists(); return file(currentDir.getAbsolutePath() + '/package.json').exists()
&& !file(currentDir.getAbsolutePath() + '/webpack.env.lib.cjs').exists();
} }
/*********************************************************************** /***********************************************************************
@ -17,8 +21,9 @@ buildscript {
} }
} }
dependencies { dependencies {
classpath "com.gradleup.shadow:shadow-gradle-plugin:${shadow_gradle_plugin_version}"
classpath "org.springframework.boot:org.springframework.boot.gradle.plugin:${spring_boot_version}" classpath "org.springframework.boot:org.springframework.boot.gradle.plugin:${spring_boot_version}"
classpath "io.sc:io.sc.platform.gradle:${platform_plugin_version}" //classpath "io.sc:io.sc.platform.gradle:${platform_plugin_version}"
classpath "org.asciidoctor:asciidoctor-gradle-jvm:${asciidoctor_version}" classpath "org.asciidoctor:asciidoctor-gradle-jvm:${asciidoctor_version}"
classpath "com.google.cloud.tools:jib-gradle-plugin:${jib_version}" classpath "com.google.cloud.tools:jib-gradle-plugin:${jib_version}"
} }
@ -29,7 +34,7 @@ buildscript {
**********************************************************************/ **********************************************************************/
allprojects { allprojects {
apply plugin: 'idea' apply plugin: 'idea'
apply plugin: 'io.sc.platform.gradle' //apply plugin: 'io.sc.platform.gradle'
} }
/*********************************************************************** /***********************************************************************
@ -42,78 +47,86 @@ subprojects {
apply plugin: 'maven-publish' apply plugin: 'maven-publish'
apply plugin: 'org.springframework.boot' apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management' apply plugin: 'io.spring.dependency-management'
apply plugin: "org.asciidoctor.jvm.convert" apply plugin: 'org.asciidoctor.jvm.convert'
configurations.all { configurations.all {
// gradle // gradle
//resolutionStrategy.cacheDynamicVersionsFor 0, 'seconds' //: 1.1.+ //resolutionStrategy.cacheDynamicVersionsFor 0, 'seconds' //: 1.1.+
//resolutionStrategy.cacheChangingModulesFor 0, 'seconds' //: 1.1.2 //resolutionStrategy.cacheChangingModulesFor 0, 'seconds' //: 1.1.2
// //
// exclude group: "org.apache.logging.log4j", module: "log4j-api"
// exclude group: "org.apache.logging.log4j", module: "log4j-to-slf4j"
// exclude group: "org.slf4j", module: "slf4j-jdk14"
exclude group: "org.slf4j", module: "slf4j-nop" exclude group: "org.slf4j", module: "slf4j-nop"
exclude group: "org.slf4j", module: "slf4j-reload4j"
resolutionStrategy.eachDependency { DependencyResolveDetails detail -> //exclude group: "com.mysql", module: "mysql-connector-j"
def requested =detail.requested;
def groupAndName =requested.group + ":" + requested.name; if(PlatformDependencyVersions!=null && PlatformDependencyVersions.size()>0) {
if(PlatformDependencyVersions[groupAndName]!=null){ resolutionStrategy.eachDependency { DependencyResolveDetails detail ->
detail.useVersion(PlatformDependencyVersions[groupAndName]); def requested = detail.requested;
def groupAndName = requested.group + ":" + requested.name;
String version = PlatformDependencyVersions[groupAndName];
if (version != null) {
detail.useVersion(version);
}
} }
} }
} }
dependencyManagement { dependencyManagement {
resolutionStrategy { resolutionStrategy {
// gradle // gradle
//cacheDynamicVersionsFor 0, 'seconds' //: 1.1.+ //cacheDynamicVersionsFor 0, 'seconds' //: 1.1.+
//cacheChangingModulesFor 0, 'seconds' //: 1.1.2 //cacheChangingModulesFor 0, 'seconds' //: 1.1.2
} }
imports { imports {
//mavenBom "org.springframework.cloud:spring-cloud-dependencies:${spring_cloud_version}" //mavenBom "org.springframework.cloud:spring-cloud-dependencies:${spring_cloud_version}"
mavenBom "com.alibaba.cloud:spring-cloud-alibaba-dependencies:${spring_cloud_alibaba_version}" mavenBom "com.alibaba.cloud:spring-cloud-alibaba-dependencies:${spring_cloud_alibaba_version}"
mavenBom "org.springframework.statemachine:spring-statemachine-bom:${spring_statemachine_version}" mavenBom "org.springframework.statemachine:spring-statemachine-bom:${spring_statemachine_version}"
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* url * url
* url ${repository_url} * url ${repository_url}
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
repositories { repositories {
all { ArtifactRepository repo -> all { ArtifactRepository repo ->
if(repo instanceof MavenArtifactRepository){ if(repo instanceof MavenArtifactRepository){
def url = repo.url.toString() def url = repo.url.toString()
if ( if (
url.startsWith('https://repo1.maven.org/maven2') url.startsWith('https://repo1.maven.org/maven2')
|| url.startsWith('https://jcenter.bintray.com/') || url.startsWith('https://jcenter.bintray.com/')
|| url.startsWith('https://maven.aliyun.com') || url.startsWith('https://maven.aliyun.com')
) { ) {
remove repo remove repo
} }
} }
} }
maven { maven {
allowInsecureProtocol = true allowInsecureProtocol = true
url "${repository_url}" url "${repository_url}"
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* java * java
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
sourceCompatibility ="${java_version}" sourceCompatibility ="${java_version}"
targetCompatibility ="${java_version}" targetCompatibility ="${java_version}"
compileJava.options.encoding ="${java_encoding}" compileJava.options.encoding ="${java_encoding}"
compileTestJava.options.encoding ="${java_encoding}" compileTestJava.options.encoding ="${java_encoding}"
tasks.withType(JavaCompile) { tasks.withType(JavaCompile) {
options.compilerArgs += ["-Xlint:deprecation","-Xlint:unchecked"] options.compilerArgs += ["-Xlint:deprecation","-Xlint:unchecked"]
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* *
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
group ="${application_group}" group ="${application_group}"
version ="${application_version}" version ="${application_version}"
if(file('package.json').exists()){ if(file('package.json').exists()){
mkdir 'java-src/main/java'; mkdir 'java-src/main/java';
@ -121,7 +134,7 @@ subprojects {
mkdir 'dist'; mkdir 'dist';
sourceSets.main.java.srcDir 'java-src/main/java' sourceSets.main.java.srcDir 'java-src/main/java'
sourceSets.main.resources.srcDir 'java-src/main/resources' sourceSets.main.resources.srcDir 'java-src/main/resources'
sourceSets.main.resources.srcDir 'dist' sourceSets.main.resources.srcDir 'dist'
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
@ -147,48 +160,51 @@ subprojects {
} }
clean { clean {
delete 'dist' //
delete 'bin' // eclipse bin delete 'bin' // eclipse bin
delete 'build' // gradle delete 'build' // gradle
delete 'dist' //
delete 'node_modules' // node_modules
delete 'pnpm-lock.yaml' // pnpm
delete 'package-lock.json' // npm
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* eclipse * eclipse
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
eclipse{ eclipse{
jdt{ jdt{
sourceCompatibility ="${java_version}" sourceCompatibility ="${java_version}"
targetCompatibility ="${java_version}" targetCompatibility ="${java_version}"
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* springboot * springboot
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
jar { jar {
// jar // jar
enabled = true enabled = true
archiveClassifier.set("") archiveClassifier.set("")
manifest { manifest {
attributes 'Manifest-Version' : '1.0', attributes 'Manifest-Version' : '1.0',
'Implementation-Title' : name, 'Implementation-Title' : name,
'Implementation-Vendor' : group, 'Implementation-Vendor' : group,
'Implementation-Version': archiveVersion 'Implementation-Version': archiveVersion
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* asciidoctor , asciidoc , jar * asciidoctor , asciidoc , jar
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
asciidoctor { asciidoctor {
baseDirFollowsSourceDir() baseDirFollowsSourceDir()
outputs.upToDateWhen { true } outputs.upToDateWhen { true }
logDocuments = true logDocuments = true
sourceDir = file('asciidoc') sourceDir = file('asciidoc')
sources { sources {
include '*.adoc' include '*.adoc'
} }
outputDir = file("dist/help/" + project.name) outputDir = file("dist/help/" + project.name)
resources { resources {
from(sourceDir) { from(sourceDir) {
@ -198,24 +214,24 @@ subprojects {
} }
asciidoctorj { asciidoctorj {
modules { modules {
diagram.use() diagram.use()
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* , asciidoc web ,便 * , asciidoc web ,便
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
task doc(type: org.asciidoctor.gradle.jvm.AsciidoctorTask){ task doc(type: org.asciidoctor.gradle.jvm.AsciidoctorTask){
baseDirFollowsSourceDir() baseDirFollowsSourceDir()
outputs.upToDateWhen { true } outputs.upToDateWhen { true }
logDocuments = true logDocuments = true
sourceDir = file('asciidoc') sourceDir = file('asciidoc')
sources { sources {
include '*.adoc' include '*.adoc'
} }
outputDir = file("$asciidoc_deploy_dir" + project.name) outputDir = file("$asciidoc_deploy_dir" + project.name)
// asciidoc // asciidoc
// : -D // : -D
@ -229,48 +245,48 @@ subprojects {
} }
} }
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* asciidoctor * asciidoctor
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
processResources { processResources {
dependsOn asciidoctor dependsOn asciidoctor
doLast{ doLast{
// jrebel // jrebel
delete "$buildDir/resources/main/rebel.xml" delete "$buildDir/resources/main/rebel.xml"
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* jrebel.xml (eclipse) * jrebel.xml (eclipse)
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
task jrebelEclipse() {} task jrebelEclipse() {}
tasks.jrebelEclipse.doLast { tasks.jrebelEclipse.doLast {
File resourcesFile =file('src/main/resources') File resourcesFile =file('src/main/resources')
if(resourcesFile!=null && resourcesFile.exists()){ if(resourcesFile!=null && resourcesFile.exists()){
File rebelFile = file('src/main/resources/rebel.xml') File rebelFile = file('src/main/resources/rebel.xml')
rebelFile.withWriter('UTF-8') { writer -> rebelFile.withWriter('UTF-8') { writer ->
writer.write('<?xml version="1.0" encoding="UTF-8"?>\n'); writer.write('<?xml version="1.0" encoding="UTF-8"?>\n');
writer.write('<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_1.xsd">\n'); writer.write('<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.zeroturnaround.com" xsi:schemaLocation="http://www.zeroturnaround.com http://update.zeroturnaround.com/jrebel/rebel-2_1.xsd">\n');
writer.write('\t<classpath>\n'); writer.write('\t<classpath>\n');
if(file(project.name + '/src/main').exists()){ if(file(project.name + '/src/main').exists()){
writer.write('\t\t<dir name="' + project.projectDir + '/bin/main"/>\n'); writer.write('\t\t<dir name="' + project.projectDir + '/bin/main"/>\n');
} }
if(file(project.name + '/src/generated').exists()){ if(file(project.name + '/src/generated').exists()){
writer.write('\t\t<dir name="' + project.projectDir + '/bin/generated"/>\n'); writer.write('\t\t<dir name="' + project.projectDir + '/bin/generated"/>\n');
} }
writer.write('\t</classpath>\n'); writer.write('\t</classpath>\n');
writer.write('</application>'); writer.write('</application>');
} }
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* jrebel.xml (idea) * jrebel.xml (idea)
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
task jrebelIdea() {} task jrebelIdea() {}
tasks.jrebelIdea.doLast { tasks.jrebelIdea.doLast {
if(isFrontendProject(file('.'))) { if(isFrontendProject(file('.'))) {
File resourcesFile = file('java-src/main/resources') File resourcesFile = file('java-src/main/resources')
if (resourcesFile != null && resourcesFile.exists()) { if (resourcesFile != null && resourcesFile.exists()) {
@ -302,7 +318,7 @@ subprojects {
} }
} }
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* maven publish * maven publish
@ -310,12 +326,12 @@ subprojects {
publishing { publishing {
repositories { repositories {
maven { maven {
allowInsecureProtocol = true // http allowInsecureProtocol = true // http
url = version.contains('SNAPSHOT') ? "${repository_snapshot_url}" : "${repository_release_url}" url = version.contains('SNAPSHOT') ? "${repository_snapshot_url}" : "${repository_release_url}"
credentials { credentials {
username = (version.contains('SNAPSHOT') ? "${repository_snapshot_username}" : "${repository_release_username}") username = (version.contains('SNAPSHOT') ? "${repository_snapshot_username}" : "${repository_release_username}")
password = (version.contains('SNAPSHOT') ? "${repository_snapshot_password}" : "${repository_release_password}") password = (version.contains('SNAPSHOT') ? "${repository_snapshot_password}" : "${repository_release_password}")
} }
} }
} }
publications{ publications{
@ -324,18 +340,18 @@ subprojects {
//artifact sourcesJar //artifact sourcesJar
//artifact javadocJar //artifact javadocJar
versionMapping { versionMapping {
usage('java-api') { usage('java-api') {
fromResolutionOf('runtimeClasspath') fromResolutionOf('runtimeClasspath')
} }
usage('java-runtime') { usage('java-runtime') {
fromResolutionResult() fromResolutionResult()
} }
} }
} }
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* package.json , name version * package.json , name version
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
task frontendUpdatePackageJson(){} task frontendUpdatePackageJson(){}
@ -361,7 +377,7 @@ subprojects {
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* pnpm install * pnpm install
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
task frontendNpmInstall(type:Exec){ task frontendNpmInstall(type:Exec){
@ -411,7 +427,32 @@ subprojects {
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* pnpm re install
*----------------------------------------------------------------*/
task frontendNpmReInstall(type:Exec){
if(isFrontendProject(file('.'))){
workingDir '.'
if(org.gradle.internal.os.OperatingSystem.current().isWindows()){
commandLine 'cmd', '/c', 'pnpm', 'install'
}else{
commandLine 'pnpm', 'install'
}
}else{
if(org.gradle.internal.os.OperatingSystem.current().isWindows()){
commandLine 'cmd', '/c', 'cd', '.'
}else{
commandLine 'cd', '.'
}
}
}
tasks.frontendNpmReInstall.doFirst {
if(isFrontendProject(file('.'))) {
println '开始执行 pnpm re install ......';
}
}
/*-----------------------------------------------------------------
* pnpm run build * pnpm run build
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
task frontendNpmBuild(type:Exec) { task frontendNpmBuild(type:Exec) {
@ -436,7 +477,7 @@ subprojects {
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
* pnpm run prod * pnpm run prod
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
task frontendNpmProd(type:Exec) { task frontendNpmProd(type:Exec) {
@ -475,6 +516,9 @@ subprojects {
} }
tasks.frontendGenerateThymeleafTemplate.doLast { tasks.frontendGenerateThymeleafTemplate.doLast {
if(isFrontendProject(file('.'))) { if(isFrontendProject(file('.'))) {
if(!file("dist/public/${project.name}/index.html").exists()){
return;
}
def content = file("dist/public/${project.name}/index.html").text; def content = file("dist/public/${project.name}/index.html").text;
content = content.replace('<script defer src="javascript/main', """<script defer src="${project.name}/javascript/main"""); content = content.replace('<script defer src="javascript/main', """<script defer src="${project.name}/javascript/main""");
def output = file("java-src/main/resources/templates/${project.name}.html"); def output = file("java-src/main/resources/templates/${project.name}.html");
@ -549,6 +593,9 @@ subprojects {
} }
tasks.frontendGenerateMenus.doLast { tasks.frontendGenerateMenus.doLast {
if(isFrontendProject(file('.'))) { if(isFrontendProject(file('.'))) {
if(!file('src/menus/menus.json').exists()) {
return;
}
java.nio.file.Files.copy(file('src/menus/menus.json').toPath(), file('java-src/main/resources/META-INF/platform/plugins/menus.json').toPath()); java.nio.file.Files.copy(file('src/menus/menus.json').toPath(), file('java-src/main/resources/META-INF/platform/plugins/menus.json').toPath());
} }
} }
@ -565,12 +612,15 @@ subprojects {
} }
tasks.frontendGenerateRoutes.doLast { tasks.frontendGenerateRoutes.doLast {
if(isFrontendProject(file('.'))) { if(isFrontendProject(file('.'))) {
if(!file("src/routes/routes.json").exists()) {
return;
}
def routes = new groovy.json.JsonSlurper().parseText(file("src/routes/routes.json").text); def routes = new groovy.json.JsonSlurper().parseText(file("src/routes/routes.json").text);
for(def route : routes){ for (def route : routes) {
route.module=project.name; route.module = project.name;
} }
def json = groovy.json.JsonOutput.toJson(routes); def json = groovy.json.JsonOutput.toJson(routes);
def outputFile =file("java-src/main/resources/META-INF/platform/plugins/frontend-routes.json"); def outputFile = file("java-src/main/resources/META-INF/platform/plugins/frontend-routes.json");
outputFile.withWriter('UTF-8') { writer -> outputFile.withWriter('UTF-8') { writer ->
writer.write(groovy.json.JsonOutput.prettyPrint(json)); writer.write(groovy.json.JsonOutput.prettyPrint(json));
} }
@ -591,9 +641,11 @@ subprojects {
if(isFrontendProject(file('.'))) { if(isFrontendProject(file('.'))) {
//components--------------------------------------- //components---------------------------------------
List<String> components =new ArrayList<String>(); List<String> components =new ArrayList<String>();
def routes = new groovy.json.JsonSlurper().parseText(file("java-src/main/resources/META-INF/platform/plugins/frontend-routes.json").text); if(file("java-src/main/resources/META-INF/platform/plugins/frontend-routes.json").exists()) {
for(def route : routes){ def routes = new groovy.json.JsonSlurper().parseText(file("java-src/main/resources/META-INF/platform/plugins/frontend-routes.json").text);
components.add(route.component); for (def route : routes) {
components.add(route.component);
}
} }
//resources---------------------------------------- //resources----------------------------------------
@ -614,12 +666,12 @@ subprojects {
}else{ }else{
def tree = fileTree('dist') { def tree = fileTree('dist') {
include '**/*.*' include '**/*.*'
exclude '**/webjars/**/*.*' // exclude '**/webjars/**/*.*'
exclude "public/${project.name}/configure.js" // exclude "public/${project.name}/configure.js"
exclude "public/${project.name}/favicon.svg" // exclude "public/${project.name}/favicon.svg"
exclude "public/${project.name}/index.html" // exclude "public/${project.name}/index.html"
exclude "public/${project.name}/login-bg.jpg" // exclude "public/${project.name}/login-bg.jpg"
exclude "public/${project.name}/logo.svg" // exclude "public/${project.name}/logo.svg"
} }
tree.each { File file -> tree.each { File file ->
resources.add(file.absolutePath.substring(dirPath.length())); resources.add(file.absolutePath.substring(dirPath.length()));
@ -654,8 +706,9 @@ subprojects {
// //
frontendNpmInstall.dependsOn(frontendUpdatePackageJson) frontendNpmInstall.dependsOn(frontendUpdatePackageJson)
frontendNpmSync.dependsOn(frontendNpmInstall) frontendNpmSync.dependsOn(frontendNpmInstall)
frontendNpmBuild.dependsOn(frontendNpmSync) frontendNpmReInstall.dependsOn(frontendNpmSync)
frontendNpmProd.dependsOn(frontendNpmSync) frontendNpmBuild.dependsOn(frontendNpmReInstall)
frontendNpmProd.dependsOn(frontendNpmReInstall)
// //
// : -D // : -D
@ -674,22 +727,61 @@ subprojects {
frontendModule.dependsOn(frontendGenerateRoutes); frontendModule.dependsOn(frontendGenerateRoutes);
frontend.dependsOn(frontendModule); frontend.dependsOn(frontendModule);
//tasks.preBuild.dependsOn(frontend);
processResources.dependsOn(frontend) processResources.dependsOn(frontend)
processResources { processResources {
if(isFrontendProject(file('.'))) { if(isFrontendProject(file('.'))) {
exclude("**/${project.name}/*.*"); if(project.name!='io.sc.platform.mvc.frontend'){
if(project.name!='io.sc.platform.mvc.frontend' && project.name!='io.sc.platform.security.frontend'){ exclude("**/${project.name}/*.*");
// exclude("**/${project.name}/javascript/codemirror.*"); exclude("**/${project.name}/javascript/codemirror.*");
// exclude("**/${project.name}/javascript/echarts.*"); exclude("**/${project.name}/javascript/echarts.*");
// exclude("**/${project.name}/javascript/platform-core.*"); exclude("**/${project.name}/javascript/maxgraph.*");
// exclude("**/${project.name}/javascript/quasar.*"); exclude("**/${project.name}/javascript/platform-core.*");
// exclude("**/${project.name}/javascript/vue.*"); exclude("**/${project.name}/javascript/quasar.*");
// exclude("**/${project.name}/fonts/*.*"); exclude("**/${project.name}/javascript/vue.*");
// exclude("**/${project.name}/webjars/**/*.*"); exclude("**/${project.name}/fonts/*.*");
exclude("**/${project.name}/webjars/**/*.*");
}
}
}
// idea node_modules , idea
idea {
module {
excludeDirs += file('node_modules')
excludeDirs += file('dist')
}
}
task classpath() {}
tasks.classpath.doFirst {
if(isFrontendProject(file('.'))){
println '开始执行 classpath ......'
}
}
tasks.classpath.doLast {
List<String> jars =new ArrayList<>();
def doc =new XmlParser().parse(file(project.name + '.iml').absolutePath);
doc.component.each { component ->
if(component.@name=='NewModuleRootManager'){
component.orderEntry.each { entry ->
if(entry.@type=='module-library'){
entry.library.CLASSES.root.each { jar ->
String url =jar.@url;
url =url.substring(0,url.length()-2);
url =url.substring(url.lastIndexOf('/')+1);
jars.add(url);
}
}
}
} }
} }
Collections.sort(jars);
println project.name + ' dependencies jars : {'
jars.each {
println ' ' + it;
}
println '}';
} }
} }
@ -700,7 +792,7 @@ subprojects {
* idea * idea
*----------------------------------------------------------------*/ *----------------------------------------------------------------*/
tasks.ideaProject.enabled=true // ideaProject , ipr tasks.ideaProject.enabled=true // ideaProject , ipr
tasks.ideaModule.enabled=false // ideaModule tasks.ideaModule.enabled=false // ideaModule
tasks.ideaWorkspace.enabled=true // ideaWorkspace , iws tasks.ideaWorkspace.enabled=true // ideaWorkspace , iws
tasks.ideaProject.doFirst { tasks.ideaProject.doFirst {
@ -730,8 +822,8 @@ idea {
} }
} }
} }
project { project {
vcs = 'Git' vcs = 'Git'
ipr { ipr {
// ipr , // ipr ,
// 1. // 1.
@ -756,22 +848,22 @@ idea {
withXml { withXml {
// 1. // 1.
def node = it.asNode() def node = it.asNode()
def projectModuleManagerNode =node.find{it.@name=='ProjectModuleManager'} def projectModuleManagerNode = node.find { it.@name == 'ProjectModuleManager' }
def rootImlNode =projectModuleManagerNode.modules.module.find{it.@fileurl=='file://$PROJECT_DIR$/' + project.name + '.iml'} def rootImlNode = projectModuleManagerNode.modules.module.find { it.@fileurl == 'file://$PROJECT_DIR$/' + project.name + '.iml' }
def rootImlParentNode =rootImlNode.parent() def rootImlParentNode = rootImlNode.parent()
rootImlParentNode.remove(rootImlNode) rootImlParentNode.remove(rootImlNode)
// 2. Encoding // 2. Encoding
def encodingNode =node.find{it.@name=='Encoding'} def encodingNode = node.find { it.@name == 'Encoding' }
encodingNode.@native2AsciiForPropertiesFiles="true" encodingNode.@native2AsciiForPropertiesFiles = "true"
// 3. 使 idea (enable annotation processing) // 3. 使 idea (enable annotation processing)
def compilerConfigurationNode =node.find{it.@name=='CompilerConfiguration'} def compilerConfigurationNode = node.find { it.@name == 'CompilerConfiguration' }
def annotationProcessingNode =compilerConfigurationNode.annotationProcessing[0] def annotationProcessingNode = compilerConfigurationNode.annotationProcessing[0]
def annotationProcessingParentNode =annotationProcessingNode.parent() def annotationProcessingParentNode = annotationProcessingNode.parent()
annotationProcessingParentNode.remove(annotationProcessingNode) annotationProcessingParentNode.remove(annotationProcessingNode)
annotationProcessingNode =annotationProcessingParentNode.appendNode("annotationProcessing") annotationProcessingNode = annotationProcessingParentNode.appendNode("annotationProcessing")
annotationProcessingNode.appendNode("profile",[default:true,enabled:true]) annotationProcessingNode.appendNode("profile", [default: true, enabled: true])
// 4. SaveActions , , .ipr xml // 4. SaveActions , , .ipr xml
// <component name="SaveActionSettings"> // <component name="SaveActionSettings">
@ -785,39 +877,39 @@ idea {
// </component> // </component>
// <component name="SaveActionSettings"> // <component name="SaveActionSettings">
def saveActionSettingsNode =node.find{it.@name=='SaveActionSettings'} def saveActionSettingsNode = node.find { it.@name == 'SaveActionSettings' }
if(saveActionSettingsNode==null){ if (saveActionSettingsNode == null) {
saveActionSettingsNode =node.appendNode("component",[name:"SaveActionSettings"]) saveActionSettingsNode = node.appendNode("component", [name: "SaveActionSettings"])
} }
// <option name="actions"> // <option name="actions">
def actionsNode =saveActionSettingsNode.find{it.@name=='actions'} def actionsNode = saveActionSettingsNode.find { it.@name == 'actions' }
if(actionsNode==null){ if (actionsNode == null) {
actionsNode =saveActionSettingsNode.appendNode("option",[name:"actions"]) actionsNode = saveActionSettingsNode.appendNode("option", [name: "actions"])
} }
// <set> // <set>
def setNode =actionsNode.set[0] def setNode = actionsNode.set[0]
if(setNode==null){ if (setNode == null) {
setNode =actionsNode.appendNode("set") setNode = actionsNode.appendNode("set")
} }
// <option value="activate" /> // <option value="activate" />
// <option value="reload" /> // <option value="reload" />
def options =setNode.option def options = setNode.option
if(options!=null && options.size()>0){ if (options != null && options.size() > 0) {
// //
for(int i=0;i<options.size();i++){ for (int i = 0; i < options.size(); i++) {
setNode.remove(options.get(i)); setNode.remove(options.get(i));
} }
} }
// //
setNode.appendNode("option",[value:"activate"]) setNode.appendNode("option", [value: "activate"])
setNode.appendNode("option",[value:"reload"]) setNode.appendNode("option", [value: "reload"])
} }
} }
} }
} }
/*----------------------------------------------------------------- /*-----------------------------------------------------------------
@ -842,10 +934,20 @@ cleanIdea {
dependsOn cleanIdeaWorkspace dependsOn cleanIdeaWorkspace
} }
/*-----------------------------------------------------------------
* IDEA
*----------------------------------------------------------------*/
task cleanIdeaSettings(){}
tasks.cleanIdeaSettings.doFirst {
delete System.getProperty("user.home") + "/Library/Application Support/JetBrains"
delete System.getProperty("user.home") + "/Library/Logs/JetBrains"
delete System.getProperty("user.home") + "/Library/Caches/JetBrains"
}
task github { task github {
println '' println ''
} }
tasks.named('wrapper') { tasks.named('wrapper') {
distributionUrl = "http://nexus.sc.io:8000/repository/maven-releases/gradle/gradle/${gradleVersion}/gradle-${gradleVersion}.zip" distributionUrl = "http://nexus.sc.io:8000/repository/maven-releases/gradle/gradle/${gradleVersion}/gradle-${gradleVersion}-bin.zip"
} }

5
irbs.cust.rating/src/main/java/irbs/cust/rating/controller/CompanyRatingController.java

@ -84,6 +84,11 @@ public class CompanyRatingController extends RestCrudController<CompanyRatingVo,
return service.stepQual(ratingId, page); return service.stepQual(ratingId, page);
} }
@GetMapping("getQualTestCalcNum")
public Integer getQualTestCalcNum(String ratingId) throws Exception {
return service.getQualTestCalcNum(ratingId);
}
/** /**
* 定性保存指标 * 定性保存指标
* @param flag 试算下一步 * @param flag 试算下一步

19
irbs.cust.rating/src/main/java/irbs/cust/rating/controller/FinanceReportDetailController.java

@ -1,15 +1,30 @@
package irbs.cust.rating.controller; package irbs.cust.rating.controller;
import io.sc.platform.mvc.controller.support.RestCrudController; import io.sc.platform.mvc.controller.support.RestCrudController;
import io.sc.platform.orm.service.support.QueryParameter;
import irbs.cust.rating.jpa.entity.FinanceReportDetail; import irbs.cust.rating.jpa.entity.FinanceReportDetail;
import irbs.cust.rating.jpa.repository.FinanceReportDetailRepository; import irbs.cust.rating.jpa.repository.FinanceReportDetailRepository;
import irbs.cust.rating.jpa.vo.FinanceReportDetailVo; import irbs.cust.rating.jpa.vo.FinanceReportDetailVo;
import irbs.cust.rating.jpa.vo.FinanceReportDetailsVo;
import irbs.cust.rating.jpa.vo.FinanceReportVo;
import irbs.cust.rating.service.FinanceReportDetailService; import irbs.cust.rating.service.FinanceReportDetailService;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController @RestController
@RequestMapping("/api/irbs/financeReportDetail") @RequestMapping("/api/irbs/financeReportDetail")
public class FinanceReportDetailController extends RestCrudController<FinanceReportDetailVo, FinanceReportDetail, String, FinanceReportDetailRepository, FinanceReportDetailService> { public class FinanceReportDetailController extends RestCrudController<FinanceReportDetailVo, FinanceReportDetail, String, FinanceReportDetailRepository, FinanceReportDetailService> {
/**
* 根据客户ID获取最新多期财报企业类获取2期事业类获取3期
* @param custId
* @return
* @throws Exception
*/
@GetMapping("query/{custId}")
@ResponseBody
public List<FinanceReportDetailsVo> queryDetail(@PathVariable(name="custId") String custId, QueryParameter queryParameter) throws Exception {
return service.queryDetail(custId, queryParameter);
}
} }

99
irbs.cust.rating/src/main/java/irbs/cust/rating/jpa/vo/FinanceReportDetailsVo.java

@ -0,0 +1,99 @@
package irbs.cust.rating.jpa.vo;
import io.sc.platform.orm.api.vo.BaseVo;
import java.math.BigDecimal;
/**
* 多期财报科目详情Vo
*/
public class FinanceReportDetailsVo extends BaseVo {
private String id;
/**
* 科目编码
*/
private String code;
/**
* 科目名称
*/
private String name;
/**
* 科目本期值
*/
private BigDecimal value;
/**
* 科目上期值
*/
private BigDecimal previousPeriodvalue;
/**
* 科目上2期值
*/
private BigDecimal previousPeriod2value;
/**
* 科目上3期值
*/
private BigDecimal previousPeriod3value;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getValue() {
return value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
public BigDecimal getPreviousPeriodvalue() {
return previousPeriodvalue;
}
public void setPreviousPeriodvalue(BigDecimal previousPeriodvalue) {
this.previousPeriodvalue = previousPeriodvalue;
}
public BigDecimal getPreviousPeriod2value() {
return previousPeriod2value;
}
public void setPreviousPeriod2value(BigDecimal previousPeriod2value) {
this.previousPeriod2value = previousPeriod2value;
}
public BigDecimal getPreviousPeriod3value() {
return previousPeriod3value;
}
public void setPreviousPeriod3value(BigDecimal previousPeriod3value) {
this.previousPeriod3value = previousPeriod3value;
}
}

2
irbs.cust.rating/src/main/java/irbs/cust/rating/service/CompanyRatingService.java

@ -29,6 +29,8 @@ public interface CompanyRatingService extends DaoService<CompanyRating, String,
public CompanyRating stepQual(String ratingId, String page) throws Exception; public CompanyRating stepQual(String ratingId, String page) throws Exception;
public Integer getQualTestCalcNum(String ratingId) throws Exception;
public Map<String, Object> qualSaveIndices(String flag, List<RatingIndex> indices) throws Exception; public Map<String, Object> qualSaveIndices(String flag, List<RatingIndex> indices) throws Exception;
public CompanyRating stepInitRating(String ratingId, String page) throws Exception; public CompanyRating stepInitRating(String ratingId, String page) throws Exception;

5
irbs.cust.rating/src/main/java/irbs/cust/rating/service/FinanceReportDetailService.java

@ -1,9 +1,14 @@
package irbs.cust.rating.service; package irbs.cust.rating.service;
import io.sc.platform.orm.service.DaoService; import io.sc.platform.orm.service.DaoService;
import io.sc.platform.orm.service.support.QueryParameter;
import irbs.cust.rating.jpa.entity.FinanceReportDetail; import irbs.cust.rating.jpa.entity.FinanceReportDetail;
import irbs.cust.rating.jpa.repository.FinanceReportDetailRepository; import irbs.cust.rating.jpa.repository.FinanceReportDetailRepository;
import irbs.cust.rating.jpa.vo.FinanceReportDetailsVo;
import java.util.List;
public interface FinanceReportDetailService extends DaoService<FinanceReportDetail, String, FinanceReportDetailRepository> { public interface FinanceReportDetailService extends DaoService<FinanceReportDetail, String, FinanceReportDetailRepository> {
public List<FinanceReportDetailsVo> queryDetail(String custId, QueryParameter queryParameter) throws Exception;
} }

9
irbs.cust.rating/src/main/java/irbs/cust/rating/service/impl/BusiProcessServiceImpl.java

@ -3,6 +3,8 @@ package irbs.cust.rating.service.impl;
import io.sc.platform.flowable.service.ProcessOperationService; import io.sc.platform.flowable.service.ProcessOperationService;
import io.sc.platform.flowable.service.ProcessQueryService; import io.sc.platform.flowable.service.ProcessQueryService;
import io.sc.platform.flowable.support.ProcessTaskWrapper; import io.sc.platform.flowable.support.ProcessTaskWrapper;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.criteria.impl.Equals;
import io.sc.platform.security.util.SecurityUtil; import io.sc.platform.security.util.SecurityUtil;
import irbs.cust.rating.service.BusiProcessService; import irbs.cust.rating.service.BusiProcessService;
import org.flowable.engine.ProcessEngine; import org.flowable.engine.ProcessEngine;
@ -45,6 +47,13 @@ public class BusiProcessServiceImpl implements BusiProcessService {
@Override @Override
public ProcessTaskWrapper findTaskByProcInstId(String procInstId) throws Exception { public ProcessTaskWrapper findTaskByProcInstId(String procInstId) throws Exception {
ProcessTaskWrapper taskWrapper = null; ProcessTaskWrapper taskWrapper = null;
// QueryParameter parameter = new QueryParameter();
// parameter.setPageable(false);
// Equals eq = new Equals();
// eq.setFieldName("processInstanceId");
// eq.setValue(procInstId);
// parameter.addCriteria(eq);
// List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(parameter).getContent();
List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(procInstId, null); List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(procInstId, null);
if (null != list && list.size() > 1) { if (null != list && list.size() > 1) {
// 同一个流程实例查找出多个任务则为多实例任务,还需再根据任务处理人匹配。 // 同一个流程实例查找出多个任务则为多实例任务,还需再根据任务处理人匹配。

26
irbs.cust.rating/src/main/java/irbs/cust/rating/service/impl/CompanyRatingServiceImpl.java

@ -427,6 +427,21 @@ public class CompanyRatingServiceImpl extends DaoServiceImpl<CompanyRating, Stri
return namedParameterJdbcTemplate.queryForObject(sql, params, Integer.class); return namedParameterJdbcTemplate.queryForObject(sql, params, Integer.class);
} }
public Integer calcQualTestCalcNum(CompanyRating rating) throws Exception {
Integer calcNum = Integer.parseInt(systemParameterService.getParameter("parameter.irbs.params.qual.calc.num"));
if (rating.getQualCalcCount()!=null) {
return calcNum - rating.getQualCalcCount();
} else {
return calcNum;
}
}
@Override
public Integer getQualTestCalcNum(String ratingId) throws Exception {
CompanyRating rating = this.findById(ratingId);
return calcQualTestCalcNum(rating);
}
@Override @Override
public Map<String, Object> qualSaveIndices(String flag, List<RatingIndex> indices) throws Exception { public Map<String, Object> qualSaveIndices(String flag, List<RatingIndex> indices) throws Exception {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
@ -449,8 +464,8 @@ public class CompanyRatingServiceImpl extends DaoServiceImpl<CompanyRating, Stri
String stepId = indices.get(0).getStepId(); String stepId = indices.get(0).getStepId();
RatingStep step = ratingStepService.findById(stepId); RatingStep step = ratingStepService.findById(stepId);
CompanyRating rating = this.findById(step.getRatingId()); CompanyRating rating = this.findById(step.getRatingId());
Integer calcNum = Integer.parseInt(systemParameterService.getParameter("parameter.irbs.params.qual.calc.num")); Integer calcNum = calcQualTestCalcNum(rating);
if(rating.getQualCalcCount() == null || rating.getQualCalcCount() <= calcNum || flag.equals("next")) { if(calcNum > 0) {
ratingIndexService.getRepository().saveAll(indices); ratingIndexService.getRepository().saveAll(indices);
rating = ratingIndexService.calculateModel(rating); rating = ratingIndexService.calculateModel(rating);
rating.setQualCalcCount(rating.getQualCalcCount() == null ? 0+1 : rating.getQualCalcCount() + 1); rating.setQualCalcCount(rating.getQualCalcCount() == null ? 0+1 : rating.getQualCalcCount() + 1);
@ -463,7 +478,7 @@ public class CompanyRatingServiceImpl extends DaoServiceImpl<CompanyRating, Stri
} }
} else { } else {
map.put("success", false); map.put("success", false);
map.put("errorMsg", "无选项修改"); map.put("errorMsg", "未修改任何选项");
} }
return map; return map;
} }
@ -505,6 +520,7 @@ public class CompanyRatingServiceImpl extends DaoServiceImpl<CompanyRating, Stri
RatingStep step = ratingStepService.findById(indices.get(0).getStepId()); RatingStep step = ratingStepService.findById(indices.get(0).getStepId());
CompanyRating rating = this.findById(step.getRatingId()); CompanyRating rating = this.findById(step.getRatingId());
ratingIndexService.getRepository().saveAll(indices); ratingIndexService.getRepository().saveAll(indices);
rating.setCurrentStep(RatingStepType.REPORT_INFO.getText());
calcAdj(rating, indices, false); calcAdj(rating, indices, false);
// TODO 灰度 // TODO 灰度
@ -691,7 +707,7 @@ public class CompanyRatingServiceImpl extends DaoServiceImpl<CompanyRating, Stri
} }
} }
rating.setProcessStatus(RatingProcessStatus.APPROVALING.name()); rating.setProcessStatus(RatingProcessStatus.APPROVALING.name());
rating.setCurrentStep(RatingStepType.OTHER.getText()); rating.setCurrentStep(RatingStepType.REPORT_INFO.getText());
if (rating.getOverNum() != null) { if (rating.getOverNum() != null) {
rating.setOverNum(rating.getOverNum()+1); rating.setOverNum(rating.getOverNum()+1);
} }
@ -703,7 +719,7 @@ public class CompanyRatingServiceImpl extends DaoServiceImpl<CompanyRating, Stri
CompanyRating rating = this.findById(ratingId); CompanyRating rating = this.findById(ratingId);
saveOpinion(rating,null, ProcessStatus.退回.getCode(), map); saveOpinion(rating,null, ProcessStatus.退回.getCode(), map);
rating.setProcessStatus(RatingProcessStatus.BACK.name()); rating.setProcessStatus(RatingProcessStatus.BACK.name());
rating.setCurrentStep(RatingStepType.OTHER.getText()); rating.setCurrentStep(RatingStepType.REPORT_INFO.getText());
if (rating.getOverNum() != null) { if (rating.getOverNum() != null) {
rating.setOverNum(rating.getOverNum()+1); rating.setOverNum(rating.getOverNum()+1);
} }

120
irbs.cust.rating/src/main/java/irbs/cust/rating/service/impl/FinanceReportDetailServiceImpl.java

@ -1,13 +1,133 @@
package irbs.cust.rating.service.impl; package irbs.cust.rating.service.impl;
import io.sc.platform.lcdp.frontend.component.support.CriteriaHandler;
import io.sc.platform.orm.service.impl.DaoServiceImpl; import io.sc.platform.orm.service.impl.DaoServiceImpl;
import io.sc.platform.orm.service.support.OperatorType;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.criteria.Criteria;
import io.sc.platform.orm.service.support.criteria.impl.InSet;
import irbs.cust.rating.jpa.entity.FinanceReport;
import irbs.cust.rating.jpa.entity.FinanceReportDetail; import irbs.cust.rating.jpa.entity.FinanceReportDetail;
import irbs.cust.rating.jpa.entity.RatingCompanyCustomer;
import irbs.cust.rating.jpa.repository.FinanceReportDetailRepository; import irbs.cust.rating.jpa.repository.FinanceReportDetailRepository;
import irbs.cust.rating.jpa.repository.FinanceReportRepository;
import irbs.cust.rating.jpa.vo.FinanceReportDetailsVo;
import irbs.cust.rating.service.FinanceReportDetailService; import irbs.cust.rating.service.FinanceReportDetailService;
import irbs.cust.rating.service.RatingCompanyCustomerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service("financeReportDetailService") @Service("financeReportDetailService")
public class FinanceReportDetailServiceImpl extends DaoServiceImpl<FinanceReportDetail, String, FinanceReportDetailRepository> implements FinanceReportDetailService { public class FinanceReportDetailServiceImpl extends DaoServiceImpl<FinanceReportDetail, String, FinanceReportDetailRepository> implements FinanceReportDetailService {
@Autowired
private RatingCompanyCustomerService ratingCompanyCustomerService;
@Autowired
private FinanceReportRepository financeReportRepository;
@Override
public List<FinanceReportDetailsVo> queryDetail(String custId, QueryParameter queryParameter) throws Exception {
List<String> reportIds = getReportIds(custId);
addCriteria(reportIds, queryParameter);
List<FinanceReportDetail> list = this.list(queryParameter);
List<FinanceReportDetailsVo> result = new ArrayList<>();
resultHandler(reportIds, list, result);
return result;
}
private void resultHandler(List<String> reportIds, List<FinanceReportDetail> list, List<FinanceReportDetailsVo> result) throws Exception {
if (list!=null && list.size()>0) {
Map<String, List<FinanceReportDetail>> map = list.stream().collect(Collectors.groupingBy(FinanceReportDetail::getReportId));
//以本期值为基础
List<FinanceReportDetail> currList = map.get(reportIds.get(0));
// 上期值
List<FinanceReportDetail> previousPeriodList = new ArrayList<>();
if (reportIds.size() > 1 && map.containsKey(reportIds.get(1))) {
previousPeriodList = map.get(reportIds.get(1));
}
// 上2期值
List<FinanceReportDetail> previousPeriod2List = new ArrayList<>();
if (reportIds.size() > 2 && map.containsKey(reportIds.get(2))) {
previousPeriod2List = map.get(reportIds.get(2));
}
// 上3期值
List<FinanceReportDetail> previousPeriod3List = new ArrayList<>();
if (reportIds.size() > 3 && map.containsKey(reportIds.get(3))) {
previousPeriod3List = map.get(reportIds.get(3));
}
list2ListVo(currList, result, previousPeriodList, previousPeriod2List, previousPeriod3List);
}
}
private void list2ListVo(
List<FinanceReportDetail> list,
List<FinanceReportDetailsVo> listVo,
List<FinanceReportDetail> previousPeriodList,
List<FinanceReportDetail> previousPeriod2List,
List<FinanceReportDetail> previousPeriod3List
) {
for(FinanceReportDetail frd: list) {
FinanceReportDetailsVo vo = new FinanceReportDetailsVo();
vo.setId(frd.getId());
vo.setCode(frd.getProjectCode());
vo.setName(frd.getProjectName());
vo.setValue(frd.getProjectValue());
if (previousPeriodList.size() > 0) {
FinanceReportDetail tmp = previousPeriodList.stream().filter(entity -> entity.getProjectCode().equals(frd.getProjectCode())).findFirst().get();
vo.setPreviousPeriodvalue(tmp.getProjectValue());
}
if (previousPeriod2List.size() > 0) {
FinanceReportDetail tmp = previousPeriod2List.stream().filter(entity -> entity.getProjectCode().equals(frd.getProjectCode())).findFirst().get();
vo.setPreviousPeriod2value(tmp.getProjectValue());
}
if (previousPeriod3List.size() > 0) {
FinanceReportDetail tmp = previousPeriod3List.stream().filter(entity -> entity.getProjectCode().equals(frd.getProjectCode())).findFirst().get();
vo.setPreviousPeriod3value(tmp.getProjectValue());
}
listVo.add(vo);
}
}
private void addCriteria(List<String> reportIds, QueryParameter queryParameter) throws Exception {
InSet inSet = new InSet();
inSet.setFieldName("reportId");
inSet.setOperator(OperatorType.inSet);
if (reportIds != null && reportIds.size() > 0) {
inSet.setValue((String[])reportIds.toArray(new String[0]));
} else {
inSet.setValue(new String[]{Long.toString(System.currentTimeMillis())});
}
queryParameter.addCriteria(inSet);
}
/**
* 根据客户ID查询最新多期报表ID企业类3期其他4期
* @param custId
* @return
* @throws Exception
*/
private List<String> getReportIds(String custId) throws Exception {
RatingCompanyCustomer customer = ratingCompanyCustomerService.findById(custId);
Integer periodNum = 3;
if (!customer.getCustomerType().equals("1")) {
periodNum = 4;
}
List<FinanceReport> reports = financeReportRepository.findByCustIdOrderByEndDateDesc(custId);
List<String> reportIds = new ArrayList<>();
if (reports!=null && reports.size() > 0) {
if (reports.size() <= periodNum) {
reportIds = reports.stream().map(FinanceReport::getId).collect(Collectors.toList());
} else {
for(int i=0;i<periodNum-1;i++) {
reportIds.add(reports.get(i).getId());
}
}
}
return reportIds;
}
} }

8
irbs.cust.rating/src/main/java/irbs/cust/rating/service/impl/MainScaleVersionServiceImpl.java

@ -9,6 +9,7 @@ import io.sc.platform.flowable.support.CompleteTaskResponse;
import io.sc.platform.flowable.support.ProcessTaskWrapper; import io.sc.platform.flowable.support.ProcessTaskWrapper;
import io.sc.platform.orm.service.impl.DaoServiceImpl; import io.sc.platform.orm.service.impl.DaoServiceImpl;
import io.sc.platform.orm.service.support.QueryParameter; import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.criteria.impl.Equals;
import io.sc.platform.security.util.SecurityUtil; import io.sc.platform.security.util.SecurityUtil;
import irbs.cust.rating.constant.ProcessConstant; import irbs.cust.rating.constant.ProcessConstant;
import irbs.cust.rating.enums.GoBackType; import irbs.cust.rating.enums.GoBackType;
@ -68,6 +69,13 @@ public class MainScaleVersionServiceImpl extends DaoServiceImpl<MainScaleVersion
@Override @Override
public ProcessTaskWrapper findTaskByProcInstId(String procInstId) throws Exception { public ProcessTaskWrapper findTaskByProcInstId(String procInstId) throws Exception {
ProcessTaskWrapper taskWrapper = null; ProcessTaskWrapper taskWrapper = null;
// QueryParameter parameter = new QueryParameter();
// parameter.setPageable(false);
// Equals eq = new Equals();
// eq.setFieldName("processInstanceId");
// eq.setValue(procInstId);
// parameter.addCriteria(eq);
// List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(parameter).getContent();
List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(procInstId, null); List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(procInstId, null);
if (null != list && list.size() > 1) { if (null != list && list.size() > 1) {
// 同一个流程实例查找出多个任务则为多实例任务,还需再根据任务处理人匹配。 // 同一个流程实例查找出多个任务则为多实例任务,还需再根据任务处理人匹配。

8
irbs.defaultManager/src/main/java/irbs/defaultManager/service/impl/DefaultCognizanceServiceImpl.java

@ -6,6 +6,7 @@ import io.sc.platform.flowable.support.ProcessTaskWrapper;
import io.sc.platform.lcdp.form.service.JdbcTemplateService; import io.sc.platform.lcdp.form.service.JdbcTemplateService;
import io.sc.platform.orm.service.impl.DaoServiceImpl; import io.sc.platform.orm.service.impl.DaoServiceImpl;
import io.sc.platform.orm.service.support.QueryParameter; import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.criteria.impl.Equals;
import io.sc.platform.orm.util.EntityVoUtil; import io.sc.platform.orm.util.EntityVoUtil;
import io.sc.platform.security.util.SecurityUtil; import io.sc.platform.security.util.SecurityUtil;
import irbs.defaultManager.constant.DefaultConstant; import irbs.defaultManager.constant.DefaultConstant;
@ -126,6 +127,13 @@ public class DefaultCognizanceServiceImpl extends DaoServiceImpl<DefaultCognizan
public ProcessTaskWrapper findTaskByProcInstId(String procInstId) throws Exception { public ProcessTaskWrapper findTaskByProcInstId(String procInstId) throws Exception {
ProcessTaskWrapper taskWrapper = null; ProcessTaskWrapper taskWrapper = null;
// QueryParameter parameter = new QueryParameter();
// parameter.setPageable(false);
// Equals eq = new Equals();
// eq.setFieldName("processInstanceId");
// eq.setValue(procInstId);
// parameter.addCriteria(eq);
// List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(parameter).getContent();
List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(procInstId, null); List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(procInstId, null);
if (null != list && list.size() > 1) { if (null != list && list.size() > 1) {
// 同一个流程实例查找出多个任务则为多实例任务,还需再根据任务处理人匹配。 // 同一个流程实例查找出多个任务则为多实例任务,还需再根据任务处理人匹配。

8
irbs.defaultManager/src/main/java/irbs/defaultManager/service/impl/DefaultRebirthServiceImpl.java

@ -7,6 +7,7 @@ import io.sc.platform.jdbc.sql.condition.Condition;
import io.sc.platform.lcdp.form.service.JdbcTemplateService; import io.sc.platform.lcdp.form.service.JdbcTemplateService;
import io.sc.platform.orm.service.impl.DaoServiceImpl; import io.sc.platform.orm.service.impl.DaoServiceImpl;
import io.sc.platform.orm.service.support.QueryParameter; import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.criteria.impl.Equals;
import io.sc.platform.orm.util.EntityVoUtil; import io.sc.platform.orm.util.EntityVoUtil;
import io.sc.platform.security.util.SecurityUtil; import io.sc.platform.security.util.SecurityUtil;
import irbs.defaultManager.constant.DefaultConstant; import irbs.defaultManager.constant.DefaultConstant;
@ -66,6 +67,13 @@ public class DefaultRebirthServiceImpl extends DaoServiceImpl<DefaultRebirth, St
public ProcessTaskWrapper findTaskByProcInstId(String procInstId) throws Exception { public ProcessTaskWrapper findTaskByProcInstId(String procInstId) throws Exception {
ProcessTaskWrapper taskWrapper = null; ProcessTaskWrapper taskWrapper = null;
// QueryParameter parameter = new QueryParameter();
// parameter.setPageable(false);
// Equals eq = new Equals();
// eq.setFieldName("processInstanceId");
// eq.setValue(procInstId);
// parameter.addCriteria(eq);
// List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(parameter).getContent();
List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(procInstId, null); List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(procInstId, null);
if (null != list && list.size() > 1) { if (null != list && list.size() > 1) {
// 同一个流程实例查找出多个任务则为多实例任务,还需再根据任务处理人匹配。 // 同一个流程实例查找出多个任务则为多实例任务,还需再根据任务处理人匹配。

5
irbs.frontend/package.json

@ -86,6 +86,7 @@
"@codemirror/view": "6.36.2", "@codemirror/view": "6.36.2",
"@maxgraph/core": "0.14.0", "@maxgraph/core": "0.14.0",
"@quasar/extras": "1.16.15", "@quasar/extras": "1.16.15",
"@quasar/quasar-ui-qmarkdown": "2.0.5",
"@univerjs/core": "0.5.4", "@univerjs/core": "0.5.4",
"@univerjs/design": "0.5.4", "@univerjs/design": "0.5.4",
"@univerjs/docs": "0.5.4", "@univerjs/docs": "0.5.4",
@ -99,7 +100,7 @@
"@univerjs/thread-comment": "0.5.4", "@univerjs/thread-comment": "0.5.4",
"@univerjs/ui": "0.5.4", "@univerjs/ui": "0.5.4",
"@vueuse/core": "12.4.0", "@vueuse/core": "12.4.0",
"axios": "1.7.9", "axios": "1.8.2",
"codemirror": "6.0.1", "codemirror": "6.0.1",
"dayjs": "1.11.13", "dayjs": "1.11.13",
"echarts": "5.6.0", "echarts": "5.6.0",
@ -110,7 +111,7 @@
"mockjs": "1.1.0", "mockjs": "1.1.0",
"node-sql-parser": "5.3.6", "node-sql-parser": "5.3.6",
"pinia": "2.3.0", "pinia": "2.3.0",
"platform-core": "8.2.50", "platform-core": "v999.999.7",
"quasar": "2.17.6", "quasar": "2.17.6",
"sort-array": "5.0.0", "sort-array": "5.0.0",
"svg-path-commander": "2.1.7", "svg-path-commander": "2.1.7",

2
irbs.frontend/src/i18n/messages_zh_CN.json

@ -9,6 +9,8 @@
"menu.irbs.custRating": "客户评级管理", "menu.irbs.custRating": "客户评级管理",
"menu.irbs.custRating.custRating": "一般公司客户评级", "menu.irbs.custRating.custRating": "一般公司客户评级",
"menu.irbs.custRating.mockCmis": "模拟信贷系统发起",
"route.irbs.rating.apply": "一般公司客户评级",
"menu.irbs.custRating.custSeparateRating": "一般公司客户独立评级", "menu.irbs.custRating.custSeparateRating": "一般公司客户独立评级",
"menu.irbs.custRating.financialRating": "金融机构客户评级", "menu.irbs.custRating.financialRating": "金融机构客户评级",

1
irbs.frontend/src/menus/menus.json

@ -27,6 +27,7 @@
{"type":"GROUP", "order":200, "parentId":"menu.irbs", "id":"menu.irbs.custRating", "titleI18nKey":"menu.irbs.custRating", "icon":"bar_chart"}, {"type":"GROUP", "order":200, "parentId":"menu.irbs", "id":"menu.irbs.custRating", "titleI18nKey":"menu.irbs.custRating", "icon":"bar_chart"},
/*/*/ /*/*/
{"type":"ROUTE", "order":100, "parentId":"menu.irbs.custRating", "id":"menu.irbs.custRating.custRating", "titleI18nKey":"menu.irbs.custRating.custRating", "icon":"format_list_numbered", "routeName":"route.irbs.custRating.custRating"}, {"type":"ROUTE", "order":100, "parentId":"menu.irbs.custRating", "id":"menu.irbs.custRating.custRating", "titleI18nKey":"menu.irbs.custRating.custRating", "icon":"format_list_numbered", "routeName":"route.irbs.custRating.custRating"},
{"type":"ROUTE", "order":200, "parentId":"menu.irbs.custRating", "id":"menu.irbs.custRating.mockCmis", "titleI18nKey":"menu.irbs.custRating.mockCmis", "icon":"computer", "routeName":"route.irbs.custRating.mockCmis"},
/*/ /*/
{"type":"ROUTE", "order":200, "parentId":"menu.irbs.custRating", "id":"menu.irbs.custRating.custSeparateRating", "titleI18nKey":"menu.irbs.custRating.custSeparateRating", "icon":"", "routeName":"route.irbs.custRating.custSeparateRating"},*/ {"type":"ROUTE", "order":200, "parentId":"menu.irbs.custRating", "id":"menu.irbs.custRating.custSeparateRating", "titleI18nKey":"menu.irbs.custRating.custSeparateRating", "icon":"", "routeName":"route.irbs.custRating.custSeparateRating"},*/
/*/ /*/

33
irbs.frontend/src/routes/routes.json

@ -54,11 +54,38 @@
}, },
{ {
"name": "route.irbs.custRating.custRating", "name": "route.irbs.custRating.custRating",
"path": "irbs/custRating", "path": "irbs/company/custRating",
"parent": "/", "parent": "/",
"priority": -1, "priority": -1,
"component": "irbs.custRating", "component": "irbs.company.custRating",
"componentPath": "@/views/custRating/CustRating.vue", "componentPath": "@/views/custRating/company/RatingGrid.vue",
"redirect": null,
"meta": {
"permissions": ["/example/**/*"]
},
"children": []
},
{
"parent": "/",
"name": "route.irbs.rating.apply",
"path": "/irbs/rating/apply",
"priority": -1,
"component": "irbs.company.apply",
"componentPath": "@/views/custRating/company/Apply.vue",
"redirect": null,
"meta": {
"route.irbs.rating.apply": { "titleI18nKey": "route.irbs.rating.apply" },
"permissions": ["/example/**/*"]
},
"children": []
},
{
"name": "route.irbs.custRating.mockCmis",
"path": "irbs/company/mockCmis",
"parent": "/",
"priority": -1,
"component": "irbs.company.mockCmis",
"componentPath": "@/views/custRating/mock/MockCmis.vue",
"redirect": null, "redirect": null,
"meta": { "meta": {
"permissions": ["/example/**/*"] "permissions": ["/example/**/*"]

36
irbs.frontend/src/views/components/LoadingDialog.vue

@ -0,0 +1,36 @@
<template>
<q-dialog v-model="alert" no-esc-dismiss no-backdrop-dismiss>
<q-card style="width: 300px; height: 200px">
<q-card-section class="w-full h-full">
<div style="display: flex; justify-content: center; align-items: center; height: 100%; flex-direction: column">
<div>
<q-spinner-gears color="primary" size="5.5em" />
</div>
<div>
{{ msg }}
</div>
</div>
</q-card-section>
</q-card>
</q-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const alert = ref(false);
const msg = ref('');
const show = (msg_: string = '正在处理,请稍等...') => {
msg.value = msg_;
alert.value = true;
};
const hide = () => {
alert.value = false;
};
defineExpose({
show,
hide,
});
</script>

30
irbs.frontend/src/views/custRating/CustRating.ts

@ -2,21 +2,21 @@
* *
*/ */
export const RatingLevelOptions = [ export const RatingLevelOptions = [
{ label: 'AAA+', value: 'AAA+', numberValue: 15, color: 'green' }, { label: 'AAA+', value: 'AAA+', numberValue: 15, color: 'green', denseLabel: false },
{ label: 'AAA', value: 'AAA', numberValue: 14, color: 'green' }, { label: 'AAA', value: 'AAA', numberValue: 14, color: 'green', denseLabel: false },
{ label: 'AA+', value: 'AA+', numberValue: 13, color: 'green' }, { label: 'AA+', value: 'AA+', numberValue: 13, color: 'green', denseLabel: false },
{ label: 'AA', value: 'AA', numberValue: 12, color: 'green' }, { label: 'AA', value: 'AA', numberValue: 12, color: 'green', denseLabel: false },
{ label: 'AA-', value: 'AA-', numberValue: 11, color: 'green' }, { label: 'AA-', value: 'AA-', numberValue: 11, color: 'green', denseLabel: false },
{ label: 'A+', value: 'A+', numberValue: 10, color: 'green' }, { label: 'A+', value: 'A+', numberValue: 10, color: 'green', denseLabel: false },
{ label: 'A', value: 'A', numberValue: 9, color: 'green' }, { label: 'A', value: 'A', numberValue: 9, color: 'green', denseLabel: false },
{ label: 'A-', value: 'A-', numberValue: 8, color: 'green' }, { label: 'A-', value: 'A-', numberValue: 8, color: 'green', denseLabel: false },
{ label: 'BBB', value: 'BBB', numberValue: 7, color: 'green' }, { label: 'BBB', value: 'BBB', numberValue: 7, color: 'green', denseLabel: false },
{ label: 'BB', value: 'BB', numberValue: 6, color: 'red' }, { label: 'BB', value: 'BB', numberValue: 6, color: 'red', denseLabel: false },
{ label: 'B', value: 'B', numberValue: 5, color: 'red' }, { label: 'B', value: 'B', numberValue: 5, color: 'red', denseLabel: false },
{ label: 'CCC', value: 'CCC', numberValue: 4, color: 'red' }, { label: 'CCC', value: 'CCC', numberValue: 4, color: 'red', denseLabel: false },
{ label: 'CC', value: 'CC', numberValue: 3, color: 'red' }, { label: 'CC', value: 'CC', numberValue: 3, color: 'red', denseLabel: false },
{ label: 'C', value: 'C', numberValue: 2, color: 'red' }, { label: 'C', value: 'C', numberValue: 2, color: 'red', denseLabel: false },
{ label: 'D', value: 'D', numberValue: 1, color: 'red' }, { label: 'D', value: 'D', numberValue: 1, color: 'red', denseLabel: false },
]; ];
/** /**

2
irbs.frontend/src/views/custRating/CustRating.vue

@ -171,7 +171,7 @@ const companyRatingGrid = {
columns: [ columns: [
{ name: 'id', label: '申请编号', align: 'center' }, { name: 'id', label: '申请编号', align: 'center' },
{ name: 'custNo', label: '客户号', align: 'center' }, { name: 'custNo', label: '客户号', align: 'center' },
{ name: 'custName', label: '客户名称' }, { name: 'custName', label: '客户名称', width: 150 },
{ name: 'industryTypeName', label: '行业类型' }, { name: 'industryTypeName', label: '行业类型' },
{ name: 'modelScore', label: '模型得分' }, { name: 'modelScore', label: '模型得分' },
{ name: 'modelLevel', label: '模型等级' }, { name: 'modelLevel', label: '模型等级' },

3
irbs.frontend/src/views/custRating/RatingLevel.vue

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<q-knob v-model="value" :min="1" :max="10" readonly show-value size="md" :color="color" track-color="grey-3" v-bind="attrs"> <q-knob v-model="value" :min="1" :max="10" readonly show-value :size="size" :color="color" track-color="grey-3" v-bind="attrs">
<span>{{ props.level }}</span> <span>{{ props.level }}</span>
</q-knob> </q-knob>
</div> </div>
@ -13,6 +13,7 @@ import { RatingLevelOptions } from './CustRating.ts';
const attrs = useAttrs(); const attrs = useAttrs();
const props = defineProps({ const props = defineProps({
level: { type: String, default: '' }, level: { type: String, default: '' },
size: { type: String, default: 'md' },
}); });
const value = ref(0); const value = ref(0);

61
irbs.frontend/src/views/custRating/RatingLevelSlider.vue

@ -0,0 +1,61 @@
<template>
<q-slider
v-model="ratingLevel"
dense
readonly
color="blue"
:label-always="labelAlwaysComputed"
:label-value="labelValueComputed"
:marker-labels="labelsComputed"
:min="minLevel"
:max="maxLevel"
style="width: 95%"
/>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { RatingLevelOptions } from './CustRating';
const modelValue = defineModel<string>();
const minLevel = ref(RatingLevelOptions.find((item) => item.value === 'D')?.numberValue);
const maxLevel = ref(RatingLevelOptions.find((item) => item.value === 'AAA+')?.numberValue);
const props = defineProps({
// marker-labels
denseLabel: { type: Boolean, default: false },
});
const ratingLevel = computed(() => {
const ratingLevel_ = RatingLevelOptions.find((item) => {
return item['value'] === modelValue.value;
});
if (ratingLevel_) {
return ratingLevel_.numberValue;
}
return 1;
});
const labelsComputed = computed(() => {
const result = <any>[];
RatingLevelOptions.forEach((item) => {
if (props.denseLabel && item.denseLabel) {
result.push({
label: item.label,
value: item.numberValue,
});
} else if (!props.denseLabel) {
result.push({
label: item.label,
value: item.numberValue,
});
}
});
return result;
});
const labelAlwaysComputed = computed(() => {
return props.denseLabel;
});
const labelValueComputed = computed(() => {
return modelValue.value;
});
</script>

69
irbs.frontend/src/views/custRating/company/AnnotationButton.vue

@ -0,0 +1,69 @@
<template>
<div>
<q-btn
v-if="showComputed"
icon="mark_chat_unread"
color="primary"
label="批注"
@click="
() => {
addAnnotationRef.show();
}
"
/>
<w-drawer ref="addAnnotationRef" title="批注">
<div class="p-2 h-full">
<w-splitter :size="205" horizontal unit="px" disable :show-separator="false">
<template #before>
<w-form ref="formRef" :cols-num="1" :fields="[{ label: '批注内容', name: 'annotation', type: 'w-textarea' }]"></w-form>
<br />
<q-btn
icon="add"
color="primary"
label="添加"
@click="
() => {
annotationGridRef.addLocalData({ nr: formRef.getData()['annotation'], sj: currDate() });
}
"
/>
</template>
<template #after>
<div class="h-full">
<w-grid
ref="annotationGridRef"
:auto-fetch-data="false"
:config-button="false"
:toolbar-actions="['refresh', 'remove']"
:columns="[
{ label: '批注内容', name: 'nr' },
{ label: '批注时间', name: 'sj', width: 200 },
]"
>
</w-grid>
</div>
</template>
</w-splitter>
</div>
</w-drawer>
</div>
</template>
<script setup lang="ts">
import { ref, inject, computed } from 'vue';
import { Rating } from './ts/Rating';
import { Step } from './ts/Step';
import { Constant } from './ts/Constant';
const rating = <Rating>inject('rating');
const addAnnotationRef = ref();
const annotationGridRef = ref();
const formRef = ref();
const currDate = () => {
const now = new Date();
const formattedTime = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
return formattedTime;
};
const showComputed = computed(() => {
return true;
});
</script>

13
irbs.frontend/src/views/custRating/company/Apply.vue

@ -0,0 +1,13 @@
<template>
<div style="height: 100%">
<RatingManager :show-rating-dialog="true" :cust-no="custNo"></RatingManager>
</div>
</template>
<script setup lang="ts">
import RatingManager from './RatingManager.vue';
import { useRoute } from 'vue-router';
const route = useRoute();
const custNo = route?.query?.custNo;
</script>

37
irbs.frontend/src/views/custRating/company/Content.vue

@ -0,0 +1,37 @@
<template>
<CustInfo v-if="custComputed"></CustInfo>
<QuanQualAnalysis v-else-if="qqaComputed"></QuanQualAnalysis>
<AdjustItem v-else-if="aiComputed"></AdjustItem>
<ReportInfo v-else-if="riComputed"></ReportInfo>
<Opinion v-else-if="opinionComputed"></Opinion>
</template>
<script setup lang="ts">
import { ref, PropType, computed } from 'vue';
import type { StepType } from './ts/type/StepType';
import { Step } from './ts/Step';
import CustInfo from './content/CustInfo.vue';
import QuanQualAnalysis from './content/QuanQualAnalysis.vue';
import AdjustItem from './content/AdjustItem.vue';
import ReportInfo from './content/ReportInfo.vue';
import Opinion from './content/Opinion.vue';
const props = defineProps({
step: { type: Object as PropType<StepType>, default: undefined },
});
const custComputed = computed(() => {
return props.step?.value === Step.type.custInfo.value;
});
const qqaComputed = computed(() => {
return props.step?.value === Step.type.quanQualAnalysis.value;
});
const aiComputed = computed(() => {
return props.step?.value === Step.type.adjustItem.value;
});
const riComputed = computed(() => {
return props.step?.value === Step.type.reportInfo.value;
});
const opinionComputed = computed(() => {
return props.step?.value === Step.type.opinion.value;
});
</script>

54
irbs.frontend/src/views/custRating/company/CustSelectDialog.vue

@ -0,0 +1,54 @@
<template>
<w-dialog
ref="dialogRef"
:title="state.dialogTitle"
width="80%"
height="80%"
:buttons="[
{
label: '确定',
icon: 'beenhere',
click: () => {
submit();
},
},
]"
>
<CustSelectGrid ref="customerGridRef"></CustSelectGrid>
</w-dialog>
</template>
<script setup lang="ts">
import { NotifyManager } from 'platform-core';
import { reactive, ref } from 'vue';
import CustSelectGrid from './CustSelectGrid.vue';
const dialogRef = ref();
const customerGridRef = ref();
const emit = defineEmits(['refresh', 'submitHandler']);
const state = reactive({
dialogTitle: '选择客户',
});
const submit = () => {
const rows = customerGridRef.value.getRef().getSelectedRows();
if (rows.length === 0) {
NotifyManager.warn('请选择客户');
return;
}
emit('submitHandler', rows[0]);
};
const show = () => {
dialogRef.value.show();
};
const hide = () => {
dialogRef.value.hide();
};
defineExpose({
show,
hide,
});
</script>

57
irbs.frontend/src/views/custRating/company/CustSelectGrid.vue

@ -0,0 +1,57 @@
<template>
<div class="h-full">
<w-grid
ref="customerGridRef"
title="客户列表"
:fetch-data-url="Environment.apiContextPath('api/irbs/companyCustomer/query')"
:sort-no="true"
:checkbox-selection="false"
:config-button="false"
:toolbar-actions="props.toolbarActions"
:query-criteria="{
fieldName: 'mgerNo',
operator: 'equals',
value: SessionManager.getUser().loginName,
}"
:sort-by="['-lastModifyDate']"
:query-form-cols-num="3"
:query-form-fields="[
{ label: '客户号', name: 'custNo', type: 'w-text' },
{ label: '客户名称', name: 'custName', type: 'w-text' },
{ label: '企业规模', name: 'corpSizeCd', type: 'w-select', options: Options.dictionary(dictionaryArr['CustomerSizeCd']) },
]"
:columns="[
{ name: 'custNo', label: '客户号' },
{ name: 'custName', label: '客户名称' },
{ name: 'induSortName', label: '行业类型' },
{ name: 'custTypeCd', label: '客户类型', format: Formater.dictionary(dictionaryArr['CustomerTypeCd']) },
{ name: 'buildDt', label: '成立时间' },
{ name: 'corpSizeCd', label: '企业规模', format: Formater.dictionary(dictionaryArr['CustomerSizeCd']) },
]"
></w-grid>
</div>
</template>
<script setup lang="ts">
import { DictionaryTools, Environment, Formater, Options, SessionManager } from 'platform-core';
import { ref } from 'vue';
const customerGridRef = ref();
const props = defineProps({
toolbarActions: {
type: Array,
default: () => {
return ['query', 'reset'];
},
},
});
const getRef = () => {
return customerGridRef.value;
};
defineExpose({
getRef,
});
const dictionaryArr = await DictionaryTools.fetch(['CustomerSizeCd', 'CustomerTypeCd']);
</script>

21
irbs.frontend/src/views/custRating/company/NextButton.vue

@ -0,0 +1,21 @@
<template>
<q-btn v-if="showComputed" icon="next_plan" color="primary" label="下一步" @click="rating.step.nextClick" />
</template>
<script setup lang="ts">
import { inject, computed } from 'vue';
import { Rating } from './ts/Rating';
import { Step } from './ts/Step';
import { Constant } from './ts/Constant';
const rating = <Rating>inject('rating');
const showComputed = computed(() => {
if (rating.ratingData.value['processStatus'] === Constant.RATING_PROCESS_STATUS.BACK && rating.step.currStep.value === Step.type.reportInfo.value) {
return false;
} else {
if (rating.cm.isApplyUserProcessStatus.value && rating.step.currStep.value !== Step.type.opinion.value) {
return true;
}
}
return false;
});
</script>

93
irbs.frontend/src/views/custRating/company/RatingDialog.vue

@ -0,0 +1,93 @@
<template>
<w-dialog ref="dialogRef" width="95%" height="95%" body-padding="0px 0px 0px 0px" @hide="hideEvent">
<template #title>
<div>
<span class="text-xl">客户评级</span>
<span class="text-3xl">
{{ custInfoData['custName'] }}
<q-badge color="orange" align="top">客户号{{ custInfoData['custNo'] }}</q-badge
>&nbsp; <q-badge color="green" align="top">上市</q-badge>&nbsp;
<q-badge color="red" align="top">{{ Formater.dictionary(dictionary.customerSize)(custInfoData['customerSize']) }}</q-badge
>&nbsp; <q-badge align="top">{{ Formater.dictionary(dictionary.registeredType)(custInfoData['registeredType']) }}</q-badge
>&nbsp; <q-badge color="secondary" align="top">{{ custInfoData['groupCustInd'] === '1' ? '集团客户' : '非集团客户' }}</q-badge
>&nbsp;
<q-badge v-if="custInfoData['groupCustInd'] === '1'" align="top"
>集团成员类别{{ Formater.dictionary(dictionary.memberTypeCd)(custInfoData['memberType']) }}</q-badge
><template v-if="custInfoData['groupCustInd'] === '1'">&nbsp;</template>
<q-badge color="blue" align="top">行业{{ custInfoData['industryTypeName'] }}</q-badge
>&nbsp; <q-badge color="brown" align="top">成立日期{{ custInfoData['buildDate'] }}</q-badge
>&nbsp;
</span>
</div>
</template>
<RatingPage :rating-data="props.ratingData" :read-mode="props.readMode" @after-complete="afterComplete"></RatingPage>
</w-dialog>
</template>
<script setup lang="ts">
import { ref, computed, nextTick } from 'vue';
import { axios, Environment, Formater } from 'platform-core';
import RatingPage from './RatingPage.vue';
import { Dictionary } from './ts/Dictionary';
const dialogRef = ref();
const custInfoData = ref({});
const dictionary = new Dictionary();
const props = defineProps({
ratingData: {
type: Object,
default: () => {
return {};
},
},
readMode: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(['refresh']);
const titleComputed = computed(() => {
return `公司客户评级 客户:` + props.ratingData['custName'] + ` 评级模型:` + (props.ratingData['modelName'] || '');
});
/**
* 显示评级窗口
*/
const show = () => {
dialogRef.value.show();
nextTick(() => {
const custId = props.ratingData['custId'];
axios.get(Environment.apiContextPath('api/irbs/ratingCompanyCustomer/' + custId)).then((resp) => {
if (resp && resp.data) {
custInfoData.value = resp.data;
}
});
});
};
/**
* 隐藏评级窗口
*/
const hide = () => {
dialogRef.value.hide();
};
/**
* 隐藏窗口事件
*/
const hideEvent = () => {
afterComplete();
};
const afterComplete = () => {
//
hide();
emit('refresh');
};
defineExpose({
show,
hide,
});
await dictionary.load();
</script>

9
irbs.frontend/src/views/custRating/company/RatingGrid.vue

@ -0,0 +1,9 @@
<template>
<div style="height: 100%">
<RatingManager :show-rating-dialog="false"></RatingManager>
</div>
</template>
<script setup lang="ts">
import RatingManager from './RatingManager.vue';
</script>

287
irbs.frontend/src/views/custRating/company/RatingManager.vue

@ -0,0 +1,287 @@
<template>
<div style="height: 100%">
<w-grid
ref="companyRatingGridRef"
title="客户评级列表"
:data-url="Environment.apiContextPath('api/irbs/companyRating')"
:fetch-data-url="Environment.apiContextPath('api/irbs/companyRating/query')"
:sort-no="true"
group-mode="alone"
:checkbox-selection="false"
:toolbar-actions="[
'query',
'reset',
'separator',
{
extend: 'add',
label: '发起评级',
click: () => {
custSelectDialogRef.show();
},
},
{
extend: 'edit',
label: '评级',
enableIf: (args) => {
if (
args.selected &&
(args.selected['processStatus'] === RatingProcessStatus.AWAIT_RATING ||
args.selected['processStatus'] === RatingProcessStatus.AWAIT_SUBMIT ||
args.selected['processStatus'] === RatingProcessStatus.BACK)
) {
return true;
}
return false;
},
click: (args) => {
ratingData = args.selected;
readMode = false;
ratingDialogRef.show();
},
},
// {
// extend: 'remove',
// label: '',
// click: () => {},
// },
'separator',
{
extend: 'view',
click: (args) => {
ratingData = args.selected;
readMode = true;
ratingDialogRef.show();
},
},
'export',
'separator',
[
{
name: 'otherOp',
label: '其他操作',
icon: 'device_hub',
},
{
name: 'viewGray',
extend: 'view',
label: '查看灰度模型结果',
click: (args) => {
grayDialogRef.show(args.selected);
},
},
'separator',
{
extend: 'remove',
name: 'removeRatingAndProcess',
label: '强制删除',
click: (args: any) => {
removeRatingAndProcess(args);
},
},
],
'separator',
]"
:query-criteria="{
operator: 'and',
criteria: [
{
fieldName: 'triggerType',
operator: 'equals',
value: 'INDEPENDENT',
},
{
fieldName: 'launchUser',
operator: 'equals',
value: SessionManager.getUser().loginName,
},
],
}"
:sort-by="['-createDate']"
:query-form-fields="[
{ label: '申请编号', name: 'id', type: 'w-text' },
{ label: '客户号', name: 'custNo', type: 'w-text' },
{ label: '客户名称', name: 'custName', type: 'w-text' },
{ label: '认定等级', name: 'finalLevel', type: 'w-select', options: RatingLevelOptions },
{ label: '流程状态', name: 'processStatus', type: 'w-select', options: Options.enum(RatingProcessStatusEnum) },
{ label: '评级状态', name: 'ratingStatus', type: 'w-select', options: Options.enum(RatingStatusEnum) },
]"
:columns="[
{ name: 'id', label: '申请编号', align: 'center' },
{ name: 'custNo', label: '客户号', align: 'center' },
{ name: 'custName', label: '客户名称', width: 150 },
{ name: 'industryTypeName', label: '行业类型' },
{ name: 'modelScore', label: '模型得分' },
{ name: 'modelLevel', label: '模型等级' },
{ name: 'adjLevel', label: '调整后等级' },
{ name: 'initLevel', label: '初评等级' },
{
name: 'finalLevel',
label: '认定等级',
format: (val) => {
if (!Tools.isEmpty(val)) {
return {
componentType: RatingLevel,
attrs: {
level: val,
dense: true,
},
};
}
return val;
},
},
{
name: 'pd',
label: '违约概率',
format: (val) => {
if (val && typeof val === 'number') {
return Round(val * 100, 2) + '%';
}
return val;
},
},
{ name: 'effectiveTime', label: '评级生效日', format: Formater.dateOnly() },
{ name: 'matureTime', label: '评级失效日', format: Formater.dateOnly() },
{ name: 'ratingStatus', label: '评级状态', format: Formater.enum(RatingStatusEnum) },
{ name: 'launchUser', label: '发起人' },
{ name: 'processStatus', label: '流程状态', format: Formater.enum(RatingProcessStatusEnum) },
{ name: 'currentAssignee', label: '当前处理人' },
]"
></w-grid>
<CustSelectDialog ref="custSelectDialogRef" @refresh="refreshTable" @submit-handler="selectCustSubmit"></CustSelectDialog>
<RatingDialog ref="ratingDialogRef" :rating-data="ratingData" :read-mode="readMode" @refresh="refreshTable"></RatingDialog>
<GrayModelDialog ref="grayDialogRef" @refresh="refreshTable"></GrayModelDialog>
<LoadingDialog ref="loadingDialogRef"></LoadingDialog>
</div>
</template>
<script setup lang="ts">
import { ref, nextTick, onMounted } from 'vue';
import { useQuasar } from 'quasar';
import { axios, EnumTools, Environment, Formater, noErrorAxios, NotifyManager, Options, SessionManager, Tools, ServerExceptionHandler } from 'platform-core';
import { RatingLevelOptions, RatingProcessStatus, Round } from '../CustRating.ts';
import GrayModelDialog from '../GrayModelDialog.vue';
import RatingDialog from './RatingDialog.vue';
import RatingLevel from '../RatingLevel.vue';
import CustSelectDialog from './CustSelectDialog.vue';
import LoadingDialog from '@/views/components/LoadingDialog.vue';
const $q = useQuasar();
const companyRatingGridRef = ref();
const custSelectDialogRef = ref();
const loadingDialogRef = ref();
const ratingDialogRef = ref();
const grayDialogRef = ref();
const ratingData = ref({});
const readMode = ref(false);
const enums = await EnumTools.fetch(['irbs.cust.rating.enums.RatingStatus', 'irbs.cust.rating.enums.RatingProcessStatus']);
const RatingStatusEnum = enums['RatingStatus'];
const RatingProcessStatusEnum = enums['RatingProcessStatus'];
const props = defineProps({
//
showRatingDialog: { type: Boolean, default: false },
//
custNo: { type: String, default: undefined },
});
const removeRatingAndProcess = (args: any) => {
$q.dialog({
title: '询问',
message: '是否确认删除已生成评级信息及流程信息?',
cancel: { noCaps: true },
ok: { noCaps: true },
persistent: true,
}).onOk(() => {
axios
.post(Environment.apiContextPath('api/irbs/companyRating/removeRatingAndProcess/' + args.selected['id']))
.then((resp) => {
if (resp && resp.data) {
NotifyManager.info('删除成功');
companyRatingGridRef.value.refresh();
}
})
.catch((error) => {
console.info('error====', error);
NotifyManager.warn('删除失败');
});
});
};
const showLoading = (msg: string = '正在处理,请稍等...') => {
loadingDialogRef.value.show(msg);
};
const hideLoading = () => {
loadingDialogRef.value.hide();
};
/**
* 选择客户提交处理方法
* @param data 选择的客户数据
*/
const selectCustSubmit = async (data: any) => {
//
const monthLimit = await axios.post(Environment.apiContextPath('api/irbs/companyRating/getMonthRatingLimit/' + data['custNo']));
if (monthLimit?.data?.result === true && monthLimit?.data?.tactics === '1') {
NotifyManager.warn('该客户当月已达评级次数上限(' + monthLimit?.data?.num + '次),无法再次发起评级');
return;
} else if (monthLimit?.data?.result === true && monthLimit?.data?.tactics === '2') {
$q.dialog({
title: '询问',
message: '该客户当月已发起评级次数超过:' + monthLimit?.data?.num + '次,是否继续发起?',
cancel: { noCaps: true },
ok: { noCaps: true },
persistent: true,
}).onOk(() => {
generateRating(data);
});
} else {
generateRating(data);
}
};
//
const generateRating = (data: any) => {
showLoading();
const requestParams = {
method: 'POST',
headers: { 'content-type': 'application/json;charset=utf-8;' },
url: Environment.apiContextPath('api/irbs/companyRating/generateRating/' + data['custNo']),
};
noErrorAxios(requestParams)
.then((resp: any) => {
hideLoading();
if (resp?.code === 200) {
refreshTable();
custSelectDialogRef.value.hide();
//
if (resp.data) {
ratingData.value = resp.data;
readMode.value = false;
ratingDialogRef.value.show();
}
}
})
.catch((error) => {
hideLoading();
if (error?.code === 1001) {
//
NotifyManager.error('验证错误');
} else {
console.info('error=========', error);
ServerExceptionHandler.handle(error);
}
});
};
const refreshTable = () => {
companyRatingGridRef.value.refresh();
};
onMounted(async () => {
if (props.showRatingDialog && props.custNo) {
await selectCustSubmit({ custNo: props.custNo });
}
});
</script>

71
irbs.frontend/src/views/custRating/company/RatingPage.vue

@ -0,0 +1,71 @@
<template>
<w-splitter :size="46" horizontal disable reverse unit="px" style="height: 100%">
<template #before>
<Step ref="stepRef" class="h-full"></Step>
</template>
<template #after>
<div class="p-1 flex justify-end gap-x-4">
<AnnotationButton></AnnotationButton>
<!-- <TestCalcButton></TestCalcButton> -->
<NextButton></NextButton>
<WorkflowButton></WorkflowButton>
</div>
</template>
</w-splitter>
</template>
<script setup lang="ts">
import { VueTools } from 'platform-core';
import { getCurrentInstance, onMounted, provide, ref, shallowRef } from 'vue';
import RatingLevel from '../RatingLevel.vue';
import NextButton from './NextButton.vue';
import Step from './Step.vue';
import TestCalcButton from './TestCalcButton.vue';
import { Rating } from './ts/Rating';
import WorkflowButton from './WorkflowButton.vue';
import AnnotationButton from './AnnotationButton.vue';
const RatingLevelRef = shallowRef(RatingLevel);
const props = defineProps({
ratingData: {
type: Object,
default: () => {
return {};
},
},
readMode: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(['afterComplete']);
const rating = new Rating(props.ratingData, props.readMode);
await rating.dictionary.load();
await rating.enum.load();
await rating.systemParameter.load();
const ratingLevelFormat = (modelLevel: any, size: string) => {
return {
componentType: RatingLevelRef,
attrs: {
level: modelLevel,
dense: true,
size: size,
},
};
};
rating.refs.setRatingLevelFormatFunction(ratingLevelFormat);
onMounted(() => {
rating.step.setCurrStep(rating.ratingData.value['currentStep']);
});
//
const instance = getCurrentInstance();
// API
VueTools.expose2Instance(instance);
//
rating.setInstance(instance);
provide('rating', rating);
</script>

58
irbs.frontend/src/views/custRating/company/Step.vue

@ -0,0 +1,58 @@
<template>
<w-splitter :size="75" class="h-full" unit="px" disable>
<template #before>
<div class="h-full" style="display: flex; align-items: center">
<q-tabs
v-model="rating.step.currStep.value"
vertical
indicator-color="amber"
active-color="amber"
align="left"
:dense="rating.cm.isAwaitSubmitProcessStatus.value"
style="height: auto"
@update:model-value="rating.step.click"
>
<template v-for="(step, index) in rating.step.steps.value" :key="step.value">
<q-tab :name="step.value" :icon="step.icon" :label="step.label" :disable="step.disable" style="padding: 2px">
<q-tooltip v-if="rating.cm.isAwaitSubmitProcessStatus.value" transition-show="rotate" transition-hide="rotate">{{ step.tooltip }}</q-tooltip>
</q-tab>
<div v-if="index !== rating.step.steps.value.length - 1 && rating.cm.isAwaitSubmitProcessStatus.value" style="width: 100%; text-align: center">
<q-icon name="bi-arrow-down-short" size="sm"></q-icon>
</div>
</template>
</q-tabs>
</div>
</template>
<template #after>
<!-- 切分窗口 -->
<w-splitter v-if="!rating.cm.isAwaitSubmitProcessStatus.value" :size="77" :separator-color="rating.separatorColor" class="h-full">
<template #before>
<q-tab-panels v-model="rating.step.currStep.value" class="p-0 h-full">
<q-tab-panel v-for="step in rating.step.steps.value" :key="step.value" :name="step.value" class="p-0 h-full">
<Content :step="step"></Content>
</q-tab-panel>
</q-tab-panels>
</template>
<template #after>
<Opinion></Opinion>
</template>
</w-splitter>
<!-- 不切分 -->
<q-tab-panels v-else v-model="rating.step.currStep.value" class="p-0 h-full">
<q-tab-panel v-for="step in rating.step.steps.value" :key="step.value" :name="step.value" class="p-0 h-full">
<Content :step="step"></Content>
</q-tab-panel>
</q-tab-panels>
</template>
</w-splitter>
</template>
<script setup lang="ts">
import { inject, ref, onMounted } from 'vue';
import { Rating } from './ts/Rating';
import Content from './Content.vue';
import { Constant } from './ts/Constant';
import Opinion from './content/Opinion.vue';
const rating = <Rating>inject('rating');
</script>

73
irbs.frontend/src/views/custRating/company/TestCalcButton.vue

@ -0,0 +1,73 @@
<template>
<q-btn v-if="showComputed" icon="calculate" color="primary" label="试算" :disable="testCalcNum < 1" @click="click">
<q-badge :color="testCalcNum > 3 ? 'green' : 'red'" floating
>{{ testCalcNum }}
<q-tooltip> 剩余可试算次数 </q-tooltip>
</q-badge>
</q-btn>
</template>
<script setup lang="ts">
import { ref, inject, computed, onBeforeMount } from 'vue';
import { useQuasar } from 'quasar';
import { axios, Environment, NotifyManager, Tools } from 'platform-core';
import { Rating } from './ts/Rating';
import { Step } from './ts/Step';
import { Constant } from './ts/Constant';
import { round } from './ts/Utils';
const $q = useQuasar();
const rating = <Rating>inject('rating');
const testCalcNum = ref(0);
const getTestCalcNum = async () => {
const resp = await axios.get(Environment.apiContextPath('api/irbs/companyRating/getQualTestCalcNum'), {
params: { ratingId: rating.ratingData.value['id'] },
});
if (resp?.data) {
testCalcNum.value = resp.data;
}
};
const click = async () => {
const result = rating.step.qualFormValidate();
if (!result['result']) {
return;
}
rating.showLoading('正在计算定性得分,请稍等...');
const url = Environment.apiContextPath('api/irbs/companyRating/qualSaveIndices/' + Constant.QUAL_SAVE_OPERATOR.TEST);
const resp = await axios.post(url, result['submitData']).catch((error) => {
rating.hideLoading();
NotifyManager.error('计算出错,请联系管理员');
console.info('error====', error);
});
rating.hideLoading();
if (resp?.data?.success === true) {
rating.ratingData.value['lastQualTestCalcScore'] = round(resp.data.qualScore, 2);
$q.dialog({
title: '消息',
message: '本次试算定性得分为:' + round(resp.data.qualScore, 2),
cancel: false,
persistent: true,
});
//
getTestCalcNum();
} else if (resp?.data?.success === false && !Tools.isEmpty(resp.data.errorMsg)) {
if (rating.ratingData.value['lastQualTestCalcScore']) {
NotifyManager.error(resp.data.errorMsg + ',与最后一次试算结果相同,得分为:' + rating.ratingData.value['lastQualTestCalcScore']);
} else {
NotifyManager.error(resp.data.errorMsg);
}
}
};
const showComputed = computed(() => {
if (rating.cm.isApplyUserProcessStatus.value && rating.step.currStep.value === Step.type.quanQualAnalysis.value) {
return true;
}
return false;
});
onBeforeMount(() => {
getTestCalcNum();
});
</script>

48
irbs.frontend/src/views/custRating/company/WorkflowButton.vue

@ -0,0 +1,48 @@
<template>
<w-workflow-action
v-if="showComputed"
:task-id="rating.ratingData.value['taskId']"
:data="rating.opinionData.value"
:default-submit-button="false"
:action-url="Environment.apiContextPath('/api/irbs/companyRatingProcess/submit')"
@before-submit="
async (action, callback) => {
rating.opinionData.value = {
transientVariables: {
opaVal: action.transientVariables.goback,
desc: '客户名称:' + rating.ratingData.value['custName'],
},
data: rating.refs.overturnFormRefFunction().getData(),
};
const validateResult = await rating.refs.overturnFormRefFunction().validate();
if (validateResult) {
callback(true);
} else {
callback(false);
}
}
"
@after-submit="
() => {
rating.instance.emit('afterComplete');
}
"
>
</w-workflow-action>
</template>
<script setup lang="ts">
import { inject, computed } from 'vue';
import { Environment } from 'platform-core';
import { Rating } from './ts/Rating';
import { Step } from './ts/Step';
const rating = <Rating>inject('rating');
const showComputed = computed(() => {
if (rating.cm.isAwaitSubmitProcessStatus.value) {
return rating.step.currStep.value === Step.type.opinion.value;
} else if (rating.ratingData.value['taskId']) {
return true;
}
return false;
});
</script>

18
irbs.frontend/src/views/custRating/company/content/AdjustItem.vue

@ -0,0 +1,18 @@
<template>
<w-splitter :size="45" unit="px" horizontal disable>
<template #before>
<FirstRatingResult></FirstRatingResult>
</template>
<template #after>
<AdjustItemGrid class="px-1"></AdjustItemGrid>
</template>
</w-splitter>
</template>
<script setup lang="ts">
import { inject, computed } from 'vue';
import { Rating } from '../ts/Rating';
import FirstRatingResult from './FirstRatingResult.vue';
import AdjustItemGrid from './AdjustItemGrid.vue';
const rating = <Rating>inject('rating');
</script>

68
irbs.frontend/src/views/custRating/company/content/AdjustItemGrid.vue

@ -0,0 +1,68 @@
<template>
<w-grid
ref="adjustItemGridRef"
title="评级调整项列表"
:dense="rating.dense"
:pageable="false"
:hide-bottom="true"
:auto-fetch-data="false"
:checkbox-selection="false"
group-mode="alone"
group-by-field="indexCategory"
:stripe="true"
:sort-no="false"
:config-button="false"
:toolbar-actions="['expand']"
:columns="[
{
name: 'value',
label: '符合',
width: 80,
align: 'center',
sortable: false,
format: (val) => {
return {
componentType: 'w-checkbox',
bindModelValue: true,
attrs: {
dense: true,
disableIf: () => {
// if (showNextBtnComputed) {
// return false;
// }
return false;
},
},
};
},
},
{
name: 'indexCategory',
label: '调整项分类',
showIf: false,
},
{
name: 'indexCode',
label: '调整项编码',
sortable: false,
},
{
name: 'adjustItemName',
label: '调整项(<span class=\'text-red-500\'>若客户符合调整项所描述情况,请在【符合】列打勾</span>)',
sortable: false,
},
]"
@row-db-click="() => {}"
></w-grid>
</template>
<script setup lang="ts">
import { inject, ref } from 'vue';
import { Rating } from '../ts/Rating';
const rating = <Rating>inject('rating');
const adjustItemGridRef = ref();
const getAdjustItemGridRef = () => {
return adjustItemGridRef.value;
};
rating.refs.setAdjustItemGridRefFunction(getAdjustItemGridRef);
</script>

36
irbs.frontend/src/views/custRating/company/content/AdjustItemIndex.vue

@ -0,0 +1,36 @@
<template>
<w-splitter :size="34" horizontal unit="px" disable class="h-full">
<template #before>
<w-card-panel
label="评级调整项详情"
:bordered="false"
:title-mode="true"
icon="build_circle"
:icon-attrs="{ color: 'yellow' }"
color="yellow"
></w-card-panel>
</template>
<template #after>
<q-list v-if="rating.adjustItemScoreDtlData.value" padding>
<template v-for="(values, key, a) in rating.adjustItemScoreDtlData.value" :key="a">
<q-item-label header>{{ key }}</q-item-label>
<template v-for="(dtl, index) in values" :key="index">
<q-item>
<q-item-section>
<q-item-label>{{ index + 1 }}{{ dtl['INDEX_NAME'] }}</q-item-label>
<!-- <q-item-label caption> {{ dtl['TEXT'] }} </q-item-label> -->
</q-item-section>
</q-item>
</template>
<!-- <q-separator /> -->
</template>
</q-list>
</template>
</w-splitter>
</template>
<script setup lang="ts">
import { inject } from 'vue';
import { Rating } from '../ts/Rating';
const rating = <Rating>inject('rating');
</script>

38
irbs.frontend/src/views/custRating/company/content/CreditReportGrid.vue

@ -0,0 +1,38 @@
<template>
<w-grid
ref="creditReportGridRef"
title="征信报告"
:dense="rating.dense"
:pageable="false"
:hide-bottom="true"
:auto-fetch-data="false"
:fetch-data-url="Environment.apiContextPath('api/irbs/creditReport')"
:checkbox-selection="false"
:config-button="false"
:columns="[
{ name: 'id', label: '报告号' },
{ name: 'custNo', label: '客户号' },
{ name: 'entName', label: '客户名称' },
{ name: 'reportDate', label: '报告日期', format: Formater.dateOnly() },
{ name: 'expiryDate', label: '征信有效期', format: Formater.dateOnly() },
{ name: 'blankInd', label: '是否白户', slot: 'isValid' },
]"
:query-criteria="{
fieldName: 'custNo',
operator: 'equals',
value: '',
}"
></w-grid>
</template>
<script setup lang="ts">
import { ref, inject } from 'vue';
import { Formater, Environment } from 'platform-core';
import { Rating } from '../ts/Rating';
const rating = <Rating>inject('rating');
const creditReportGridRef = ref();
const getCreditReportGridRef = () => {
return creditReportGridRef.value;
};
rating.refs.setCreditReportGridRefFunction(getCreditReportGridRef);
</script>

29
irbs.frontend/src/views/custRating/company/content/CustBaseInfo.vue

@ -0,0 +1,29 @@
<template>
<q-card flat bordered>
<q-card-section>
<span class="text-3xl">
{{ rating.custInfoData.value['custName'] }}
<!-- <q-badge v-if="rating.custInfoData.value['marketEnterprisesInd'] === '1'" color="red" align="top">上市</q-badge> -->
<q-badge color="orange" align="top">客户号{{ rating.custInfoData.value['custNo'] }}</q-badge
>&nbsp; <q-badge color="green" align="top">上市</q-badge>&nbsp;
<q-badge color="red" align="top">{{ Formater.dictionary(rating.dictionary.customerSize)(rating.custInfoData.value['customerSize']) }}</q-badge
>&nbsp; <q-badge align="top">{{ Formater.dictionary(rating.dictionary.registeredType)(rating.custInfoData.value['registeredType']) }}</q-badge
>&nbsp; <q-badge color="secondary" align="top">{{ rating.custInfoData.value['groupCustInd'] === '1' ? '集团客户' : '非集团客户' }}</q-badge
>&nbsp;
<q-badge v-if="rating.custInfoData.value['groupCustInd'] === '1'" align="top"
>集团成员类别{{ Formater.dictionary(rating.dictionary.memberTypeCd)(rating.custInfoData.value['memberType']) }}</q-badge
><template v-if="rating.custInfoData.value['groupCustInd'] === '1'">&nbsp;</template>
<q-badge color="blue" align="top">行业{{ rating.custInfoData.value['industryTypeName'] }}</q-badge
>&nbsp; <q-badge color="brown" align="top">成立日期{{ rating.custInfoData.value['buildDate'] }}</q-badge
>&nbsp;
</span>
</q-card-section>
</q-card>
</template>
<script setup lang="ts">
import { Formater } from 'platform-core';
import { inject } from 'vue';
import { Rating } from '../ts/Rating';
const rating = <Rating>inject('rating');
</script>

61
irbs.frontend/src/views/custRating/company/content/CustInfo.vue

@ -0,0 +1,61 @@
<template>
<w-splitter :size="48" unit="px" horizontal disable>
<template #before>
<div class="py-1 pl-1 flex flex-nowrap items-start gap-x-2">
<div class="flex-1">
<w-form
:cols-num="3"
:fields="[
{
label: '评分卡',
name: 'modelName',
type: 'w-select',
options: ['A评分卡', 'B评分卡', 'K评分卡'],
defaultValue: rating.ratingData.value['modelName'],
},
{
label: '更改评分卡说明',
name: 'updateModelDesc',
type: 'w-text',
colSpan: 2,
},
]"
>
</w-form>
</div>
<div class="flex-none pr-4">
<q-btn icon="task_alt" color="primary" label="更改" @click="click" />
</div>
</div>
</template>
<template #after>
<w-splitter :size="70" :limits="[30, 95]" horizontal :separator-color="rating.separatorColor">
<template #before>
<FinanceReportTabs></FinanceReportTabs>
</template>
<template #after>
<CreditReportGrid class="px-1"></CreditReportGrid>
</template>
</w-splitter>
</template>
</w-splitter>
</template>
<script setup lang="ts">
import { ref, inject } from 'vue';
import { DialogManager } from 'platform-core';
import { Rating } from '../ts/Rating';
import FinanceReportGrid from './FinanceReportGrid.vue';
import CreditReportGrid from './CreditReportGrid.vue';
import CustBaseInfo from './CustBaseInfo.vue';
import FinanceReportTabs from './FinanceReportTabs.vue';
const rating = <Rating>inject('rating');
const custFormRef = ref();
const getCustFormRef = () => {
return custFormRef.value;
};
rating.refs.setCustFormRefFunction(getCustFormRef);
const click = () => {
DialogManager.confirm('更改评分卡后流程会经总行进行审批,确认要更改评分卡吗', () => {});
};
</script>

46
irbs.frontend/src/views/custRating/company/content/DefaultCognizanceGrid.vue

@ -0,0 +1,46 @@
<template>
<w-grid
ref="defaultCognizanceGridRef"
:dense="rating.dense"
:pageable="false"
:hide-bottom="true"
:auto-fetch-data="true"
:toolbar-actions="[]"
:fetch-data-url="Environment.apiContextPath('api/irbs/defaultCognizance')"
:checkbox-selection="false"
:config-button="false"
:columns="[
{ name: 'custNo', label: '客户号' },
{ name: 'custName', label: '客户名称' },
{ name: 'levelHis', label: '违约时评级' },
{ name: 'effectiveDate', label: '违约发起时间' },
{ name: 'creator', label: '违约发起人' },
{ name: 'defaultProcessStatus', label: '违约流程状态' },
{ name: 'defalutType', label: '违约认定类型' },
]"
:query-criteria="{
operator: 'and',
criteria: [
{
fieldName: 'custNo',
operator: 'equals',
value: rating.ratingData.value['custNo'],
},
{
fieldName: 'status',
operator: 'equals',
value: Constant.DEFAULT_PROCESS_STATUS.PASS,
},
],
}"
:sort-by="['-effectiveDate']"
></w-grid>
</template>
<script setup lang="ts">
import { Environment } from 'platform-core';
import { inject } from 'vue';
import { Constant } from '../ts/Constant';
import { Rating } from '../ts/Rating';
const rating = <Rating>inject('rating');
</script>

45
irbs.frontend/src/views/custRating/company/content/DefaultRebirthGrid.vue

@ -0,0 +1,45 @@
<template>
<w-grid
ref="defaultRebirthGridRef"
:dense="rating.dense"
:pageable="false"
:hide-bottom="true"
:auto-fetch-data="true"
:toolbar-actions="[]"
:fetch-data-url="Environment.apiContextPath('api/irbs/defaultRebirth')"
:checkbox-selection="false"
:config-button="false"
:columns="[
{ name: 'custNo', label: '客户号' },
{ name: 'custName', label: '客户名称' },
{ name: 'rebirthEffectiveDate', label: '重生生效时间' },
{ name: 'creator', label: '重生发起人' },
{ name: 'rebirthProcessStatus', label: '重生流程状态' },
{ name: 'defalutRebornType', label: '违约重生类型' },
]"
:query-criteria="{
operator: 'and',
criteria: [
{
fieldName: 'custNo',
operator: 'equals',
value: rating.ratingData.value['custNo'],
},
{
fieldName: 'rebirthProcessStatus',
operator: 'equals',
value: Constant.DEFAULT_PROCESS_STATUS.PASS,
},
],
}"
:sort-by="['-rebirthEffectiveDate']"
></w-grid>
</template>
<script setup lang="ts">
import { Environment } from 'platform-core';
import { inject } from 'vue';
import { Constant } from '../ts/Constant';
import { Rating } from '../ts/Rating';
const rating = <Rating>inject('rating');
</script>

49
irbs.frontend/src/views/custRating/company/content/FinanceProjectCompare.vue

@ -0,0 +1,49 @@
<template>
<div v-if="!Tools.isEmpty(valueComputed)">{{ formatAmt(valueComputed) }} <q-icon :name="iconComputed?.name" :color="iconComputed?.color"></q-icon></div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { Tools } from 'platform-core';
import { formatAmt } from '../ts/Utils';
const props = defineProps({
//
value: { type: Number, default: undefined },
//
previousPeriod: { type: Number, default: undefined },
});
const icon = {
equals: {
name: 'horizontal_rule',
color: 'green',
},
up: {
name: 'arrow_upward',
color: 'blue',
},
down: {
name: 'arrow_downward',
color: 'orange',
},
};
const valueComputed = computed(() => {
if (!Tools.isEmpty(props.value) && !Tools.isEmpty(props.previousPeriod)) {
const result = props.value - props.previousPeriod;
return result;
}
return undefined;
});
const iconComputed = computed(() => {
if (!Tools.isEmpty(valueComputed.value) && valueComputed.value === 0) {
return icon.equals;
} else if (!Tools.isEmpty(valueComputed.value) && valueComputed.value > 0) {
return icon.up;
} else if (!Tools.isEmpty(valueComputed.value) && valueComputed.value < 0) {
return icon.down;
}
return undefined;
});
</script>

74
irbs.frontend/src/views/custRating/company/content/FinanceProjectGrid.vue

@ -0,0 +1,74 @@
<template>
<w-grid
:dense-body="true"
:pageable="false"
:hide-bottom="true"
:auto-fetch-data="true"
:dense="true"
:fetch-data-url="Environment.apiContextPath('api/irbs/financeReportDetail/query/' + rating.ratingData.value['custId'])"
:checkbox-selection="false"
:sort-no="true"
:config-button="false"
:columns="columnsComputed"
:query-criteria="props.queryCriteria"
:sort-by="['projectCode']"
></w-grid>
</template>
<script setup lang="ts">
import { inject, onMounted, computed } from 'vue';
import { Environment } from 'platform-core';
import { Rating } from '../ts/Rating';
import FinanceProjectCompare from './FinanceProjectCompare.vue';
import { formatAmt } from '../ts/Utils';
const rating = <Rating>inject('rating');
const props = defineProps({
queryCriteria: { type: Object, default: undefined },
});
const columnsComputed = computed(() => {
const columns = <any>[
{ name: 'code', label: '科目编码' },
{ name: 'name', label: '科目名称' },
];
if (rating.financeReport.value.length > 0) {
const columnNames = ['value', 'previousPeriodvalue', 'previousPeriod2value', 'previousPeriod3value'];
rating.financeReport.value.forEach((report: any, index: number) => {
const year = report['endDate'].substring(0, 4);
columns.push({
name: year,
label: year,
columns: [
{
name: columnNames[index],
label: '本期值',
align: 'right',
format: (val, row) => {
return formatAmt(val);
},
},
{
name: year + 'comparePreviousPeriod',
label: '比上期',
align: 'right',
format: (val, row) => {
return {
componentType: FinanceProjectCompare,
attrs: {
value: row[columnNames[index]],
previousPeriod: index === columnNames.length - 1 ? undefined : row[columnNames[index + 1]],
},
};
},
},
],
});
});
}
return columns;
});
onMounted(() => {
rating.api.loadFinanceReport();
});
</script>

146
irbs.frontend/src/views/custRating/company/content/FinanceReportGrid.vue

@ -0,0 +1,146 @@
<template>
<div>
<w-grid
ref="financeReportGridRef"
title="财务报表"
:dense="rating.dense"
:height="150"
:pageable="false"
:hide-bottom="true"
:auto-fetch-data="false"
:fetch-data-url="Environment.apiContextPath('api/irbs/financeReport/getReport')"
:checkbox-selection="false"
:config-button="false"
:columns="[
{ name: 'endDate', label: '财报日期', format: Formater.dateOnly() },
// { name: 'type', label: '', format: Formater.dictionary(rating.dictionary.financeTypeCd) },
{
name: 'type',
label: '报表类型',
format: Formater.dictionary(rating.dictionary.financeTypeCd),
},
{ name: 'sort', label: '报表类别', format: Formater.dictionary(rating.dictionary.financeSortTypeCd) },
{ name: 'auditedInd', label: '是否审计', format: Formater.dictionary(rating.dictionary.financeStatusCd) },
{ name: 'caliber', label: '报表口径', format: Formater.dictionary(rating.dictionary.caliberCd) },
{ name: 'currency', label: '报表币种', format: Formater.dictionary(rating.dictionary.currencyTypeCd) },
{ name: 'userNo', label: '经办人' },
{ name: 'remarks', label: '备注' },
{
name: 'op',
label: '操作',
format: opFormat,
},
]"
></w-grid>
<w-dialog ref="financeReportDetailDialogRef" title="财报详情" width="80%" height="80%" body-padding="0px 0px 0px 0px">
<w-splitter :size="60" horizontal unit="px" disable class="h-full">
<template #before>
<div class="p-1">
<w-info-panel :info="financeReport.otherInfo" :column-num="5" :label-width="150"></w-info-panel>
</div>
</template>
<template #after>
<div class="flex flex-nowrap items-start h-full">
<div class="flex-none h-full">
<q-tabs v-model="detailTab" vertical indicator-color="amber" active-color="amber">
<template v-for="report in financeReport.tabsComputed.value" :key="report.value">
<q-tab :name="report.value" :icon="report.icon" :label="report.label" />
</template>
</q-tabs>
</div>
<q-separator vertical />
<div class="flex-1 h-full">
<q-tab-panels
v-model="detailTab"
:keep-alive="true"
animated
swipeable
vertical
transition-prev="jump-up"
transition-next="jump-up"
class="h-full"
>
<template v-for="report in financeReport.tabsComputed.value" :key="report.value">
<q-tab-panel :name="report.value" class="h-full p-1">
<FinanceProjectGrid
:query-criteria="{
operator: 'and',
criteria: [
{
fieldName: 'reportId',
operator: 'equals',
value: financeReport.reportId,
},
{
fieldName: 'projectType',
operator: 'equals',
value: report.value,
},
],
}"
></FinanceProjectGrid>
</q-tab-panel>
</template>
</q-tab-panels>
</div>
</div>
</template>
</w-splitter>
</w-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, nextTick, reactive, inject } from 'vue';
import { Formater, Environment } from 'platform-core';
import { Rating } from '../ts/Rating';
import FinanceProjectGrid from './FinanceProjectGrid.vue';
import { FinanceReport, Constant } from '../ts/FinanceReport';
const rating = <Rating>inject('rating');
const financeReportGridRef = ref();
const getFinanceReportGridRef = () => {
return financeReportGridRef.value;
};
rating.refs.setFinanceReportGridRefFunction(getFinanceReportGridRef);
const financeReportDetailDialogRef = ref();
const financeReport = new FinanceReport();
const splitterModel = ref(60);
const detailTab = ref('');
const opFormat = (value, row) => {
if (row && row['sort']) {
return {
componentType: 'q-chip',
attrs: {
dense: true,
color: 'primary',
icon: 'visibility',
textColor: 'white',
square: true,
size: rating.dense ? 'xs' : 'md',
label: '查 看',
onclick: () => {
financeReport.reportType.value = row['sort'];
if (financeReport.reportType.value === Constant.REPORT_TYPE_COMPANY) {
detailTab.value = FinanceReport.reportDetail.c_balance_sheet.value;
} else {
detailTab.value = FinanceReport.reportDetail.p_balance_sheet.value;
}
financeReport.reportId = row['id'];
financeReportDetailDialogRef.value.show();
financeReport.otherInfo = [];
financeReport.otherInfo.push({ label: '财务报表截至日期', value: row['endDate'], format: Formater.dateOnly() });
financeReport.otherInfo.push({ label: '是否经过审计', value: row['auditedInd'], format: Formater.dictionary(rating.dictionary.financeStatusCd) });
financeReport.otherInfo.push({ label: '财务报表类别', value: row['sort'], format: Formater.dictionary(rating.dictionary.financeTypeCd) });
financeReport.otherInfo.push({ label: '财务报表口径', value: row['caliber'], format: Formater.dictionary(rating.dictionary.caliberCd) });
financeReport.otherInfo.push({ label: '财务报表币种', value: row['currency'], format: Formater.dictionary(rating.dictionary.currencyTypeCd) });
},
},
};
} else {
return '';
}
};
</script>

39
irbs.frontend/src/views/custRating/company/content/FinanceReportTabs.vue

@ -0,0 +1,39 @@
<template>
<div class="h-full">
<w-splitter :size="36" horizontal class="h-full" unit="px" disable>
<template #before>
<q-tabs v-model="tab" inline-label dense indicator-color="amber" align="right" active-color="amber">
<template v-for="report in financeReport.tabsComputed.value" :key="report.value">
<q-tab :name="report.value" :icon="report.icon" :label="report.label" />
</template>
</q-tabs>
</template>
<template #after>
<q-tab-panels v-model="tab" :keep-alive="true" animated swipeable vertical transition-prev="jump-up" transition-next="jump-up" class="h-full">
<template v-for="report in financeReport.tabsComputed.value" :key="report.value">
<q-tab-panel :name="report.value" class="h-full p-1">
<FinanceProjectGrid
:query-criteria="{
fieldName: 'projectType',
operator: 'equals',
value: report.value,
}"
></FinanceProjectGrid>
</q-tab-panel>
</template>
</q-tab-panels>
</template>
</w-splitter>
</div>
</template>
<script setup lang="ts">
import { inject, ref } from 'vue';
import { Environment, Formater } from 'platform-core';
import { Rating } from '../ts/Rating';
import { FinanceReport, Constant } from '../ts/FinanceReport';
import FinanceProjectGrid from './FinanceProjectGrid.vue';
const rating = <Rating>inject('rating');
const financeReport = new FinanceReport();
const tab = ref(FinanceReport.reportDetail.c_balance_sheet.value);
</script>

29
irbs.frontend/src/views/custRating/company/content/FirstRatingResult.vue

@ -0,0 +1,29 @@
<template>
<div v-if="rating.systemParameter.showTotalScore.value">
<span class="pl-[8px]">初评结果</span>
<w-info-panel :info="rating.firstRatingData.value" :column-num="4"></w-info-panel>
</div>
<div v-else>
<q-list dense>
<q-item>
<q-item-section avatar>初评结果</q-item-section>
<q-item-section>
<RatingLevelSlider v-model="firstRatingLevelComputed"></RatingLevelSlider>
</q-item-section>
</q-item>
</q-list>
</div>
</template>
<script setup lang="ts">
import { inject, computed } from 'vue';
import { Rating } from '../ts/Rating';
import RatingLevelSlider from '../../RatingLevelSlider.vue';
const rating = <Rating>inject('rating');
const firstRatingLevelComputed = computed(() => {
if (rating.firstRatingData.value && rating.firstRatingData.value.length > 0) {
return rating.firstRatingData.value[0]['value'];
}
return undefined;
});
</script>

51
irbs.frontend/src/views/custRating/company/content/HistRatingGrid.vue

@ -0,0 +1,51 @@
<template>
<w-grid
ref="custHistRatingGridRef"
:dense="rating.dense"
:pageable="false"
:hide-bottom="true"
:auto-fetch-data="true"
:toolbar-actions="[]"
:fetch-data-url="Environment.apiContextPath('api/irbs/companyRating')"
:checkbox-selection="false"
:config-button="false"
:columns="[
{ name: 'id', label: '申请编号' },
{ name: 'custNo', label: '客户号' },
{ name: 'custName', label: '客户名称' },
// { name: 'modelScore', label: '' },
{ name: 'modelLevel', label: '系统评级等级' },
{ name: 'adjLevel', label: '调整等级' },
{ name: 'initLevel', label: '初评等级' },
{ name: 'finalLevel', label: '最终等级' },
{ name: 'effectiveTime', label: '生效日期', format: Formater.dateOnly() },
{ name: 'matureTime', label: '到期日期', format: Formater.dateOnly() },
{ name: 'ratingStatus', label: '评级状态', format: Formater.enum(rating.enum.ratingStatus) },
{ name: 'launchUser', label: '发起人' },
{ name: 'processStatus', label: '状态', format: Formater.enum(rating.enum.ratingProcessStatus) },
]"
:query-criteria="{
operator: 'and',
criteria: [
{
fieldName: 'custNo',
operator: 'equals',
value: rating.ratingData.value['custNo'],
},
{
fieldName: 'processStatus',
operator: 'equals',
value: Constant.DEFAULT_PROCESS_STATUS.PASS,
},
],
}"
></w-grid>
</template>
<script setup lang="ts">
import { Environment, Formater } from 'platform-core';
import { inject } from 'vue';
import { Constant } from '../ts/Constant';
import { Rating } from '../ts/Rating';
const rating = <Rating>inject('rating');
</script>

33
irbs.frontend/src/views/custRating/company/content/HistTab.vue

@ -0,0 +1,33 @@
<template>
<div class="h-full">
<w-splitter :size="36" horizontal class="h-full" unit="px" disable>
<template #before>
<q-tabs v-model="tab" inline-label dense indicator-color="amber" align="left" active-color="amber">
<template v-for="item in HistGird.tabs" :key="item.value">
<q-tab :name="item.value" :icon="item.icon" :label="item.label" />
</template>
</q-tabs>
</template>
<template #after>
<q-tab-panels v-model="tab" :keep-alive="true" animated swipeable vertical transition-prev="jump-up" transition-next="jump-up" class="h-full">
<template v-for="item in HistGird.tabs" :key="item.value">
<q-tab-panel :name="item.value" class="h-full p-1">
<HistRatingGrid v-if="item.value === HistGird.type.histRating.value"></HistRatingGrid>
<DefaultCognizanceGrid v-else-if="item.value === HistGird.type.defaultCognizance.value"></DefaultCognizanceGrid>
<DefaultRebirthGrid v-else-if="item.value === HistGird.type.defaultRebirth.value"></DefaultRebirthGrid>
</q-tab-panel>
</template>
</q-tab-panels>
</template>
</w-splitter>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { HistGird } from '../ts/HistGrid';
import HistRatingGrid from './HistRatingGrid.vue';
import DefaultCognizanceGrid from './DefaultCognizanceGrid.vue';
import DefaultRebirthGrid from './DefaultRebirthGrid.vue';
const tab = ref(HistGird.type.histRating.value);
</script>

40
irbs.frontend/src/views/custRating/company/content/Opinion.vue

@ -0,0 +1,40 @@
<template>
<div class="h-full pl-1">
<w-splitter v-if="!rating.cm.isAwaitSubmitProcessStatus.value" :size="rating.readMode ? 100 : 50" horizontal class="h-full" disable :show-separator="false">
<template #before>
<w-splitter :size="36" horizontal class="h-full" unit="px" disable :show-separator="false">
<template #before>
<q-tabs v-model="histTab" dense no-caps inline-label align="right">
<q-tab name="timeline" icon="query_builder" label="审批时间线" />
<q-tab name="grid" icon="grid_on" label="审批列表" />
</q-tabs>
</template>
<template #after>
<q-tab-panels v-model="histTab" class="p-0 h-full">
<q-tab-panel name="timeline" class="p-0 pt-1 px-2 h-full">
<Timeline></Timeline>
</q-tab-panel>
<q-tab-panel name="grid" class="p-0 pt-1 h-full">
<OpinionGrid></OpinionGrid>
</q-tab-panel>
</q-tab-panels>
</template>
</w-splitter>
</template>
<template #after>
<Overturn></Overturn>
</template>
</w-splitter>
<Overturn v-else class="p-1"></Overturn>
</div>
</template>
<script setup lang="ts">
import { inject, ref } from 'vue';
import { Rating } from '../ts/Rating';
import OpinionGrid from './OpinionGrid.vue';
import Overturn from './Overturn.vue';
import Timeline from './Timeline.vue';
const rating = <Rating>inject('rating');
const histTab = ref('timeline');
</script>

44
irbs.frontend/src/views/custRating/company/content/OpinionGrid.vue

@ -0,0 +1,44 @@
<template>
<w-grid
ref="opinionGridRef"
:dense="rating.dense"
:pageable="false"
:hide-bottom="true"
:auto-fetch-data="true"
:fetch-data-url="histOpinionUrl"
:checkbox-selection="false"
:config-button="false"
:columns="[
{ name: 'roleName', label: '岗位名称', width: 150 },
{ name: 'userCode', label: '操作人工号', width: 100 },
{ name: 'userName', label: '操作人名称', width: 100 },
{ name: 'operationOpinion', label: '操作意见', width: 100, format: Formater.dictionary({ items: RatingProcessOperationStatus }) },
{ name: 'adjReason', label: '意见说明', width: 200 },
{ name: 'lastModifyDate', label: '操作时间', width: 150 },
{ name: 'isOverturn', label: '是否推翻', width: 80, format: Formater.yesNo() },
{ name: 'overturnType', label: '推翻类型', width: 100, format: Formater.dictionary(rating.dictionary.overturnType) },
{ name: 'suggestLevel', label: '建议等级', width: 100 },
{ name: 'fileCount', label: '附件列表', width: 100 },
]"
:query-criteria="{
fieldName: 'ratingId',
operator: 'equals',
value: rating.ratingData.value['id'],
}"
:sort-by="['-lastModifyDate']"
></w-grid>
</template>
<script setup lang="ts">
import { inject, ref } from 'vue';
import { Environment, Formater } from 'platform-core';
import { Rating } from '../ts/Rating';
import { RatingProcessOperationStatus } from '../../CustRating';
const rating = <Rating>inject('rating');
const overturnFormRef = ref();
const getOverturnFormRef = () => {
return overturnFormRef.value;
};
rating.refs.setOverturnFormRefFunction(getOverturnFormRef);
const histOpinionUrl = Environment.apiContextPath('api/irbs/ratingOverturn');
</script>

77
irbs.frontend/src/views/custRating/company/content/Overturn.vue

@ -0,0 +1,77 @@
<template>
<w-card-panel v-bind="panelAttrsComputed">
<div class="flex flex-row gap-4">
<div v-if="rating.cm.isAwaitSubmitProcessStatus.value" class="basis-1/4">
<w-info-panel :info="rating.overturnTipData.value" :column-num="1"></w-info-panel>
</div>
<div :class="rating.cm.isAwaitSubmitProcessStatus.value ? 'basis-2/3' : 'flex-1'">
<w-form
ref="overturnFormRef"
:fields="[
{ label: '附件', name: 'file', type: 'w-file' },
{ label: '是否推翻', name: 'isOverturn', type: 'w-checkbox' },
{
label: '推翻类型',
name: 'overturnType',
type: 'w-select',
options: Options.dictionary(rating.dictionary.overturnType),
requiredIf: true,
showIf: (args) => {
if (args?.form && args.form.getFieldValue('isOverturn')) {
return true;
}
return false;
},
},
{
label: '建议等级',
name: 'suggestLevel',
type: 'w-select',
options: RatingLevelOptions,
requiredIf: true,
showIf: (args) => {
if (args?.form && args.form.getFieldValue('isOverturn')) {
return true;
}
return false;
},
},
{
label: '意见说明',
name: 'adjReason',
type: 'w-textarea',
requiredIf: true,
},
]"
:cols-num="1"
></w-form>
</div>
</div>
</w-card-panel>
</template>
<script setup lang="ts">
import { Options } from 'platform-core';
import { computed, ref, inject } from 'vue';
import { RatingLevelOptions } from '../../CustRating';
import { Rating } from '../ts/Rating';
const rating = <Rating>inject('rating');
const overturnFormRef = ref();
const getOverturnFormRef = () => {
return overturnFormRef.value;
};
rating.refs.setOverturnFormRefFunction(getOverturnFormRef);
const panelAttrsComputed = computed(() => {
if (rating.cm.isAwaitSubmitProcessStatus.value) {
return {
label: '评级推翻',
icon: 'model_training',
};
} else {
return {
label: '审批意见',
icon: 'comment',
};
}
});
</script>

106
irbs.frontend/src/views/custRating/company/content/QualAnalysis.vue

@ -0,0 +1,106 @@
<template>
<w-splitter :size="titleSplitterModel" horizontal unit="px" disable class="h-full">
<template #before>
<w-card-panel :bordered="false" :title-mode="true" icon="scatter_plot" :icon-attrs="{ color: 'green' }" color="green">
<template #label>
<div class="flex justify-between">
<div>
定性分析<q-badge v-if="existsWaitSelectComputed" color="red" floating transparent class="qa-badge">{{
rating.waitSelectFields.value.length
}}</q-badge>
</div>
<q-toggle v-if="showToggleComputed" v-model="qaMode" color="blue" dense size="40px" icon="bi-quora" label="问卷模式" />
<q-toggle v-if="props.readOnly" v-model="showOptionsModel" color="blue" dense size="40px" icon="hdr_auto" label="显示全部选项" />
</div>
</template>
</w-card-panel>
</template>
<template #after>
<w-form
v-show="showQaPanelComputed"
ref="qa-qualFormRef"
:cols-num="1"
:fields="qaFormFieldComputed"
class="px-1 py-1"
@update-value="qaFormUpdateValue"
></w-form>
<w-form
v-show="!showQaPanelComputed"
ref="qualitativeFormRef"
:fields="qualFormFieldsComputed"
:cols-num="1"
:y-gap="10"
class="pl-1 py-1"
@update-value="formUpdateValue"
></w-form>
</template>
</w-splitter>
</template>
<script setup lang="ts">
import { inject, ref, computed } from 'vue';
import { Rating } from '../ts/Rating';
const qualitativeFormRef = ref();
const rating = <Rating>inject('rating');
const titleSplitterModel = ref(34);
const getQualitativeFormRef = () => {
return qualitativeFormRef.value;
};
rating.refs.setQualitativeFormRefFunction(getQualitativeFormRef);
const props = defineProps({
//
qualQaMode: { type: Boolean, default: true },
//
readOnly: { type: Boolean, default: false },
//
showOptions: { type: Boolean, default: false },
});
const qaMode = ref(props.readOnly ? false : props.qualQaMode);
const showOptionsModel = ref(props.showOptions);
const qaFormFieldComputed = computed(() => {
const result = <any>[];
if (rating.waitSelectFields.value?.length > 0) {
result.push({
type: 'w-form-group',
label: rating.waitSelectFields.value[0]['group'],
mode: 'card',
fields: [rating.waitSelectFields.value[0]['field']],
});
}
return result;
});
const showQaPanelComputed = computed(() => {
return showToggleComputed.value && qaMode.value;
});
const showToggleComputed = computed(() => {
return props.qualQaMode && existsWaitSelectComputed.value;
});
const existsWaitSelectComputed = computed(() => {
return rating.waitSelectFields.value.length > 0 && !props.readOnly;
});
const qualFormFieldsComputed = computed(() => {
if (showOptionsModel.value) {
return rating.qualFormData.value;
}
return rating.qualSimpleOptionData.value;
});
const qaFormUpdateValue = (args) => {
qualitativeFormRef.value.setFieldValue(args.fieldName, args.fieldValue);
rating.waitSelectFields.value = rating.waitSelectFields.value.slice(1);
};
const formUpdateValue = (args) => {
const result = rating.waitSelectFields.value.filter((field) => field.field['name'] !== args.fieldName);
rating.waitSelectFields.value = result;
};
</script>
<style lang="css">
.qa-badge {
position: relative;
top: -7px;
right: -2px;
cursor: inherit;
}
</style>

51
irbs.frontend/src/views/custRating/company/content/QuanAnalysis.vue

@ -0,0 +1,51 @@
<template>
<w-splitter :size="34" horizontal unit="px" disable class="h-full">
<template #before>
<w-card-panel label="定量分析" :bordered="false" :title-mode="true" icon="bar_chart" :icon-attrs="{ color: 'teal' }" color="teal"></w-card-panel>
</template>
<template #after>
<div v-if="rating.systemParameter.showTotalScore.value" class="p-1">
<w-card-panel :info="rating.quanData.value"></w-card-panel>
</div>
<div v-if="rating.systemParameter.showIndex.value" class="rating-quan">
<q-list>
<template v-for="(values, key, a) in rating.quanScoreDtlData.value" :key="a">
<!-- <q-item-label header><q-icon name="toc" size="25px" />定量指标详情</q-item-label> -->
<template v-for="(dtl, index) in values" :key="index">
<q-item>
<q-item-section>
<q-item-label>{{ dtl['INDEX_NAME'] }}</q-item-label>
<q-item-label caption>
{{ round(dtl['INDEX_VALUE'], 2) }}
</q-item-label>
</q-item-section>
<q-item-section v-if="rating.systemParameter.showIndexScore.value && !Tools.isEmpty(dtl['INDEX_SCORE'])" side>
<q-chip :clickable="false" :ripple="false" color="green" text-color="white">
{{ round(dtl['INDEX_SCORE'], 2) }}
</q-chip>
</q-item-section>
</q-item>
</template>
</template>
</q-list>
</div>
</template>
</w-splitter>
</template>
<script setup lang="ts">
import { Tools } from 'platform-core';
import { inject } from 'vue';
import { Rating } from '../ts/Rating';
import { round } from '../ts/Utils';
const rating = <Rating>inject('rating');
</script>
<style lang="css">
.rating-quan {
padding-top: 10px;
}
.rating-quan .text-caption {
font-size: 1rem;
color: #2196f3;
}
</style>

20
irbs.frontend/src/views/custRating/company/content/QuanQualAnalysis.vue

@ -0,0 +1,20 @@
<template>
<div class="h-full">
<w-splitter :size="25" :separator-color="rating.separatorColor" class="h-full">
<template #before>
<QuanAnalysis></QuanAnalysis>
</template>
<template #after>
<QualAnalysis :qual-qa-mode="rating.systemParameter.qualQaMode.value" :show-options="true"></QualAnalysis>
</template>
</w-splitter>
</div>
</template>
<script setup lang="ts">
import { inject } from 'vue';
import { Rating } from '../ts/Rating';
import QuanAnalysis from './QuanAnalysis.vue';
import QualAnalysis from './QualAnalysis.vue';
const rating = <Rating>inject('rating');
</script>

36
irbs.frontend/src/views/custRating/company/content/ReportIndex.vue

@ -0,0 +1,36 @@
<template>
<div v-if="rating.systemParameter.reportShowScoreDtl.value" class="h-full">
<w-splitter :size="25" :separator-color="rating.separatorColor">
<template #before>
<QuanAnalysis></QuanAnalysis>
</template>
<template #after>
<w-splitter v-if="splitComputed" :size="65" class="h-full" :separator-color="rating.separatorColor">
<template #before>
<QualAnalysis :qual-qa-mode="false" :read-only="true"></QualAnalysis>
</template>
<template #after>
<AdjustItemIndex></AdjustItemIndex>
</template>
</w-splitter>
<QualAnalysis v-else :qual-qa-mode="false" :read-only="true"></QualAnalysis>
</template>
</w-splitter>
</div>
</template>
<script setup lang="ts">
import { inject, computed } from 'vue';
import { Rating } from '../ts/Rating';
import QuanAnalysis from './QuanAnalysis.vue';
import QualAnalysis from './QualAnalysis.vue';
import AdjustItemIndex from './AdjustItemIndex.vue';
const rating = <Rating>inject('rating');
const splitComputed = computed(() => {
if (rating.adjustItemScoreDtlData.value && Object.keys(rating.adjustItemScoreDtlData.value).length > 0) {
return true;
}
return false;
});
</script>

34
irbs.frontend/src/views/custRating/company/content/ReportInfo.vue

@ -0,0 +1,34 @@
<template>
<div class="h-full">
<w-splitter :size="splitterSizeComputed" :limits="[0, Infinity]" horizontal unit="px" disable class="h-full">
<template #before>
<ReportRating></ReportRating>
</template>
<template #after>
<w-splitter :size="70" horizontal :separator-color="rating.separatorColor">
<template #before>
<ReportIndex></ReportIndex>
</template>
<template #after>
<HistTab></HistTab>
</template>
</w-splitter>
</template>
</w-splitter>
</div>
</template>
<script setup lang="ts">
import { computed, inject } from 'vue';
import { Rating } from '../ts/Rating';
import HistTab from './HistTab.vue';
import ReportIndex from './ReportIndex.vue';
import ReportRating from './ReportRating.vue';
const rating = <Rating>inject('rating');
const splitterSizeComputed = computed(() => {
if (rating.showAllRatingInfoModel.value) {
return 125;
}
return 40;
});
</script>

157
irbs.frontend/src/views/custRating/company/content/ReportRating.vue

@ -0,0 +1,157 @@
<template>
<!-- <w-card-panel label="评级结果" :bordered="false">
<div class="flex">
<div class="flex-1 text-center">
<div>模型名称</div>
<div :class="valueClassComputed">
<q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['modelName']" />
</div>
</div>
<div class="flex-1 text-center">
<div>模型级别</div>
<div :class="valueClassComputed">
<q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['modelLevel']" />
</div>
</div>
<div class="flex-1 text-center">
<div>调整后级别</div>
<div v-if="rating.ratingData.value['adjLevel']" :class="valueClassComputed">
<q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['adjLevel']" />
</div>
</div>
<div class="flex-1 text-center">
<div>推翻级别</div>
<div v-if="rating.ratingData.value['tf']" :class="valueClassComputed">
<q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['tf']" />
</div>
</div>
<div class="flex-1 text-center">
<div>最终认定级别</div>
<div v-if="rating.ratingData.value['finalLevel']" :class="valueClassComputed">
<q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['finalLevel']" />
</div>
</div>
<div class="flex-1 text-center">
<div>客户经理</div>
<div v-if="rating.ratingData.value['managerName']" :class="valueClassComputed">
<q-chip outline square size="md" :clickable="false" :ripple="false" :label="rating.ratingData.value['managerName']" />
</div>
</div>
</div>
</w-card-panel> -->
<div class="flex">
<div class="flex-1">
<div :class="classComputed">
<div :class="itemClassComputed">
<div :class="labelClassComputed">模型名称</div>
<div :class="valueClassComputed">{{ rating.ratingData.value['modelName'] }}</div>
</div>
<div :class="itemClassComputed">
<div :class="labelClassComputed">模型评级等级</div>
<div :class="valueClassComputed" @mouseover="handleHover('.rr-modelLevel', rating.ratingData.value['modelLevel'])" @mouseout="handleOut">
<span class="rr-modelLevel underline">{{ rating.ratingData.value['modelLevel'] }}</span>
</div>
</div>
<div :class="itemClassComputed">
<div :class="labelClassComputed">调整后级别</div>
<div :class="valueClassComputed" @mouseover="handleHover('.rr-adjLevel', rating.ratingData.value['adjLevel'])" @mouseout="handleOut">
<span class="rr-adjLevel underline">{{ rating.ratingData.value['adjLevel'] }}</span>
</div>
</div>
<div :class="itemClassComputed">
<div :class="labelClassComputed">最终认定级别</div>
<div :class="valueClassComputed" @mouseover="handleHover('.rr-finalLevel', rating.ratingData.value['finalLevel'])" @mouseout="handleOut">
<span class="rr-finalLevel underline">{{ rating.ratingData.value['finalLevel'] }}</span>
</div>
</div>
<div :class="itemClassComputed">
<div :class="labelClassComputed">客户经理</div>
<div :class="valueClassComputed">{{ rating.ratingData.value['managerName'] }}</div>
</div>
<template v-if="rating.showAllRatingInfoModel.value">
<div :class="itemClassComputed">
<div :class="labelClassComputed">初始级别</div>
<div :class="valueClassComputed" @mouseover="handleHover('.rr-initLevel', rating.ratingData.value['initLevel'])" @mouseout="handleOut">
<span class="rr-initLevel underline">{{ rating.ratingData.value['initLevel'] }}</span>
</div>
</div>
<div :class="itemClassComputed">
<div :class="labelClassComputed">上一次建议级别</div>
<div :class="valueClassComputed" @mouseover="handleHover('.rr-spLevel', rating.ratingData.value['spLevel'])" @mouseout="handleOut">
<span class="rr-spLevel underline">{{ rating.ratingData.value['spLevel'] }}</span>
</div>
</div>
<div :class="itemClassComputed">
<div :class="labelClassComputed">评级发起日期</div>
<div :class="valueClassComputed" v-html="Formater.dateOnly()(rating.ratingData.value['startTime'])"></div>
</div>
<div :class="itemClassComputed">
<div :class="labelClassComputed">评级生效日期</div>
<div :class="valueClassComputed" v-html="Formater.dateOnly()(rating.ratingData.value['effectiveTime'])"></div>
</div>
<div :class="itemClassComputed">
<div :class="labelClassComputed">评级到期日期</div>
<div :class="valueClassComputed" v-html="Formater.dateOnly()(rating.ratingData.value['matureTime'])"></div>
</div>
<div :class="itemClassComputed">
<div :class="labelClassComputed">评级状态</div>
<div :class="valueClassComputed">{{ Formater.enum(rating.enum.ratingStatus)(rating.ratingData.value['ratingStatus']) }}</div>
</div>
<div :class="itemClassComputed">
<div :class="labelClassComputed">流程状态</div>
<div :class="valueClassComputed">{{ Formater.enum(rating.enum.ratingProcessStatus)(rating.ratingData.value['processStatus']) }}</div>
</div>
</template>
</div>
</div>
<div class="flex-none pr-1 pt-1">
<q-btn
flat
round
color="primary"
size="sm"
:icon="rating.showAllRatingInfoModel.value ? 'bi-arrow-up-circle-fill' : 'bi-arrow-down-circle-fill'"
@click="rating.showAllRatingInfoModel.value = !rating.showAllRatingInfoModel.value"
/>
</div>
<q-popup-proxy v-model="ratingLevelShowModel" :target="ratingLevelTarget" no-parent-event>
<div style="height: 80px; width: 650px; padding: 20px 10px 10px 20px">
<RatingLevelSlider v-model="ratingLevel"></RatingLevelSlider>
</div>
</q-popup-proxy>
</div>
</template>
<script setup lang="ts">
import { ref, inject, computed } from 'vue';
import { Formater } from 'platform-core';
import { Rating } from '../ts/Rating';
import RatingLevelSlider from '../../RatingLevelSlider.vue';
const ratingLevelShowModel = ref(false);
const ratingLevel = ref('');
const ratingLevelTarget = ref('');
const rating = <Rating>inject('rating');
const itemClassComputed = computed(() => {
return 'flex items-center';
});
const labelClassComputed = computed(() => {
return 'flex-none text-gray-500';
});
const valueClassComputed = computed(() => {
return 'flex-1 text-2xl';
});
const classComputed = computed(() => {
if (rating.showAllRatingInfoModel) {
return 'grid grid-cols-5 gap-3 pl-3 pt-1';
}
return 'grid grid-cols-5 gap-x-3 pl-3 pt-1';
});
const handleHover = (target_, ratingLevel_: any) => {
ratingLevel.value = ratingLevel_;
ratingLevelTarget.value = target_;
ratingLevelShowModel.value = true;
};
const handleOut = () => {
ratingLevelShowModel.value = false;
};
</script>

82
irbs.frontend/src/views/custRating/company/content/Timeline.vue

@ -0,0 +1,82 @@
<template>
<div class="rating-timeline">
<div v-if="timelineData.length < 1" style="display: flex; justify-content: center; align-items: center; height: 100%">
<q-icon size="2em" name="info" />{{ $t('tip.noData') }}
</div>
<q-timeline v-else layout="dense" side="right" color="secondary">
<template v-for="(opinion, index) in timelineData" :key="index">
<q-timeline-entry side="left" :color="timelineEntryColor(opinion)">
<div style="background-color: #f9f9f9">
{{ opinion['adjReason'] }}
</div>
<template #subtitle>
<div class="flex justify-between">
<span class="text-sm">{{ timelineTitleFormat(opinion) }}</span>
<div class="flex gap-x-2">
<span>{{ opinion['userName'] }}</span>
<span class="text-blue-grey-6">7分钟以前</span>
</div>
</div>
</template>
</q-timeline-entry>
</template>
</q-timeline>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, inject } from 'vue';
import { $t, axios, Environment } from 'platform-core';
import { Rating } from '../ts/Rating';
import { RatingProcessOperationStatus } from '../../CustRating';
const timelineData = ref([]);
const rating = <Rating>inject('rating');
const histOpinionUrl = Environment.apiContextPath('api/irbs/ratingOverturn');
const timelineTitleFormat = (opinion: any) => {
const findResult = RatingProcessOperationStatus.find((item) => item['value'] === opinion['operationOpinion']);
if (findResult) {
return findResult['label'];
}
return '';
};
const timelineSubTitleFormat = (opinion: any) => {
return opinion['userName'] + ' ' + timelineTitleFormat(opinion) + ' ' + '7分钟以前';
};
const timelineEntryColor = (opinion: any) => {
const operator = opinion['operationOpinion'];
if (operator === '20') {
return 'red';
} else if (operator === '30' || operator === '40') {
return 'orange';
}
return 'secondary';
};
onMounted(() => {
const urlSearchParams = new URLSearchParams({ sortBy: ['-lastModifyDate'] });
urlSearchParams.append('pageable', 'false');
const criteria = {
fieldName: 'ratingId',
operator: 'equals',
value: rating.ratingData.value['id'],
};
urlSearchParams.append('criteria', JSON.stringify(criteria));
axios.get(histOpinionUrl, { params: urlSearchParams }).then((resp) => {
if (resp['code'] === 200) {
timelineData.value = resp.data.content;
}
});
});
</script>
<style lang="css">
.rating-timeline .q-timeline--dense--right .q-timeline__entry {
padding-left: 25px;
}
.rating-timeline .q-timeline__title {
margin-top: 0;
margin-bottom: 0px;
}
.rating-timeline .q-timeline__content {
padding-bottom: 10px;
}
</style>

37
irbs.frontend/src/views/custRating/company/ts/ComputedManager.ts

@ -0,0 +1,37 @@
import { computed } from 'vue';
import { Rating } from './Rating';
import { Step } from './Step';
import { Constant } from './Constant';
/**
*
*/
export class ComputedManager {
rating: Rating;
constructor(rating_: Rating) {
this.rating = rating_;
}
/**
*
*/
isApplyUserProcessStatus = computed(() => {
const processStatus = this.rating.ratingData.value['processStatus'];
const showProcessStatus = [Constant.RATING_PROCESS_STATUS.AWAIT_SUBMIT, Constant.RATING_PROCESS_STATUS.BACK];
if (showProcessStatus.includes(processStatus)) {
return true;
}
return false;
});
/**
*
*/
isAwaitSubmitProcessStatus = computed(() => {
if (this.rating.ratingData.value['processStatus'] === Constant.RATING_PROCESS_STATUS.AWAIT_SUBMIT) {
return true;
}
return false;
});
}

76
irbs.frontend/src/views/custRating/company/ts/Constant.ts

@ -0,0 +1,76 @@
class RatingProcessStatus {
/**
*
*/
static AWAIT_RATING = 'AWAIT_RATING';
/**
*
*/
static AWAIT_SUBMIT = 'AWAIT_SUBMIT';
/**
* 退
*/
static BACK = 'BACK';
/**
*
*/
static APPROVALING = 'APPROVALING';
/**
*
*/
static PASS = 'PASS';
/**
*
*/
static NEGATIVED = 'NEGATIVED';
/**
*
*/
static END = 'END';
}
class PageType {
static APPLY = 'apply';
static AUDIT = 'audit';
static DETAIL = 'detail';
}
class QualSaveOperator {
/**
*
*/
static TEST = 'test';
/**
*
*/
static NEXT = 'next';
}
class DefaultProcessStatus {
/**
*
*/
static PASS = '03';
}
/**
*
*/
export class Constant {
/**
*
*/
static RATING_PROCESS_STATUS = RatingProcessStatus;
/**
*
*/
static PAGE_TYPE = PageType;
/**
*
*/
static QUAL_SAVE_OPERATOR = QualSaveOperator;
/**
*
*/
static DEFAULT_PROCESS_STATUS = DefaultProcessStatus;
}

90
irbs.frontend/src/views/custRating/company/ts/Dictionary.ts

@ -0,0 +1,90 @@
import { DictionaryTools } from 'platform-core';
/**
* 使
*/
export class Dictionary {
/**
*
*/
overturnType: any;
/**
*
*/
customerSize: any;
/**
*
*/
registeredType: any;
/**
*
*/
goverFinanceType: any;
/**
*
*/
goverFinanceSign: any;
/**
*
*/
registrationCd: any;
/**
*
*/
nationCd: any;
/**
*
*/
memberTypeCd: any;
/**
*
*/
financeTypeCd: any;
/**
*
*/
financeSortTypeCd: any;
/**
*
*/
financeStatusCd: any;
/**
*
*/
caliberCd: any;
/**
*
*/
currencyTypeCd: any;
async load() {
const arr = await DictionaryTools.fetch([
'OVERTURN_TYPE',
'CustomerSizeCd',
'REGISTERED_TYPE',
'GOVER_FINANCE_TYPE',
'GOVER_FINANCE_SIGN',
'REGISTRATION_CD',
'NATION_CD',
'MEMBER_TYPE_CD',
'FinanceTypeCd',
'FinanceSortTypeCd',
'FinanceStatusCd',
'CaliberCd',
'CurrencyTypeCd',
]);
this.overturnType = arr['OVERTURN_TYPE'];
this.customerSize = arr['CustomerSizeCd'];
this.registeredType = arr['REGISTERED_TYPE'];
this.goverFinanceType = arr['GOVER_FINANCE_TYPE'];
this.goverFinanceSign = arr['GOVER_FINANCE_SIGN'];
this.registrationCd = arr['REGISTRATION_CD'];
this.nationCd = arr['NATION_CD'];
this.memberTypeCd = arr['MEMBER_TYPE_CD'];
this.financeTypeCd = arr['FinanceTypeCd'];
this.financeSortTypeCd = arr['FinanceSortTypeCd'];
this.financeStatusCd = arr['FinanceStatusCd'];
this.caliberCd = arr['CaliberCd'];
this.currencyTypeCd = arr['CurrencyTypeCd'];
}
}

21
irbs.frontend/src/views/custRating/company/ts/Enum.ts

@ -0,0 +1,21 @@
import { EnumTools } from 'platform-core';
/**
*
*/
export class Enum {
/**
*
*/
ratingStatus: any;
/**
*
*/
ratingProcessStatus: any;
async load() {
const arr = await EnumTools.fetch(['irbs.cust.rating.enums.RatingStatus', 'irbs.cust.rating.enums.RatingProcessStatus']);
this.ratingStatus = arr['RatingStatus'];
this.ratingProcessStatus = arr['RatingProcessStatus'];
}
}

79
irbs.frontend/src/views/custRating/company/ts/FinanceReport.ts

@ -0,0 +1,79 @@
import { Ref, ref, computed } from 'vue';
type DetailType = {
label: string;
value: string;
icon: string;
order: number;
};
/**
*
*/
export class Constant {
/**
* -
*/
static REPORT_TYPE_COMPANY = '1';
/**
* -
*/
static REPORT_TYPE_PUBLIC_INSTITUTION = '2';
}
export class FinanceReport {
/**
*
*/
static reportDetail = {
/**
*
*/
c_balance_sheet: <DetailType>{ label: '企业类资产负债表', value: '01', icon: 'currency_yen', order: 2 },
/**
*
*/
c_statement_of_cash_flows: <DetailType>{ label: '企业类现金流表', value: '02', icon: 'money', order: 3 },
/**
*
*/
c_income_statement: <DetailType>{ label: '企业类损益表', value: '03', icon: 'remove_circle_outline', order: 4 },
/**
*
*/
p_balance_sheet: <DetailType>{ label: '事业类资产负债表', value: '11', icon: 'currency_yen', order: 5 },
/**
*
*/
p_income_statement: <DetailType>{ label: '事业类资产负债表', value: '12', icon: 'price_change', order: 6 },
};
/**
*
*/
reportType: Ref = ref(Constant.REPORT_TYPE_COMPANY);
/**
* ID
*/
reportId: string = '';
/**
*
*/
otherInfo = <any>[];
/**
* tabs计算属性
*/
tabsComputed = computed(() => {
const result = <any>[];
if (this.reportType.value === Constant.REPORT_TYPE_COMPANY) {
result.push(FinanceReport.reportDetail.c_balance_sheet);
result.push(FinanceReport.reportDetail.c_statement_of_cash_flows);
result.push(FinanceReport.reportDetail.c_income_statement);
} else {
result.push(FinanceReport.reportDetail.p_balance_sheet);
result.push(FinanceReport.reportDetail.p_income_statement);
}
return result;
});
}

31
irbs.frontend/src/views/custRating/company/ts/HistGrid.ts

@ -0,0 +1,31 @@
type HistGridType = {
label: string;
value: string;
icon: string;
order: number;
};
export class HistGird {
/**
*
*/
static type = {
/**
*
*/
histRating: <HistGridType>{ label: '客户历史评级', value: 'histRating', icon: 'hotel_class', order: 1 },
/**
*
*/
defaultCognizance: <HistGridType>{ label: '违约认定历史', value: 'defaultCognizance', icon: 'pan_tool_alt', order: 2 },
/**
*
*/
defaultRebirth: <HistGridType>{ label: '违约重生历史', value: 'defaultRebirth', icon: 'auto_mode', order: 3 },
};
/**
* tabs
*/
static tabs = Object.values(HistGird.type).sort((a, b) => a.order - b.order);
}

179
irbs.frontend/src/views/custRating/company/ts/Rating.ts

@ -0,0 +1,179 @@
import { Ref, ref } from 'vue';
import { Loading } from 'quasar';
import { Step } from './Step';
import { Dictionary } from './Dictionary';
import { Enum } from './Enum';
import { Refs } from './Refs';
import { RequestApi } from './RequestApi';
import { SystemParameter } from './SystemParameter';
import { ComputedManager } from './ComputedManager';
/**
*
*/
export class Rating {
/**
*
*/
instance: any;
/**
*
*/
readMode: boolean = false;
/**
* 使
*/
dense: boolean = true;
/**
* 线
*/
separatorColor: string = 'orange';
/**
*
*/
mainLevelSize: string = '60px';
/**
*
*/
gridHeight: number = 200;
/**
*
*/
dictionary: Dictionary;
/**
*
*/
enum: Enum;
/**
*
*/
step: Step;
/**
*
*/
cm: ComputedManager;
/**
*
*/
ratingData: Ref = ref({});
/**
* ref对象的函数管理器
*/
refs: Refs;
/**
* API
*/
api: RequestApi;
/**
*
*/
systemParameter: SystemParameter;
/**
*
*/
custInfoData: Ref = ref({});
/**
*
*/
quanData: Ref = ref([]);
/**
*
*/
quanScoreDtlData: Ref = ref({});
/**
*
*/
qualFormData: Ref = ref([]);
/**
*
*/
qualSimpleOptionData: Ref = ref([]);
/**
*
*/
qualFormObj: Ref = ref({});
/**
*
*/
qualData: Ref = ref([]);
/**
*
*/
qualScoreDtlData: Ref = ref([]);
/**
*
*/
firstRatingData: Ref = ref([]);
/**
*
*/
adjustItemScoreDtlData: Ref = ref([]);
/**
*
*/
adjustItemData: Ref = ref([]);
/**
*
*/
adjustItemObj: Ref = ref({});
/**
*
*/
reportRatingMainData: Ref = ref([]);
/**
*
*/
reportCustRatingData: Ref = ref([]);
/**
*
*/
overturnTipData: Ref = ref([]);
/**
*
*/
opinionData: Ref = ref({});
/**
*
*/
financeReport: Ref = ref([]);
/**
*
*/
waitSelectFields: Ref = ref([]);
/**
*
*/
showAllRatingInfoModel: Ref = ref(false);
/**
*
* @param ratingData_
* @param readMode_
*/
constructor(ratingData_: any, readMode_: boolean) {
this.readMode = readMode_;
this.ratingData.value = ratingData_;
this.refs = new Refs();
this.dictionary = new Dictionary();
this.enum = new Enum();
this.cm = new ComputedManager(this);
this.systemParameter = new SystemParameter();
this.step = new Step(this);
this.api = new RequestApi(this);
}
showLoading(msg: string = '正在获取数据,请稍等...') {
Loading.show({
message: msg,
boxClass: 'bg-grey-2 text-grey-9',
spinnerColor: 'primary',
});
}
hideLoading() {
Loading.hide();
}
setInstance(instance_: any) {
this.instance = instance_;
}
}

52
irbs.frontend/src/views/custRating/company/ts/Refs.ts

@ -0,0 +1,52 @@
export class Refs {
/**
* ref对象函数
*/
financeReportGridRefFunction: any;
/**
* ref对象函数
*/
creditReportGridRefFunction: any;
/**
* ref对象函数
*/
custFormRefFunction: any;
/**
* ref对象函数
*/
qualitativeFormRefFunction: any;
/**
*
*/
ratingLevelFormatFunction: any;
/**
* ref对象函数
*/
adjustItemGridRefFunction: any;
/**
* ref对象函数
*/
overturnFormRefFunction: any;
setFinanceReportGridRefFunction(fun: () => void) {
this.financeReportGridRefFunction = fun;
}
setCreditReportGridRefFunction(fun: () => void) {
this.creditReportGridRefFunction = fun;
}
setCustFormRefFunction(fun: () => void) {
this.custFormRefFunction = fun;
}
setQualitativeFormRefFunction(fun: () => void) {
this.qualitativeFormRefFunction = fun;
}
setRatingLevelFormatFunction(fun: (modelLevel: any, size?: string) => any) {
this.ratingLevelFormatFunction = fun;
}
setAdjustItemGridRefFunction(fun: () => void) {
this.adjustItemGridRefFunction = fun;
}
setOverturnFormRefFunction(fun: () => void) {
this.overturnFormRefFunction = fun;
}
}

466
irbs.frontend/src/views/custRating/company/ts/RequestApi.ts

@ -0,0 +1,466 @@
import { axios, Environment, Tools, NotifyManager, Formater } from 'platform-core';
import { Rating } from './Rating';
import { Constant } from './Constant';
import { round, groupBy } from './Utils';
import { Step } from './Step';
import { StepType } from './type/StepType';
/**
* api
*/
export class RequestApi {
rating: Rating;
constructor(rating_: Rating) {
this.rating = rating_;
}
/**
*
*/
async loadCustInfo() {
const custId = this.rating.ratingData.value['custId'];
const custNo = this.rating.ratingData.value['custNo'];
await axios.get(Environment.apiContextPath('api/irbs/ratingCompanyCustomer/' + custId)).then((resp) => {
if (resp && resp.data) {
this.rating.custInfoData.value = resp.data;
}
});
if (this.rating.refs.financeReportGridRefFunction) {
// 加载财报信息
const reportGridRef = this.rating.refs.financeReportGridRefFunction();
if (reportGridRef) {
reportGridRef.setFetchDataUrl(
Environment.apiContextPath('api/irbs/financeReport/getReport?custId=' + custId + '&sort=' + this.rating.custInfoData.value['customerType']),
);
reportGridRef.refresh();
// 加载征信报告
const creditGridRef = this.rating.refs.creditReportGridRefFunction();
creditGridRef.setQueryCriteriaFieldValue('custNo', custNo);
creditGridRef.refresh();
}
}
}
/**
*
*/
async loadQuanQualInfo() {
const stepQuanUrl = Environment.apiContextPath('api/irbs/companyRating/stepQuan');
let actuCtrlYears = null;
if (this.rating.refs.custFormRefFunction) {
actuCtrlYears = this.rating.refs.custFormRefFunction()?.getFieldValue('actuCtrlYears');
}
const stepQuanParams = {
// 评级ID
ratingId: this.rating.ratingData.value['id'],
// 补录信息-实际控制人从业年限
actuCtrlYears: actuCtrlYears,
// 页面类型
page: this.rating.readMode ? Constant.PAGE_TYPE.DETAIL : Constant.PAGE_TYPE.APPLY,
};
await axios
.get(stepQuanUrl, { params: stepQuanParams })
.then((resp) => {
this.rating.hideLoading();
if (resp && resp.data && resp.data.quanScore) {
this.rating.quanData.value = [];
this.rating.quanData.value.push({ label: '定量得分', value: round(resp.data.quanScore, 2) });
}
})
.catch((error) => {
this.rating.hideLoading();
console.info('error====', error);
});
if (this.rating.systemParameter.showIndex.value) {
await this.getScoreDetail();
}
const stepQualUrl = Environment.apiContextPath('api/irbs/companyRating/stepQual');
await axios
.get(stepQualUrl, { params: stepQuanParams })
.then((resp) => {
this.rating.hideLoading();
if (resp && resp.data && resp.data.indices) {
this.rating.qualFormData.value = [];
this.rating.qualSimpleOptionData.value = [];
this.rating.waitSelectFields.value = [];
this.rating.qualFormObj.value = {};
// 将指标进行分组
const groupMap = groupBy(resp.data.indices, 'indexCategory');
Object.keys(groupMap).forEach((key: any) => {
const fields = this.buildFormQualIndex(groupMap[key]);
const group = { label: key, type: 'w-form-group', mode: 'card', fields: fields };
const simpleFields = this.buildFormQualIndex(groupMap[key], false);
const simpleGroup = { label: key, type: 'w-form-group', mode: 'card', fields: simpleFields };
this.rating.qualFormData.value.push(group);
this.rating.qualSimpleOptionData.value.push(simpleGroup);
});
}
})
.catch((error) => {
this.rating.hideLoading();
console.info('error====', error);
});
}
/**
* form表单中得定性指标字段
* @param arr
* @returns
*/
private buildFormQualIndex(arr: Array<any>, allOptions: boolean = true) {
const resultArr = <any>[];
for (let i = 0; i < arr.length; i++) {
const index = arr[i];
const indexOptions = <any>[];
if (index.options && index.options.length > 0) {
index.options.forEach((item, index_) => {
const option = { label: item.text, value: item.disVal };
if (index_ === 0) {
option['desc'] = { label: '选项说明' };
}
if (allOptions || (!Tools.isEmpty(index.indexValue) && index.indexValue === item.disVal)) {
indexOptions.push(option);
}
});
}
const radio = {
label: i + 1 + '、' + index.indexName,
name: index.indexCode,
type: 'w-ext-radio',
dense: true,
options: indexOptions,
selectedColor: 'blue',
selectedLabelColor: '#2196f3',
};
if (i !== 0) {
radio['class'] = 'pt-1';
}
if (!Tools.isEmpty(index.indexValue)) {
radio['defaultValue'] = index.indexValue;
}
resultArr.push(radio);
if (allOptions) {
this.rating.waitSelectFields.value.push({ group: index.indexCategory, field: radio });
this.rating.qualFormObj.value[index.indexCode] = [i + 1 + '、' + index.indexName, index];
}
}
return resultArr;
}
/**
*
*/
async loadAdjustItemInfo() {
this.loadFirstResult();
this.loadAdjustItem();
}
/**
*
*/
async getScoreDetail() {
// 加载得分详情
const urlSearchParams = new URLSearchParams({ sortBy: ['INDEX_TYPE', 'INDEX_CATEGORY'] });
urlSearchParams.append('pageable', 'false');
const criteria = {
fieldName: 'RATING_ID',
operator: 'equals',
value: this.rating.ratingData.value['id'],
};
urlSearchParams.append('criteria', JSON.stringify(criteria));
const url = Environment.apiContextPath('api/irbs/ratingIndex/getScoreDetail');
await axios
.get(url, { params: urlSearchParams })
.then((resp) => {
if (resp?.data?.content) {
const groupMap = groupBy(resp.data.content, 'INDEX_TYPE');
this.rating.quanScoreDtlData.value = groupBy(groupMap['QUANTITATIVE'], 'INDEX_CATEGORY');
this.rating.qualScoreDtlData.value = groupBy(groupMap[Step.type.quanQualAnalysis.value], 'INDEX_CATEGORY');
if (groupMap[Step.type.adjustItem.value] && groupMap[Step.type.adjustItem.value].length > 0) {
this.rating.adjustItemScoreDtlData.value = groupBy(
groupMap[Step.type.adjustItem.value].filter((item) => {
return item['INDEX_VALUE'] !== '0';
}),
'INDEX_CATEGORY',
);
}
}
})
.catch((error) => {
this.rating.hideLoading();
console.info('error====', error);
});
}
/**
*
* @returns
*/
async adjustItemSave() {
let result = false;
const submitData = <any>[];
const rows = this.rating.refs.adjustItemGridRefFunction().getRows();
rows.forEach((item, index) => {
this.rating.adjustItemObj.value[item.indexCode][1].indexValue = item.value
? this.rating.adjustItemObj.value[item.indexCode][1]['options'].find((opt) => {
return opt['disVal'] !== '0';
})['disVal']
: '0';
submitData.push(this.rating.adjustItemObj.value[item.indexCode][1]);
});
this.rating.showLoading('正在重新计算得分,请稍等...');
const resp = await axios.post(Environment.apiContextPath('api/irbs/companyRating/saveIndices'), submitData).catch((error) => {
this.rating.hideLoading();
NotifyManager.error('计算出错,请联系管理员');
console.info('error====', error);
});
if (resp['code'] === 200) {
result = true;
} else {
this.rating.hideLoading();
}
return result;
}
/**
*
* @param nextStep
* @param op
* @param submitData
*/
async qualSaveIndices(nextStep: StepType, op: string, submitData: Array<any>) {
this.rating.showLoading('正在计算定性得分,请稍等...');
const url = Environment.apiContextPath('api/irbs/companyRating/qualSaveIndices/' + op);
const resp = await axios.post(url, submitData).catch((error) => {
this.rating.hideLoading();
NotifyManager.error('计算出错,请联系管理员');
console.info('error====', error);
});
if (resp?.data?.success === true) {
this.loadFirstResult(nextStep);
this.loadAdjustItem();
}
}
/**
*
* @param nextStep
*/
async loadFirstResult(nextStep?: StepType) {
this.rating.firstRatingData.value = [];
const url = Environment.apiContextPath('api/irbs/companyRating/stepInitRating');
const params = {
params: {
ratingId: this.rating.ratingData.value['id'],
page: this.rating.readMode ? Constant.PAGE_TYPE.DETAIL : Constant.PAGE_TYPE.APPLY,
},
};
const res = await axios.get(url, params).catch((error) => {
this.rating.hideLoading();
console.info('error====', error);
});
if (nextStep) {
this.rating.step.next(nextStep);
this.rating.hideLoading();
}
this.rating.firstRatingData.value.push({
label: '等级',
value: res?.data?.modelLevel,
format: () => {
return this.rating.refs.ratingLevelFormatFunction(res?.data?.modelLevel);
},
});
if (this.rating.systemParameter.showTotalScore.value) {
this.rating.firstRatingData.value.push({ label: '得分', value: res?.data?.modelScore ? round(res.data.modelScore, 2) : '' });
this.rating.firstRatingData.value.push({ label: '定量得分', value: res?.data?.quanScore ? round(res.data.quanScore, 2) : '' });
this.rating.firstRatingData.value.push({ label: '定性得分', value: res?.data?.qualScore ? round(res.data.qualScore, 2) : '' });
}
}
/**
*
*/
loadAdjustItem() {
const url = Environment.apiContextPath('api/irbs/companyRating/stepAdj');
const params = {
params: {
ratingId: this.rating.ratingData.value['id'],
page: this.rating.readMode ? Constant.PAGE_TYPE.DETAIL : Constant.PAGE_TYPE.APPLY,
},
};
axios
.get(url, params)
.then((resp) => {
if (resp && resp.data && resp.data.indices) {
this.rating.adjustItemData.value = [];
for (let i = 0; i < resp.data.indices.length; i++) {
const index = resp.data.indices[i];
this.rating.adjustItemObj.value[index.indexCode] = [i + 1 + '、' + index.indexName, index];
this.rating.adjustItemData.value.push({
value: index.indexValue !== '0' && !Tools.isEmpty(index.indexValue) ? true : false,
indexCode: index.indexCode,
indexCategory: index.indexCategory,
adjustItemName: index.indexName,
});
}
this.rating.refs.adjustItemGridRefFunction().setLocalData(this.rating.adjustItemData.value);
}
})
.catch((error) => {
console.info('error====', error);
});
}
async loadRatingReport() {
this.rating.reportCustRatingData.value = [];
this.rating.reportRatingMainData.value = [];
const resp = await axios
.get(Environment.apiContextPath('api/irbs/companyRating/stepRatingReport'), { params: { ratingId: this.rating.ratingData.value['id'] } })
.catch((error) => {
this.rating.hideLoading();
console.info('error====', error);
});
this.rating.hideLoading();
this.rating.ratingData.value = resp?.data;
// this.rating.reportRatingMainData.value.push({ label: '模型名称', value: this.rating.ratingData.value['modelName'] });
// this.rating.reportCustRatingData.value.push({ label: '模型名称', value: this.rating.ratingData.value['modelName'] });
if (this.rating.systemParameter.showTotalScore.value) {
this.rating.reportCustRatingData.value.push({ label: '定量得分', value: round(this.rating.ratingData.value['quanScore'], 2) });
this.rating.reportCustRatingData.value.push({ label: '定性得分', value: round(this.rating.ratingData.value['qualScore'], 2) });
this.rating.reportCustRatingData.value.push({ label: '模型得分', value: round(this.rating.ratingData.value['modelScore'], 2) });
}
this.rating.reportRatingMainData.value.push({
label: '模型级别',
value: this.rating.ratingData.value['modelLevel'],
// format: () => {
// return this.rating.refs.ratingLevelFormatFunction(this.rating.ratingData.value['modelLevel'], this.rating.mainLevelSize);
// },
});
// this.rating.reportCustRatingData.value.push({
// label: '模型级别',
// value: this.rating.ratingData.value['modelLevel'],
// format: () => {
// return this.rating.refs.ratingLevelFormatFunction(this.rating.ratingData.value['modelLevel']);
// },
// });
this.rating.reportRatingMainData.value.push({
label: '调整项级别',
value: this.rating.ratingData.value['adjLevel'],
// format: () => {
// return this.rating.refs.ratingLevelFormatFunction(this.rating.ratingData.value['adjLevel'], this.rating.mainLevelSize);
// },
});
// this.rating.reportCustRatingData.value.push({
// label: '调整项级别',
// value: this.rating.ratingData.value['adjLevel'],
// format: () => {
// return this.rating.refs.ratingLevelFormatFunction(this.rating.ratingData.value['adjLevel']);
// },
// });
this.rating.reportCustRatingData.value.push({
label: '初始级别',
value: this.rating.ratingData.value['initLevel'],
// format: () => {
// return this.rating.refs.ratingLevelFormatFunction(this.rating.ratingData.value['initLevel']);
// },
});
this.rating.reportCustRatingData.value.push({ label: '上一次建议级别', value: this.rating.ratingData.value['spLevel'] });
this.rating.reportRatingMainData.value.push({
label: '最终认定级别',
value: this.rating.ratingData.value['finalLevel'],
// format: () => {
// return this.rating.refs.ratingLevelFormatFunction(this.rating.ratingData.value['finalLevel'], this.rating.mainLevelSize);
// },
});
// this.rating.reportCustRatingData.value.push({
// label: '最终认定级别',
// value: this.rating.ratingData.value['finalLevel'],
// format: () => {
// return this.rating.refs.ratingLevelFormatFunction(this.rating.ratingData.value['finalLevel']);
// },
// });
// this.rating.reportCustRatingData.value.push({
// label: '违约概率',
// value: this.rating.ratingData.value['pd'] ? this.rating.ratingData.value['pd'] + '%' : '',
// });
// this.rating.reportCustRatingData.value.push({ label: '客户经理', value: this.rating.ratingData.value['managerName'] });
this.rating.reportCustRatingData.value.push({ label: '评级发起日期', value: this.rating.ratingData.value['startTime'] });
this.rating.reportCustRatingData.value.push({ label: '评级生效日期', value: this.rating.ratingData.value['effectiveTime'] });
this.rating.reportCustRatingData.value.push({ label: '评级到期日期', value: this.rating.ratingData.value['matureTime'] });
this.rating.reportCustRatingData.value.push({
label: '评级状态',
value: this.rating.ratingData.value['ratingStatus'],
format: Formater.enum(this.rating.enum.ratingStatus),
});
this.rating.reportCustRatingData.value.push({
label: '流程状态',
value: this.rating.ratingData.value['processStatus'],
format: Formater.enum(this.rating.enum.ratingProcessStatus),
});
if (this.rating.systemParameter.reportShowScoreDtl.value) {
this.getScoreDetail();
}
}
/**
*
*/
async loadOverturnInfo() {
const params = {
params: {
ratingId: this.rating.ratingData.value['id'],
page: this.rating.readMode ? Constant.PAGE_TYPE.DETAIL : Constant.PAGE_TYPE.APPLY,
},
};
axios
.get(Environment.apiContextPath('api/irbs/companyRating/stepRatingOverturn'), params)
.then((res) => {
this.rating.hideLoading();
if (res && res.data) {
this.rating.overturnTipData.value = [];
if (this.rating.systemParameter.showTotalScore.value) {
this.rating.overturnTipData.value.push({ label: '定量得分', value: round(res.data.quanScore, 2) });
this.rating.overturnTipData.value.push({ label: '定性得分', value: round(res.data.qualScore, 2) });
this.rating.overturnTipData.value.push({ label: '模型得分', value: round(res.data.modelScore, 2) });
}
this.rating.overturnTipData.value.push({
label: '模型等级',
value: res.data.modelLevel,
// format: () => {
// return this.rating.refs.ratingLevelFormatFunction(res.data.modelLevel);
// },
});
this.rating.overturnTipData.value.push({
label: '调整后等级',
value: res.data.adjLevel,
// format: () => {
// return this.rating.refs.ratingLevelFormatFunction(res.data.adjLevel);
// },
});
this.rating.overturnTipData.value.push({
label: '准入建议',
value: res.data.accessLevel,
});
}
})
.catch((error) => {
this.rating.hideLoading();
console.info('error====', error);
});
}
/**
*
*/
loadFinanceReport() {
const custId = this.rating.ratingData.value['custId'];
const customerType = '1';
const url = Environment.apiContextPath('api/irbs/financeReport/getReport?custId=' + custId + '&sort=' + customerType);
axios.get(url).then((resp) => {
if (resp?.data) {
this.rating.financeReport.value = resp.data;
}
});
}
}

325
irbs.frontend/src/views/custRating/company/ts/Step.ts

@ -0,0 +1,325 @@
import { nextTick, Ref, ref } from 'vue';
import { Dialog } from 'quasar';
import { Tools, DialogManager, $t } from 'platform-core';
import { Constant } from './Constant';
import type { StepType } from './type/StepType';
import { Rating } from './Rating';
// 步骤类
export class Step {
/**
*
*/
static type = {
/**
*
*/
custInfo: <StepType>{
label: '客户信息',
tooltip: '确认评分卡及客户信息是否有误',
value: 'CUST_INFO',
icon: 'bi-1-circle-fill',
order: 1,
disable: false,
},
/**
*
*/
quanQualAnalysis: <StepType>{
label: '定性分析',
tooltip: '定性指标填报',
value: 'QUALITATIVE_EDIT',
icon: 'bi-2-circle-fill',
order: 2,
disable: false,
},
/**
*
*/
adjustItem: <StepType>{
label: '评级调整项',
tooltip: '查看初评结果并勾选调整项',
value: 'ADJUST_ITEM',
icon: 'bi-3-circle-fill',
order: 3,
disable: false,
},
/**
*
*/
reportInfo: <StepType>{
label: '评级报告',
tooltip: '确认评级指标及评级结果',
value: 'REPORT_INFO',
icon: 'bi-4-circle-fill',
order: 4,
disable: false,
},
/**
*
*/
opinion: <StepType>{
label: '签署意见',
tooltip: '评级推翻及提交审核',
value: 'OTHER',
icon: 'bi-5-circle-fill',
order: 5,
disable: false,
},
};
/**
*
*/
rating: Rating;
/**
*
*/
steps: Ref = ref([]);
/**
*
*/
currStep: Ref = ref(Step.type.reportInfo.value);
constructor(rating_: Rating) {
this.rating = rating_;
this.initSteps();
this.click = this.click.bind(this);
this.nextClick = this.nextClick.bind(this);
}
/**
*
*/
click(value: string) {
this.setCurrStep(value);
}
/**
*
* @param nextStep
*/
next(nextStep: StepType) {
// 将下一步禁用状态改为可用
this.setDisable(nextStep, false);
// 将当前步骤修改为下一步
this.setCurrStep(nextStep.value);
}
/**
*
*/
nextClick() {
const nextStep = this.findNextStep(this.currStep.value);
switch (nextStep.value) {
case Step.type.quanQualAnalysis.value:
this.nextQuanQual(nextStep);
break;
case Step.type.adjustItem.value:
this.nextAdjustItem(nextStep);
break;
case Step.type.reportInfo.value:
this.nextReport(nextStep);
break;
case Step.type.opinion.value:
this.nextOpinion(nextStep);
break;
}
}
/**
*
* @param nextStep
*/
async nextQuanQual(nextStep: StepType) {
this.rating.showLoading('正在获取定量得分,请稍等...');
// await this.rating.api.loadQuanQualInfo();
this.next(nextStep);
}
/**
*
*/
async nextAdjustItem(nextStep: StepType) {
const result = this.qualFormValidate();
if (!result['result']) {
return;
}
DialogManager.yesnoDialog({
title: $t('confirm') || '',
message: '请检查所选数据的正确性,提交并计算结果后无法再次修改,确定要提交吗?',
yesCallback: () => {
this.rating.showLoading('正在计算定性得分,请稍等...');
this.rating.api.qualSaveIndices(nextStep, Constant.QUAL_SAVE_OPERATOR.NEXT, result['submitData']);
},
});
}
/**
*
* @param nextStep
*/
async nextReport(nextStep: StepType) {
const result = await this.rating.api.adjustItemSave();
if (result) {
this.next(nextStep);
// this.rating.api.loadCustInfo();
// this.rating.api.loadQuanQualInfo();
// this.rating.api.loadRatingReport();
}
}
/**
*
* @param nextStep
*/
async nextOpinion(nextStep: StepType) {
// await this.rating.api.loadOverturnInfo();
this.next(nextStep);
}
/**
*
* @returns
*/
qualFormValidate() {
// 判断是否存在未选择的选项
const formData = this.rating.refs.qualitativeFormRefFunction().getData();
const submitData = <any>[];
let result = true;
const errorRows = <any>[];
const keys = Object.keys(formData);
for (let i = 0; i < keys.length; i++) {
if (Tools.isEmpty(formData[keys[i]])) {
result = false;
errorRows.push({
label: this.rating.qualFormObj.value[keys[i]][0],
value: keys[i],
checkedIcon: 'cancel',
uncheckedIcon: 'cancel',
color: 'red',
keepColor: true,
disable: true,
dense: true,
});
} else {
this.rating.qualFormObj.value[keys[i]][1].indexValue = formData[keys[i]];
submitData.push(this.rating.qualFormObj.value[keys[i]][1]);
}
}
if (!result) {
Dialog.create({
title: '提示',
message: '以下定性选项为空,请选择后执行该操作!',
persistent: true,
options: {
type: 'checkbox',
model: [],
items: errorRows,
},
});
}
return {
result,
submitData,
};
}
/**
* value
* @param value
*/
findByValue(value: string): StepType {
return this.steps.value.find((item) => item.value === value);
}
/**
* value
* @param value
*/
findNextStep(value: string): StepType {
const currStep_ = this.findByValue(value);
if (!currStep_) {
throw new Error('[step.ts] Step information cannot be found based on the current value(' + value + ').');
}
return this.steps.value.find((item) => item.order === currStep_.order + 1);
}
/**
*
* @param step_
* @param value
*/
setDisable(step_: StepType, value: boolean) {
step_.disable = value;
}
/**
*
* @param step_
*/
setCurrStep(value: string) {
// TODO 如果状态为初始化完成,直接使用改造过后的前端步骤-客户信息
const value_ = value === 'INIT_FINISH' ? Step.type.custInfo.value : value;
if (value_) {
this.currStep.value = value_;
nextTick(() => {
switch (value_) {
case Step.type.custInfo.value:
this.rating.api.loadCustInfo();
break;
case Step.type.quanQualAnalysis.value:
this.rating.api.loadQuanQualInfo();
break;
case Step.type.adjustItem.value:
this.rating.api.loadAdjustItemInfo();
break;
case Step.type.reportInfo.value:
this.rating.api.loadCustInfo();
this.rating.api.loadQuanQualInfo();
this.rating.api.loadRatingReport();
break;
case Step.type.opinion.value:
this.rating.api.loadOverturnInfo();
break;
}
});
}
}
/**
*
* @param
*/
private initSteps() {
if (this.rating.cm.isAwaitSubmitProcessStatus.value) {
// 发起评级页面
const currStep_ = Object.values(Step.type).find(
(item) =>
item.value ===
(this.rating.ratingData.value['currentStep'] === 'INIT_FINISH' ? Step.type.custInfo.value : this.rating.ratingData.value['currentStep']),
);
const result: Array<StepType> = [];
Object.values(Step.type)
.sort((a, b) => a.order - b.order)
.forEach((step: StepType) => {
if (step.order > Step.type.custInfo.order) {
// 默认将顺序大于`客户信息`的步骤全部置为不可用状态。
step.disable = true;
}
if (currStep_ && step.order <= currStep_.order) {
// 将顺序 <= 当前评级表中存储的步骤 的状态置为可用
step.disable = false;
}
result.push(step);
});
this.steps.value = result;
} else {
// 审批流程页面签署意见需要单独与业务信息分成左右两边布局放置,不需要【签署意见】步骤。
this.steps.value = Object.values(Step.type)
.filter((item) => item.value !== Step.type.opinion.value)
.sort((a, b) => a.order - b.order);
}
}
}

67
irbs.frontend/src/views/custRating/company/ts/SystemParameter.ts

@ -0,0 +1,67 @@
import { axios, Environment } from 'platform-core';
import { Ref, ref } from 'vue';
/**
*
*/
export class SystemParameter {
/**
*
*/
overturnLevel: Ref = ref(3);
/**
*
*/
showTotalScore: Ref = ref(false);
/**
*
*/
showIndex: Ref = ref(false);
/**
*
*/
showIndexScore: Ref = ref(false);
/**
*
*/
reportShowScoreDtl: Ref = ref(false);
/**
*
*/
reportShowIndexScore: Ref = ref(false);
/**
*
*/
qualTestCalcNum: Ref = ref(5);
/**
*
*/
qualQaMode: Ref = ref(true);
async load() {
// 获取当前参数配置中评级页面相关的配置
const parameters = [
'parameter.irbs.params.overturnLevel',
'parameter.irbs.params.ratingUI.totalScore',
'parameter.irbs.params.ratingUI.index',
'parameter.irbs.params.ratingUI.indexScore',
'parameter.irbs.params.ratingUI.report.indexScore',
'parameter.irbs.params.qual.calc.num',
];
// 判断当前用户在评级报告中是否能看到得分详情
const authResult = await axios.get(Environment.apiContextPath('api/irbs/rating/report/showScoreRole/findShowScoreAuth')).catch((error) => {
console.info('error====', error);
});
this.reportShowScoreDtl.value = authResult['data'];
const res: any = await axios.post(Environment.apiContextPath('api/irbs/companyRating/getSystemParameters'), parameters).catch((error) => {
console.info('error====', error);
});
this.overturnLevel.value = parseInt(res.data['parameter.irbs.params.overturnLevel']);
this.showTotalScore.value = res.data['parameter.irbs.params.ratingUI.totalScore'] === 'show' ? true : false;
this.showIndex.value = res.data['parameter.irbs.params.ratingUI.index'] === 'show' ? true : false;
this.showIndexScore.value = res.data['parameter.irbs.params.ratingUI.indexScore'] === 'show' ? true : false;
this.reportShowIndexScore.value =
res.data['parameter.irbs.params.ratingUI.report.indexScore'] === 'show' && this.reportShowScoreDtl.value === true ? true : false;
this.qualTestCalcNum.value = parseInt(res.data['parameter.irbs.params.qual.calc.num']);
}
}

41
irbs.frontend/src/views/custRating/company/ts/Utils.ts

@ -0,0 +1,41 @@
export const round = (val: any, precision: any) => {
if (typeof precision !== 'number' || precision <= 0) return val;
let result = val;
if (val && typeof val === 'string') {
const patt = /^-?[0-9]+.?[0-9]*/;
if (patt.test(val)) {
result = parseFloat(val);
}
}
if (result && typeof result === 'number' && String(result).indexOf('.') > -1) {
let scale = '1';
for (let i = 0; i < precision; i++) {
scale += 0;
}
const pre = 'e' + precision;
const post = 'e-' + precision;
return (+(Math.round(result + pre) + post)).toFixed(precision);
}
return result;
};
export const groupBy = (arr, prop) =>
arr.reduce((acc, item) => {
const key = item[prop];
if (!acc[key]) acc[key] = [];
acc[key].push(item);
return acc;
}, {});
export const formatAmt = (num: any) => {
if (num) {
// 强制转换为Number类型(自动解析科学计数法)
const numberVal = Number(num);
// 常规处理流程
const fixedNum = numberVal.toFixed(2);
const [integer, decimal] = fixedNum.split('.');
return integer.replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1,') + '.' + decimal;
}
return num;
};

27
irbs.frontend/src/views/custRating/company/ts/type/StepType.ts

@ -0,0 +1,27 @@
// 步骤类型
export type StepType = {
/**
*
*/
label: string;
/**
*
*/
value: string;
/**
* 使
*/
icon: string;
/**
*
*/
order: number;
/**
*
*/
disable: boolean;
/**
*
*/
tooltip: string;
};

50
irbs.frontend/src/views/custRating/mock/MockCmis.vue

@ -0,0 +1,50 @@
<template>
<div class="h-full">
<q-splitter v-model="tabsSplitterModel" horizontal class="h-full" unit="px" disable>
<template #before>
<q-tabs v-model="tabsModel" dense no-caps inline-label indicator-color="amber" active-color="amber" align="right">
<q-tab name="mockApply" icon="arrow_outward" label="模拟发起评级直接打开评级窗口" />
<q-tab name="mockTask" icon="assignment" label="模拟处理任务直接打开任务窗口" />
</q-tabs>
</template>
<template #after>
<!-- 切分窗口 -->
<q-tab-panels v-model="tabsModel" class="p-0 h-full" animated>
<q-tab-panel name="mockApply" class="p-0 h-full">
<CustSelectGrid
ref="customerGridRef"
:toolbar-actions="[
'query',
'reset',
'separator',
{
name: 'mock',
label: '模拟发起评级直接打开评级窗口',
icon: 'add',
enableIf: (args) => {
return args.selected;
},
click: mockApply,
},
]"
></CustSelectGrid>
</q-tab-panel>
<q-tab-panel name="mockTask" class="p-0 h-full"> 模拟处理任务直接打开任务窗口 </q-tab-panel>
</q-tab-panels>
</template>
</q-splitter>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import CustSelectGrid from '../company/CustSelectGrid.vue';
const tabsSplitterModel = ref(36);
const customerGridRef = ref();
const tabsModel = ref('mockApply');
const mockApply = (args) => {
const custNo = args.selected['custNo'];
window.open('http://localhost:3000/#/irbs/rating/apply?custNo=' + custNo, '_blank');
};
</script>

16
irbs.frontend/src/views/workbench/TodoTask.vue

@ -15,7 +15,7 @@
}" }"
:sort-by="['-CREATE_TIME']" :sort-by="['-CREATE_TIME']"
></w-grid> ></w-grid>
<RatingDialog ref="ratingDialogRef" @refresh="refresh"></RatingDialog> <RatingDialog ref="ratingDialogRef" :rating-data="ratingData" :read-mode="ratingMode" @refresh="refresh"></RatingDialog>
<CognizanceDialog ref="cognizanceDialogRef" @refresh="refresh"></CognizanceDialog> <CognizanceDialog ref="cognizanceDialogRef" @refresh="refresh"></CognizanceDialog>
<RebirthDialog ref="rebirthDialogRef" @refresh="refresh"></RebirthDialog> <RebirthDialog ref="rebirthDialogRef" @refresh="refresh"></RebirthDialog>
<HandmadeExposureDialog ref="handmadeExposureDialogRef" @refresh="refresh"></HandmadeExposureDialog> <HandmadeExposureDialog ref="handmadeExposureDialogRef" @refresh="refresh"></HandmadeExposureDialog>
@ -23,12 +23,12 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import RatingDialog from '@/views/custRating/company/RatingDialog.vue';
import { Environment, EnumTools, DictionaryTools, Options, Formater, axios, NotifyManager } from 'platform-core';
import RatingDialog from '@/views/custRating/RatingDialog.vue';
import CognizanceDialog from '@/views/default/CognizanceDialog.vue'; import CognizanceDialog from '@/views/default/CognizanceDialog.vue';
import RebirthDialog from '@/views/default/RebirthDialog.vue'; import RebirthDialog from '@/views/default/RebirthDialog.vue';
import HandmadeExposureDialog from '@/views/riskExposure/HandmadeExposureDialog.vue'; import HandmadeExposureDialog from '@/views/riskExposure/HandmadeExposureDialog.vue';
import { axios, Environment } from 'platform-core';
import { ref, nextTick } from 'vue';
import { ProcessDefKey } from './Task.ts'; import { ProcessDefKey } from './Task.ts';
const gridRef = ref(); const gridRef = ref();
@ -37,6 +37,9 @@ const cognizanceDialogRef = ref();
const rebirthDialogRef = ref(); const rebirthDialogRef = ref();
const handmadeExposureDialogRef = ref(); const handmadeExposureDialogRef = ref();
const ratingData = ref({});
const ratingMode = ref(false);
const grid = { const grid = {
queryFormFields: [ queryFormFields: [
{ label: '业务流水号', name: 'BUSINESS_ID', type: 'w-text' }, { label: '业务流水号', name: 'BUSINESS_ID', type: 'w-text' },
@ -92,7 +95,10 @@ const openRatingDialog = (task) => {
.get(Environment.apiContextPath('api/irbs/companyRating?pageable=false'), { params: urlSearchParams }) .get(Environment.apiContextPath('api/irbs/companyRating?pageable=false'), { params: urlSearchParams })
.then((resp) => { .then((resp) => {
if (resp.data?.content) { if (resp.data?.content) {
ratingDialogRef.value.show({ ...resp.data.content[0], taskId: task['ID'] }); ratingData.value = { ...resp.data.content[0], taskId: task['ID'] };
nextTick(() => {
ratingDialogRef.value.show();
});
} }
}) })
.catch((error) => { .catch((error) => {

8
irbs.frontend/webpack.config.common.cjs

@ -22,7 +22,7 @@ module.exports = {
// 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录 // 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录
path: path.resolve(__dirname, `dist/public/${projectName}`), path: path.resolve(__dirname, `dist/public/${projectName}`),
// 输出文件名 // 输出文件名
filename: `javascript/[name].[contenthash:5].js`, filename: `javascript/[name].[contenthash:6].js`,
// 指定发布路径,使用 auto 可具有更多灵活性 // 指定发布路径,使用 auto 可具有更多灵活性
publicPath: 'auto', publicPath: 'auto',
// 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果 // 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果
@ -69,7 +69,7 @@ module.exports = {
test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/, test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/,
type: 'asset/resource', type: 'asset/resource',
generator: { generator: {
filename: `fonts/[name].[contenthash:5].[ext]`, filename: `fonts/[name].[contenthash:6].[ext]`,
}, },
}, },
@ -122,8 +122,8 @@ module.exports = {
// css 抽取插件 // css 抽取插件
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: `css/[name].[contenthash:5].css`, filename: `css/[name].[contenthash:6].css`,
chunkFilename: `css/[name].[contenthash:5].css`, chunkFilename: `css/[name].[contenthash:6].css`,
}), }),
// 自动生成静态 index.html 文件 // 自动生成静态 index.html 文件

51
irbs.frontend/webpack.config.mf.cjs

@ -1,19 +1,19 @@
/** /**
* webpack module federation 配置 * webpack module federation 配置
*/ */
const fs = require('fs'); // 文件读取 const fs = require('fs'); // 文件读取
const Json5 =require('json5'); // json5 const Json5 = require('json5'); // json5
const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件
const packageJson = require('./package.json'); // package.json const packageJson = require('./package.json'); // package.json
const projectName =packageJson.name; // 项目名称 const projectName = packageJson.name; // 项目名称
const deps = packageJson.dependencies; // 项目依赖 const deps = packageJson.dependencies; // 项目依赖
// 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值 // 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值
const data = fs.readFileSync('./src/routes/routes.json', 'utf8'); const data = fs.readFileSync('./src/routes/routes.json', 'utf8');
const routes =Json5.parse(data); const routes = Json5.parse(data);
const mfExposes ={}; const mfExposes = {};
for(const route of routes){ for (const route of routes) {
mfExposes[route.component]= route.componentPath; mfExposes[route.component] = route.componentPath;
} }
// 导出 webapck 配置的模块联邦部分 // 导出 webapck 配置的模块联邦部分
@ -57,24 +57,25 @@ module.exports = {
'@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true }, '@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true },
'@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true }, '@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true },
'@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true }, '@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true },
'axios': { requiredVersion: deps['axios'], singleton: true }, axios: { requiredVersion: deps['axios'], singleton: true },
'codemirror': { requiredVersion: deps['codemirror'], singleton: true }, codemirror: { requiredVersion: deps['codemirror'], singleton: true },
'dayjs': { requiredVersion: deps['dayjs'], singleton: true }, dayjs: { requiredVersion: deps['dayjs'], singleton: true },
'echarts':{ requiredVersion: deps['echarts'], singleton: true }, echarts: { requiredVersion: deps['echarts'], singleton: true },
'exceljs':{ requiredVersion: deps['exceljs'], singleton: true }, exceljs: { requiredVersion: deps['exceljs'], singleton: true },
'file-saver':{ requiredVersion: deps['file-saver'], singleton: true }, 'file-saver': { requiredVersion: deps['file-saver'], singleton: true },
'luckyexcel':{ requiredVersion: deps['luckyexcel'], singleton: true }, luckyexcel: { requiredVersion: deps['luckyexcel'], singleton: true },
'mockjs': { requiredVersion: deps['mockjs'], singleton: true }, mockjs: { requiredVersion: deps['mockjs'], singleton: true },
'pinia': { requiredVersion: deps['pinia'], singleton: true }, pinia: { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true }, quasar: { requiredVersion: deps['quasar'], singleton: true },
'@quasar/quasar-ui-qmarkdown': { requiredVersion: deps['@quasar/quasar-ui-qmarkdown'], singleton: true },
'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true }, 'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true }, vue: { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-dompurify-html': { requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true } 'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true },
} },
}), }),
] ],
}; };

48
irbs.frontend/webpack.env.build.cjs

@ -1,9 +1,9 @@
/** /**
* 开发环境构建 * 开发环境构建
*/ */
const { merge } = require('webpack-merge'); // webpack 配置合并函数 const { merge } = require('webpack-merge'); // webpack 配置合并函数
const common = require('./webpack.config.common.cjs'); // webpack 通用配置 const common = require('./webpack.config.common.cjs'); // webpack 通用配置
const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置
module.exports = merge(common, mf, { module.exports = merge(common, mf, {
mode: 'development', mode: 'development',
@ -22,76 +22,76 @@ module.exports = merge(common, mf, {
splitChunks: { splitChunks: {
cacheGroups: { cacheGroups: {
'shared': { shared: {
name: 'vue', name: 'vue',
test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/, test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'vue': { vue: {
name: 'vue', name: 'vue',
test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/, test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'codemirror':{ codemirror: {
name: 'codemirror', name: 'codemirror',
test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/, test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'quasar': { quasar: {
name: 'quasar', name: 'quasar',
test: /[\\/]node_modules[\\/](quasar)[\\/]/, test: /[\\/]node_modules[\\/](quasar|@quasar[\\/]quasar-ui-qmarkdown)[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'platform-core': { 'platform-core': {
name: 'platform-core', name: 'platform-core',
test: /[\\/]node_modules[\\/]platform-core[\\/]/, test: /[\\/]node_modules[\\/]platform-core[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'echarts': { echarts: {
name: 'echarts', name: 'echarts',
test: /[\\/]node_modules[\\/]echarts[\\/]/, test: /[\\/]node_modules[\\/]echarts[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'maxgraph': { maxgraph: {
name: 'maxgraph', name: 'maxgraph',
test: /[\\/]node_modules[\\/]@maxgraph[\\/]/, test: /[\\/]node_modules[\\/]@maxgraph[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'@univerjs': { '@univerjs': {
name: '@univerjs', name: '@univerjs',
test: /[\\/]node_modules[\\/]@univerjs[\\/]/, test: /[\\/]node_modules[\\/]@univerjs[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'view': { view: {
name: 'view', name: 'view',
test: /[\\/]view[\\/]/, test: /[\\/]view[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'vendors': { vendors: {
name: 'vendors', name: 'vendors',
test: /[\\/]node_modules[\\/]/, test: /[\\/]node_modules[\\/]/,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
} },
} },
}, },
}); });

9
irbs.riskExposure/src/main/java/irbs/riskExposure/service/impl/RiskExposureFlowServiceImpl.java

@ -3,6 +3,8 @@ package irbs.riskExposure.service.impl;
import io.sc.platform.flowable.service.ProcessOperationService; import io.sc.platform.flowable.service.ProcessOperationService;
import io.sc.platform.flowable.service.ProcessQueryService; import io.sc.platform.flowable.service.ProcessQueryService;
import io.sc.platform.flowable.support.ProcessTaskWrapper; import io.sc.platform.flowable.support.ProcessTaskWrapper;
import io.sc.platform.orm.service.support.QueryParameter;
import io.sc.platform.orm.service.support.criteria.impl.Equals;
import io.sc.platform.security.util.SecurityUtil; import io.sc.platform.security.util.SecurityUtil;
import irbs.riskExposure.service.RiskExposureFlowService; import irbs.riskExposure.service.RiskExposureFlowService;
import org.flowable.engine.runtime.ProcessInstance; import org.flowable.engine.runtime.ProcessInstance;
@ -31,6 +33,13 @@ public class RiskExposureFlowServiceImpl implements RiskExposureFlowService {
@Override @Override
public ProcessTaskWrapper findTaskByProcInstId(String procInstId) throws Exception { public ProcessTaskWrapper findTaskByProcInstId(String procInstId) throws Exception {
ProcessTaskWrapper taskWrapper = null; ProcessTaskWrapper taskWrapper = null;
// QueryParameter parameter = new QueryParameter();
// parameter.setPageable(false);
// Equals eq = new Equals();
// eq.setFieldName("processInstanceId");
// eq.setValue(procInstId);
// parameter.addCriteria(eq);
// List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(parameter).getContent();
List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(procInstId, null); List<ProcessTaskWrapper> list = processQueryService.queryProcessTasks(procInstId, null);
if (null != list && list.size() > 1) { if (null != list && list.size() > 1) {
// 同一个流程实例查找出多个任务则为多实例任务,还需再根据任务处理人匹配。 // 同一个流程实例查找出多个任务则为多实例任务,还需再根据任务处理人匹配。

5
irbs.shrcb.poc.frontend/package.json

@ -87,6 +87,7 @@
"@codemirror/view": "6.36.2", "@codemirror/view": "6.36.2",
"@maxgraph/core": "0.14.0", "@maxgraph/core": "0.14.0",
"@quasar/extras": "1.16.15", "@quasar/extras": "1.16.15",
"@quasar/quasar-ui-qmarkdown": "2.0.5",
"@univerjs/core": "0.5.4", "@univerjs/core": "0.5.4",
"@univerjs/design": "0.5.4", "@univerjs/design": "0.5.4",
"@univerjs/docs": "0.5.4", "@univerjs/docs": "0.5.4",
@ -100,7 +101,7 @@
"@univerjs/thread-comment": "0.5.4", "@univerjs/thread-comment": "0.5.4",
"@univerjs/ui": "0.5.4", "@univerjs/ui": "0.5.4",
"@vueuse/core": "12.4.0", "@vueuse/core": "12.4.0",
"axios": "1.7.9", "axios": "1.8.2",
"codemirror": "6.0.1", "codemirror": "6.0.1",
"dayjs": "1.11.13", "dayjs": "1.11.13",
"echarts": "5.6.0", "echarts": "5.6.0",
@ -111,7 +112,7 @@
"mockjs": "1.1.0", "mockjs": "1.1.0",
"node-sql-parser": "5.3.6", "node-sql-parser": "5.3.6",
"pinia": "2.3.0", "pinia": "2.3.0",
"platform-core": "8.2.40", "platform-core": "8.2.50",
"quasar": "2.17.6", "quasar": "2.17.6",
"sort-array": "5.0.0", "sort-array": "5.0.0",
"svg-path-commander": "2.1.7", "svg-path-commander": "2.1.7",

8
irbs.shrcb.poc.frontend/webpack.config.common.cjs

@ -22,7 +22,7 @@ module.exports = {
// 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录 // 2. 兼容多个前端项目: 每个项目发布到 public 目录下的唯一项目名称目录
path: path.resolve(__dirname, `dist/public/${projectName}`), path: path.resolve(__dirname, `dist/public/${projectName}`),
// 输出文件名 // 输出文件名
filename: `javascript/[name].[contenthash:5].js`, filename: `javascript/[name].[contenthash:6].js`,
// 指定发布路径,使用 auto 可具有更多灵活性 // 指定发布路径,使用 auto 可具有更多灵活性
publicPath: 'auto', publicPath: 'auto',
// 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果 // 每次构建时,首先删除 output.path 目录所有内容,保证每次得到最新的构建结果
@ -69,7 +69,7 @@ module.exports = {
test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/, test: /\.(woff|woff2|eot|ttf|otf)(\?.*)?$/,
type: 'asset/resource', type: 'asset/resource',
generator: { generator: {
filename: `fonts/[name].[contenthash:5].[ext]`, filename: `fonts/[name].[contenthash:6].[ext]`,
}, },
}, },
@ -122,8 +122,8 @@ module.exports = {
// css 抽取插件 // css 抽取插件
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: `css/[name].[contenthash:5].css`, filename: `css/[name].[contenthash:6].css`,
chunkFilename: `css/[name].[contenthash:5].css`, chunkFilename: `css/[name].[contenthash:6].css`,
}), }),
// 自动生成静态 index.html 文件 // 自动生成静态 index.html 文件

51
irbs.shrcb.poc.frontend/webpack.config.mf.cjs

@ -1,19 +1,19 @@
/** /**
* webpack module federation 配置 * webpack module federation 配置
*/ */
const fs = require('fs'); // 文件读取 const fs = require('fs'); // 文件读取
const Json5 =require('json5'); // json5 const Json5 = require('json5'); // json5
const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件 const { ModuleFederationPlugin } = require('webpack').container; // webpack 模块联邦插件
const packageJson = require('./package.json'); // package.json const packageJson = require('./package.json'); // package.json
const projectName =packageJson.name; // 项目名称 const projectName = packageJson.name; // 项目名称
const deps = packageJson.dependencies; // 项目依赖 const deps = packageJson.dependencies; // 项目依赖
// 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值 // 读取本地路由配置, 通过其中 component 和 componentPath 两个属性构建 webpack 模块联邦的 exposes 属性值
const data = fs.readFileSync('./src/routes/routes.json', 'utf8'); const data = fs.readFileSync('./src/routes/routes.json', 'utf8');
const routes =Json5.parse(data); const routes = Json5.parse(data);
const mfExposes ={}; const mfExposes = {};
for(const route of routes){ for (const route of routes) {
mfExposes[route.component]= route.componentPath; mfExposes[route.component] = route.componentPath;
} }
// 导出 webapck 配置的模块联邦部分 // 导出 webapck 配置的模块联邦部分
@ -57,24 +57,25 @@ module.exports = {
'@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true }, '@univerjs/thread-comment': { requiredVersion: deps['@univerjs/thread-comment'], singleton: true },
'@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true }, '@univerjs/ui': { requiredVersion: deps['@univerjs/ui'], singleton: true },
'@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true }, '@vueuse/core': { requiredVersion: deps['@vueuse/core'], singleton: true },
'axios': { requiredVersion: deps['axios'], singleton: true }, axios: { requiredVersion: deps['axios'], singleton: true },
'codemirror': { requiredVersion: deps['codemirror'], singleton: true }, codemirror: { requiredVersion: deps['codemirror'], singleton: true },
'dayjs': { requiredVersion: deps['dayjs'], singleton: true }, dayjs: { requiredVersion: deps['dayjs'], singleton: true },
'echarts':{ requiredVersion: deps['echarts'], singleton: true }, echarts: { requiredVersion: deps['echarts'], singleton: true },
'exceljs':{ requiredVersion: deps['exceljs'], singleton: true }, exceljs: { requiredVersion: deps['exceljs'], singleton: true },
'file-saver':{ requiredVersion: deps['file-saver'], singleton: true }, 'file-saver': { requiredVersion: deps['file-saver'], singleton: true },
'luckyexcel':{ requiredVersion: deps['luckyexcel'], singleton: true }, luckyexcel: { requiredVersion: deps['luckyexcel'], singleton: true },
'mockjs': { requiredVersion: deps['mockjs'], singleton: true }, mockjs: { requiredVersion: deps['mockjs'], singleton: true },
'pinia': { requiredVersion: deps['pinia'], singleton: true }, pinia: { requiredVersion: deps['pinia'], singleton: true },
'platform-core': { requiredVersion: deps['platform-core'], singleton: true }, 'platform-core': { requiredVersion: deps['platform-core'], singleton: true },
'quasar': { requiredVersion: deps['quasar'], singleton: true }, quasar: { requiredVersion: deps['quasar'], singleton: true },
'@quasar/quasar-ui-qmarkdown': { requiredVersion: deps['@quasar/quasar-ui-qmarkdown'], singleton: true },
'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true }, 'svg-path-commander': { requiredVersion: deps['svg-path-commander'], singleton: true },
'vue': { requiredVersion: deps['vue'], singleton: true }, vue: { requiredVersion: deps['vue'], singleton: true },
'vue-dompurify-html':{ requiredVersion: deps['vue-dompurify-html'], singleton: true }, 'vue-dompurify-html': { requiredVersion: deps['vue-dompurify-html'], singleton: true },
'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true }, 'vue-i18n': { requiredVersion: deps['vue-i18n'], singleton: true },
'vue-router': { requiredVersion: deps['vue-router'], singleton: true }, 'vue-router': { requiredVersion: deps['vue-router'], singleton: true },
'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true } 'xml-formatter': { requiredVersion: deps['xml-formatter'], singleton: true },
} },
}), }),
] ],
}; };

48
irbs.shrcb.poc.frontend/webpack.env.build.cjs

@ -1,9 +1,9 @@
/** /**
* 开发环境构建 * 开发环境构建
*/ */
const { merge } = require('webpack-merge'); // webpack 配置合并函数 const { merge } = require('webpack-merge'); // webpack 配置合并函数
const common = require('./webpack.config.common.cjs'); // webpack 通用配置 const common = require('./webpack.config.common.cjs'); // webpack 通用配置
const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置 const mf = require('./webpack.config.mf.cjs'); // webpack 模块联邦配置
module.exports = merge(common, mf, { module.exports = merge(common, mf, {
mode: 'development', mode: 'development',
@ -22,76 +22,76 @@ module.exports = merge(common, mf, {
splitChunks: { splitChunks: {
cacheGroups: { cacheGroups: {
'shared': { shared: {
name: 'vue', name: 'vue',
test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/, test: /[\\/]node_modules[\\/](axios|dayjs|exceljs|file-saver|luckyexcel|mockjs|xml-formatter)[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'vue': { vue: {
name: 'vue', name: 'vue',
test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/, test: /[\\/]node_modules[\\/](vue|vue-dompurify-html|vue-i18n|vue-router|pinia|@vueuse[\\/]core)[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'codemirror':{ codemirror: {
name: 'codemirror', name: 'codemirror',
test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/, test: /[\\/]node_modules[\\/](codemirror|@codemirror[\\/]autocomplete|@codemirror[\\/]commands|@codemirror[\\/]lang-html|@codemirror[\\/]lang-java|@codemirror[\\/]lang-javascript|@codemirror[\\/]lang-json|@codemirror[\\/]lang-sql|@codemirror[\\/]lang-xml|@codemirror[\\/]language|@codemirror[\\/]search|@codemirror[\\/]state|@codemirror[\\/]view)[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'quasar': { quasar: {
name: 'quasar', name: 'quasar',
test: /[\\/]node_modules[\\/](quasar)[\\/]/, test: /[\\/]node_modules[\\/](quasar|@quasar[\\/]quasar-ui-qmarkdown)[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'platform-core': { 'platform-core': {
name: 'platform-core', name: 'platform-core',
test: /[\\/]node_modules[\\/]platform-core[\\/]/, test: /[\\/]node_modules[\\/]platform-core[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'echarts': { echarts: {
name: 'echarts', name: 'echarts',
test: /[\\/]node_modules[\\/]echarts[\\/]/, test: /[\\/]node_modules[\\/]echarts[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'maxgraph': { maxgraph: {
name: 'maxgraph', name: 'maxgraph',
test: /[\\/]node_modules[\\/]@maxgraph[\\/]/, test: /[\\/]node_modules[\\/]@maxgraph[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'@univerjs': { '@univerjs': {
name: '@univerjs', name: '@univerjs',
test: /[\\/]node_modules[\\/]@univerjs[\\/]/, test: /[\\/]node_modules[\\/]@univerjs[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'view': { view: {
name: 'view', name: 'view',
test: /[\\/]view[\\/]/, test: /[\\/]view[\\/]/,
priority: 20, priority: 20,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
'vendors': { vendors: {
name: 'vendors', name: 'vendors',
test: /[\\/]node_modules[\\/]/, test: /[\\/]node_modules[\\/]/,
chunks: 'all', chunks: 'all',
enforce: true enforce: true,
}, },
} },
} },
}, },
}); });

3
settings.gradle

@ -9,4 +9,5 @@ include ':irbs.help.doc'
include ':irbs.reports' include ':irbs.reports'
include ':irbs.riskExposure' include ':irbs.riskExposure'
include ':irbs.shrcb.poc' include ':irbs.shrcb.poc'
include ':irbs.shrcb.poc.frontend' include ':irbs.shrcb.poc.frontend'
include ':irbs.system'
Loading…
Cancel
Save