迁移892-without-redis分支全量功能
This commit is contained in:
257
bin/prod/deploy_from_package.sh
Executable file
257
bin/prod/deploy_from_package.sh
Executable file
@@ -0,0 +1,257 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
JAVA_BIN="/home/webapp/env/java/bin/java"
|
||||
BACKEND_PORT=63310
|
||||
SPRING_PROFILE="uat"
|
||||
JAVA_OPTS="-Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError"
|
||||
|
||||
SCRIPT_DIR=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
|
||||
BACKEND_DIR="$SCRIPT_DIR/backend"
|
||||
FRONTEND_DIR="$SCRIPT_DIR/frontend"
|
||||
BACKEND_JAR_TARGET="$BACKEND_DIR/ruoyi-admin.jar"
|
||||
BACKEND_PID_FILE="$BACKEND_DIR/backend.pid"
|
||||
BACKEND_LOG_FILE="$BACKEND_DIR/backend-console.log"
|
||||
FRONTEND_DIST_ARCHIVE="$FRONTEND_DIR/dist.zip"
|
||||
FRONTEND_DIST_DIR="$FRONTEND_DIR/dist"
|
||||
BACKEND_MARKER="-Dloan.pricing.home=$SCRIPT_DIR"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
用法:
|
||||
./deploy_from_package.sh
|
||||
EOF
|
||||
}
|
||||
|
||||
timestamp() {
|
||||
date "+%Y%m%d%H%M%S"
|
||||
}
|
||||
|
||||
log_info() {
|
||||
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >&2
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if [ -n "${WORK_DIR:-}" ] && [ -d "$WORK_DIR" ]; then
|
||||
rm -rf "$WORK_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
require_dir() {
|
||||
if [ ! -d "$1" ]; then
|
||||
log_error "缺少目录: $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_command() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
log_error "缺少命令: $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
find_release_archive() {
|
||||
archives=$(find "$SCRIPT_DIR" -maxdepth 1 -type f -name '*.zip' ! -name 'dist.zip')
|
||||
count=$(printf '%s\n' "$archives" | sed '/^$/d' | wc -l | tr -d ' ')
|
||||
|
||||
if [ "$count" -ne 1 ]; then
|
||||
log_error "脚本同目录发布 zip 数量不正确,期望 1 个,实际 $count 个"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '%s\n' "$archives"
|
||||
}
|
||||
|
||||
extract_release_package() {
|
||||
release_archive="$1"
|
||||
release_extract_dir="$2"
|
||||
|
||||
mkdir -p "$release_extract_dir"
|
||||
unzip -oq "$release_archive" -d "$release_extract_dir"
|
||||
}
|
||||
|
||||
assert_single_jar() {
|
||||
search_dir="$1"
|
||||
count=$(find "$search_dir" -type f -name '*.jar' ! -path '*/__MACOSX/*' ! -name '._*' | wc -l | tr -d ' ')
|
||||
|
||||
if [ "$count" -ne 1 ]; then
|
||||
log_error "后端 jar 数量不正确,期望 1 个,实际 $count 个"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
find "$search_dir" -type f -name '*.jar' ! -path '*/__MACOSX/*' ! -name '._*' | head -n 1
|
||||
}
|
||||
|
||||
assert_single_dist_zip() {
|
||||
search_dir="$1"
|
||||
count=$(find "$search_dir" -type f -name 'dist.zip' ! -path '*/__MACOSX/*' ! -name '._*' | wc -l | tr -d ' ')
|
||||
|
||||
if [ "$count" -ne 1 ]; then
|
||||
log_error "前端 dist.zip 数量不正确,期望 1 个,实际 $count 个"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
find "$search_dir" -type f -name 'dist.zip' ! -path '*/__MACOSX/*' ! -name '._*' | head -n 1
|
||||
}
|
||||
|
||||
backup_backend_jar() {
|
||||
if [ -f "$BACKEND_JAR_TARGET" ]; then
|
||||
mv "$BACKEND_JAR_TARGET" "$BACKEND_JAR_TARGET.$(timestamp).bak"
|
||||
fi
|
||||
}
|
||||
|
||||
backup_frontend_dist() {
|
||||
if [ -d "$FRONTEND_DIST_DIR" ]; then
|
||||
mv "$FRONTEND_DIST_DIR" "$FRONTEND_DIR/dist-$(timestamp)"
|
||||
fi
|
||||
}
|
||||
|
||||
deploy_backend_jar() {
|
||||
source_jar="$1"
|
||||
mv "$source_jar" "$BACKEND_JAR_TARGET"
|
||||
}
|
||||
|
||||
deploy_frontend_dist() {
|
||||
source_dist_zip="$1"
|
||||
rm -f "$FRONTEND_DIST_ARCHIVE"
|
||||
rm -rf "$FRONTEND_DIST_DIR"
|
||||
mv "$source_dist_zip" "$FRONTEND_DIST_ARCHIVE"
|
||||
unzip -oq "$FRONTEND_DIST_ARCHIVE" -d "$FRONTEND_DIR"
|
||||
|
||||
if [ ! -d "$FRONTEND_DIST_DIR" ]; then
|
||||
log_error "dist.zip 解压后未找到 $FRONTEND_DIST_DIR"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
collect_backend_pids() {
|
||||
ps -ef | awk -v marker="$BACKEND_MARKER" -v jar="$BACKEND_JAR_TARGET" '
|
||||
index($0, "<defunct>") == 0 && index($0, marker) > 0 {
|
||||
for (i = 1; i < NF; i++) {
|
||||
if ($i == "-jar" && $(i + 1) == jar) {
|
||||
print $2
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
' | xargs 2>/dev/null || true
|
||||
}
|
||||
|
||||
stop_backend() {
|
||||
pids=$(collect_backend_pids)
|
||||
|
||||
if [ -z "${pids:-}" ]; then
|
||||
rm -f "$BACKEND_PID_FILE"
|
||||
log_info "未发现运行中的后端进程"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "停止后端进程: $pids"
|
||||
for pid in $pids; do
|
||||
kill -TERM "$pid" 2>/dev/null || true
|
||||
done
|
||||
|
||||
elapsed=0
|
||||
remaining="$pids"
|
||||
while [ "$elapsed" -lt 30 ]; do
|
||||
remaining=""
|
||||
for pid in $pids; do
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
remaining="$remaining $pid"
|
||||
fi
|
||||
done
|
||||
|
||||
remaining=$(echo "$remaining" | xargs 2>/dev/null || true)
|
||||
if [ -z "${remaining:-}" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
elapsed=$((elapsed + 1))
|
||||
done
|
||||
|
||||
if [ -n "${remaining:-}" ]; then
|
||||
log_info "执行强制停止: $remaining"
|
||||
for pid in $remaining; do
|
||||
kill -KILL "$pid" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
|
||||
rm -f "$BACKEND_PID_FILE"
|
||||
}
|
||||
|
||||
start_backend() {
|
||||
if [ ! -x "$JAVA_BIN" ]; then
|
||||
log_error "未检测到可执行 Java: $JAVA_BIN"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$BACKEND_JAR_TARGET" ]; then
|
||||
log_error "未找到后端 jar: $BACKEND_JAR_TARGET"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$(collect_backend_pids)" ]; then
|
||||
log_error "检测到后端已在运行,请先停止旧进程"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '\n===== %s deploy =====\n' "$(date '+%Y-%m-%d %H:%M:%S')" >> "$BACKEND_LOG_FILE"
|
||||
|
||||
nohup "$JAVA_BIN" $JAVA_OPTS "$BACKEND_MARKER" -jar "$BACKEND_JAR_TARGET" \
|
||||
--spring.profiles.active="$SPRING_PROFILE" \
|
||||
--server.port="$BACKEND_PORT" >> "$BACKEND_LOG_FILE" 2>&1 &
|
||||
backend_pid=$!
|
||||
printf '%s\n' "$backend_pid" > "$BACKEND_PID_FILE"
|
||||
|
||||
sleep 1
|
||||
|
||||
if ! kill -0 "$backend_pid" 2>/dev/null; then
|
||||
log_error "后端启动失败,请检查日志: $BACKEND_LOG_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "后端已启动,PID: $backend_pid"
|
||||
}
|
||||
|
||||
main() {
|
||||
if [ "$#" -ne 0 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
require_dir "$BACKEND_DIR"
|
||||
require_dir "$FRONTEND_DIR"
|
||||
require_command unzip
|
||||
require_command find
|
||||
require_command ps
|
||||
require_command nohup
|
||||
|
||||
release_archive=$(find_release_archive)
|
||||
WORK_DIR=$(mktemp -d "${TMPDIR:-/tmp}/deploy_from_package.XXXXXX")
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
extract_release_package "$release_archive" "$WORK_DIR/package"
|
||||
|
||||
backend_jar_source=$(assert_single_jar "$WORK_DIR/package")
|
||||
frontend_dist_source=$(assert_single_dist_zip "$WORK_DIR/package")
|
||||
|
||||
backup_backend_jar
|
||||
backup_frontend_dist
|
||||
stop_backend
|
||||
deploy_backend_jar "$backend_jar_source"
|
||||
deploy_frontend_dist "$frontend_dist_source"
|
||||
start_backend
|
||||
|
||||
log_info "部署完成"
|
||||
log_info "后端 jar: $BACKEND_JAR_TARGET"
|
||||
log_info "前端目录: $FRONTEND_DIST_DIR"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
262
bin/prod/deploy_from_package_test.sh
Executable file
262
bin/prod/deploy_from_package_test.sh
Executable file
@@ -0,0 +1,262 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
ROOT_DIR=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd)
|
||||
SCRIPT_UNDER_TEST="$ROOT_DIR/bin/prod/deploy_from_package.sh"
|
||||
|
||||
fail() {
|
||||
printf 'FAIL: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
assert_file_exists() {
|
||||
file_path="$1"
|
||||
[ -e "$file_path" ] || fail "expected file to exist: $file_path"
|
||||
}
|
||||
|
||||
assert_grep() {
|
||||
pattern="$1"
|
||||
target="$2"
|
||||
if ! grep -Eq "$pattern" "$target"; then
|
||||
fail "expected pattern [$pattern] in $target"
|
||||
fi
|
||||
}
|
||||
|
||||
create_fake_java() {
|
||||
fake_java="$1"
|
||||
|
||||
cat > "$fake_java" <<'EOF'
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
port=""
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--server.port=*)
|
||||
port=${arg#--server.port=}
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$port" ]; then
|
||||
echo "missing port" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
while :; do
|
||||
sleep 1
|
||||
done
|
||||
EOF
|
||||
|
||||
chmod +x "$fake_java"
|
||||
}
|
||||
|
||||
create_release_zip() {
|
||||
release_dir="$1"
|
||||
release_zip_name="$2"
|
||||
|
||||
mkdir -p "$release_dir/package/deploy" "$release_dir/package/__MACOSX/deploy"
|
||||
mkdir -p "$release_dir/package/frontend_payload/dist" "$release_dir/package/frontend_payload/__MACOSX/dist"
|
||||
printf 'new-jar\n' > "$release_dir/package/deploy/ruoyi-admin.jar"
|
||||
printf 'macos-meta\n' > "$release_dir/package/__MACOSX/deploy/._ruoyi-admin.jar"
|
||||
printf '<html>new</html>\n' > "$release_dir/package/frontend_payload/dist/index.html"
|
||||
printf 'macos-meta\n' > "$release_dir/package/frontend_payload/__MACOSX/dist/._index.html"
|
||||
(
|
||||
cd "$release_dir/package/frontend_payload"
|
||||
zip -qr "$release_dir/package/dist.zip" dist __MACOSX
|
||||
)
|
||||
mv "$release_dir/package/dist.zip" "$release_dir/package/deploy/dist.zip"
|
||||
(
|
||||
cd "$release_dir/package"
|
||||
zip -qr "$release_dir/$release_zip_name" deploy __MACOSX
|
||||
)
|
||||
}
|
||||
|
||||
find_free_port() {
|
||||
python3 - <<'PY'
|
||||
import socket
|
||||
|
||||
sock = socket.socket()
|
||||
sock.bind(("127.0.0.1", 0))
|
||||
print(sock.getsockname()[1])
|
||||
sock.close()
|
||||
PY
|
||||
}
|
||||
|
||||
prepare_release_dir() {
|
||||
release_dir="$1"
|
||||
backend_port="$2"
|
||||
|
||||
mkdir -p "$release_dir/backend" "$release_dir/frontend" "$release_dir/fake-java-bin"
|
||||
printf 'old-jar\n' > "$release_dir/backend/ruoyi-admin.jar"
|
||||
mkdir -p "$release_dir/frontend/dist"
|
||||
printf '<html>old</html>\n' > "$release_dir/frontend/dist/index.html"
|
||||
|
||||
create_fake_java "$release_dir/fake-java-bin/java"
|
||||
create_release_zip "$release_dir" "deploy.zip"
|
||||
cp "$SCRIPT_UNDER_TEST" "$release_dir/deploy_from_package.sh"
|
||||
perl -0pi -e "s#JAVA_BIN=\"/home/webapp/env/java/bin/java\"#JAVA_BIN=\"$release_dir/fake-java-bin/java\"#" \
|
||||
"$release_dir/deploy_from_package.sh"
|
||||
perl -0pi -e "s/BACKEND_PORT=63310/BACKEND_PORT=$backend_port/" \
|
||||
"$release_dir/deploy_from_package.sh"
|
||||
chmod +x "$release_dir/deploy_from_package.sh"
|
||||
}
|
||||
|
||||
cleanup_release_dir() {
|
||||
release_dir="$1"
|
||||
|
||||
if [ -f "$release_dir/backend/backend.pid" ]; then
|
||||
backend_pid=$(cat "$release_dir/backend/backend.pid" 2>/dev/null || true)
|
||||
if [ -n "${backend_pid:-}" ]; then
|
||||
kill "$backend_pid" 2>/dev/null || true
|
||||
wait "$backend_pid" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf "$release_dir"
|
||||
}
|
||||
|
||||
test_deploy_success() {
|
||||
release_dir=$(mktemp -d)
|
||||
backend_port=$(find_free_port)
|
||||
trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM
|
||||
|
||||
prepare_release_dir "$release_dir" "$backend_port"
|
||||
(
|
||||
cd "$release_dir"
|
||||
./deploy_from_package.sh
|
||||
)
|
||||
|
||||
assert_file_exists "$release_dir/backend/ruoyi-admin.jar"
|
||||
assert_file_exists "$release_dir/frontend/dist.zip"
|
||||
assert_file_exists "$release_dir/frontend/dist/index.html"
|
||||
assert_file_exists "$release_dir/backend/backend.pid"
|
||||
assert_file_exists "$release_dir/backend/backend-console.log"
|
||||
assert_grep 'new' "$release_dir/frontend/dist/index.html"
|
||||
|
||||
backup_jar_count=$(find "$release_dir/backend" -maxdepth 1 -type f -name 'ruoyi-admin.jar.*.bak' | wc -l | tr -d ' ')
|
||||
[ "$backup_jar_count" -eq 1 ] || fail "expected one backup jar, got $backup_jar_count"
|
||||
|
||||
backup_dist_count=$(find "$release_dir/frontend" -maxdepth 1 -type d -name 'dist-*' | wc -l | tr -d ' ')
|
||||
[ "$backup_dist_count" -eq 1 ] || fail "expected one backup dist dir, got $backup_dist_count"
|
||||
|
||||
backend_pid=$(cat "$release_dir/backend/backend.pid")
|
||||
kill -0 "$backend_pid" 2>/dev/null || fail "expected backend pid to be running"
|
||||
|
||||
trap - EXIT INT TERM
|
||||
cleanup_release_dir "$release_dir"
|
||||
}
|
||||
|
||||
test_multiple_release_zip_should_fail() {
|
||||
release_dir=$(mktemp -d)
|
||||
backend_port=$(find_free_port)
|
||||
trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM
|
||||
|
||||
prepare_release_dir "$release_dir" "$backend_port"
|
||||
cp "$release_dir/deploy.zip" "$release_dir/deploy-copy.zip"
|
||||
|
||||
if (
|
||||
cd "$release_dir"
|
||||
./deploy_from_package.sh >/tmp/deploy_from_package_test.stderr 2>&1
|
||||
); then
|
||||
fail "expected deploy_from_package.sh to fail when multiple release zips exist"
|
||||
fi
|
||||
|
||||
assert_file_exists /tmp/deploy_from_package_test.stderr
|
||||
assert_grep '发布 zip 数量不正确' /tmp/deploy_from_package_test.stderr
|
||||
|
||||
rm -f /tmp/deploy_from_package_test.stderr
|
||||
trap - EXIT INT TERM
|
||||
cleanup_release_dir "$release_dir"
|
||||
}
|
||||
|
||||
test_defunct_process_should_be_ignored() {
|
||||
release_dir=$(mktemp -d)
|
||||
backend_port=$(find_free_port)
|
||||
trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM
|
||||
|
||||
prepare_release_dir "$release_dir" "$backend_port"
|
||||
mkdir -p "$release_dir/fake-ps-bin"
|
||||
cat > "$release_dir/fake-ps-bin/ps" <<EOF
|
||||
#!/bin/sh
|
||||
if [ "\$1" = "-ef" ]; then
|
||||
cat <<'PSOUT'
|
||||
UID PID PPID C STIME TTY TIME CMD
|
||||
root 99999 1 0 00:00 ? 00:00:00 [java] <defunct> -Dloan.pricing.home=$release_dir -jar $release_dir/backend/ruoyi-admin.jar
|
||||
PSOUT
|
||||
exit 0
|
||||
fi
|
||||
/bin/ps "\$@"
|
||||
EOF
|
||||
chmod +x "$release_dir/fake-ps-bin/ps"
|
||||
|
||||
(
|
||||
cd "$release_dir"
|
||||
PATH="$release_dir/fake-ps-bin:/usr/bin:/bin" ./deploy_from_package.sh
|
||||
)
|
||||
|
||||
backend_pid=$(cat "$release_dir/backend/backend.pid")
|
||||
kill -0 "$backend_pid" 2>/dev/null || fail "expected backend pid to be running when defunct process is ignored"
|
||||
|
||||
trap - EXIT INT TERM
|
||||
cleanup_release_dir "$release_dir"
|
||||
}
|
||||
|
||||
test_only_current_project_jar_should_match() {
|
||||
release_dir=$(mktemp -d)
|
||||
backend_port=$(find_free_port)
|
||||
trap 'cleanup_release_dir "$release_dir"' EXIT INT TERM
|
||||
|
||||
prepare_release_dir "$release_dir" "$backend_port"
|
||||
mkdir -p "$release_dir/fake-ps-bin"
|
||||
cat > "$release_dir/fake-ps-bin/ps" <<EOF
|
||||
#!/bin/sh
|
||||
if [ "\$1" = "-ef" ]; then
|
||||
cat <<'PSOUT'
|
||||
UID PID PPID C STIME TTY TIME CMD
|
||||
root 88888 1 0 00:00 ? 00:00:00 java -Dloan.pricing.home=$release_dir -jar $release_dir/backend/ruoyi-admin.jar.bak --spring.profiles.active=pro
|
||||
PSOUT
|
||||
exit 0
|
||||
fi
|
||||
/bin/ps "\$@"
|
||||
EOF
|
||||
chmod +x "$release_dir/fake-ps-bin/ps"
|
||||
|
||||
(
|
||||
cd "$release_dir"
|
||||
PATH="$release_dir/fake-ps-bin:/usr/bin:/bin" ./deploy_from_package.sh
|
||||
)
|
||||
|
||||
backend_pid=$(cat "$release_dir/backend/backend.pid")
|
||||
kill -0 "$backend_pid" 2>/dev/null || fail "expected backend pid to be running when non-target jar process is ignored"
|
||||
|
||||
trap - EXIT INT TERM
|
||||
cleanup_release_dir "$release_dir"
|
||||
}
|
||||
|
||||
test_should_use_ps_ef_for_process_detection() {
|
||||
if rg -n 'pgrep' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then
|
||||
fail "expected deploy_from_package.sh not to depend on pgrep"
|
||||
fi
|
||||
|
||||
if ! rg -n 'ps -ef' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then
|
||||
fail "expected deploy_from_package.sh to use ps -ef for process detection"
|
||||
fi
|
||||
|
||||
if rg -n '\b(ss|lsof|netstat|resolve_frontend_source_dir|is_port_listening)\b' "$SCRIPT_UNDER_TEST" >/dev/null 2>&1; then
|
||||
fail "expected deploy_from_package.sh to remove port detection and unzip compatibility helpers"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
[ -f "$SCRIPT_UNDER_TEST" ] || fail "script under test not found: $SCRIPT_UNDER_TEST"
|
||||
test_should_use_ps_ef_for_process_detection
|
||||
test_deploy_success
|
||||
test_multiple_release_zip_should_fail
|
||||
test_defunct_process_should_be_ignored
|
||||
test_only_current_project_jar_should_match
|
||||
printf 'PASS: deploy_from_package tests\n'
|
||||
}
|
||||
|
||||
main "$@"
|
||||
245
bin/prod/deploy_release.sh
Executable file
245
bin/prod/deploy_release.sh
Executable file
@@ -0,0 +1,245 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
WEBAPP_ROOT="/home/webapp"
|
||||
ENV_ROOT="$WEBAPP_ROOT/env"
|
||||
APP_ROOT="$WEBAPP_ROOT/loan-pricing"
|
||||
JAVA_HOME="$ENV_ROOT/java"
|
||||
NGINX_HOME="$ENV_ROOT/nginx"
|
||||
NGINX_CONF="$NGINX_HOME/conf/nginx.conf"
|
||||
BACKEND_DIR="$APP_ROOT/backend"
|
||||
FRONTEND_DIR="$APP_ROOT/frontend"
|
||||
FRONTEND_DIST_DIR="$FRONTEND_DIR/dist"
|
||||
BACKUP_DIR="$APP_ROOT/backup"
|
||||
LOG_DIR="$APP_ROOT/logs"
|
||||
RUN_DIR="$APP_ROOT/run"
|
||||
TMP_DIR="$APP_ROOT/tmp"
|
||||
BACKEND_JAR="$BACKEND_DIR/ruoyi-admin.jar"
|
||||
FRONTEND_PORT=63311
|
||||
JAVA_RESTART_SCRIPT="$WEBAPP_ROOT/restart_java.sh"
|
||||
|
||||
timestamp() {
|
||||
date "+%Y-%m-%d %H:%M:%S"
|
||||
}
|
||||
|
||||
log_info() {
|
||||
printf '[%s] %s\n' "$(timestamp)" "$1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
printf '[%s] %s\n' "$(timestamp)" "$1" >&2
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
用法:
|
||||
./bin/prod/deploy_release.sh <发布压缩包路径>
|
||||
EOF
|
||||
}
|
||||
|
||||
require_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
log_error "请使用 root 用户执行部署脚本"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_command() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
log_error "缺少命令: $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_runtime_dirs() {
|
||||
mkdir -p "$BACKEND_DIR" "$FRONTEND_DIR" "$BACKUP_DIR" "$LOG_DIR" "$RUN_DIR" "$TMP_DIR"
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if [ -n "${WORK_DIR:-}" ] && [ -d "$WORK_DIR" ]; then
|
||||
rm -rf "$WORK_DIR"
|
||||
fi
|
||||
}
|
||||
|
||||
extract_release_package() {
|
||||
release_archive="$1"
|
||||
release_extract_dir="$2"
|
||||
|
||||
mkdir -p "$release_extract_dir"
|
||||
|
||||
case "$release_archive" in
|
||||
*.zip)
|
||||
unzip -oq "$release_archive" -d "$release_extract_dir"
|
||||
;;
|
||||
*.tar.gz|*.tgz)
|
||||
tar -xzf "$release_archive" -C "$release_extract_dir"
|
||||
;;
|
||||
*.tar)
|
||||
tar -xf "$release_archive" -C "$release_extract_dir"
|
||||
;;
|
||||
*)
|
||||
log_error "不支持的发布包格式: $release_archive"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
assert_single_file() {
|
||||
search_dir="$1"
|
||||
file_name="$2"
|
||||
description="$3"
|
||||
count=$(find "$search_dir" -type f -name "$file_name" | wc -l | tr -d ' ')
|
||||
|
||||
if [ "$count" -ne 1 ]; then
|
||||
log_error "$description 数量不正确,期望 1 个,实际 $count 个"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
find "$search_dir" -type f -name "$file_name" | head -n 1
|
||||
}
|
||||
|
||||
assert_single_jar() {
|
||||
search_dir="$1"
|
||||
count=$(find "$search_dir" -type f -name '*.jar' | wc -l | tr -d ' ')
|
||||
|
||||
if [ "$count" -ne 1 ]; then
|
||||
log_error "后端 jar 数量不正确,期望 1 个,实际 $count 个"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
find "$search_dir" -type f -name '*.jar' | head -n 1
|
||||
}
|
||||
|
||||
backup_current_release() {
|
||||
backup_stamp=$(date "+%Y%m%d%H%M%S")
|
||||
CURRENT_BACKUP_DIR="$BACKUP_DIR/$backup_stamp"
|
||||
|
||||
mkdir -p "$CURRENT_BACKUP_DIR/backend" "$CURRENT_BACKUP_DIR/frontend"
|
||||
|
||||
if [ -f "$BACKEND_JAR" ]; then
|
||||
cp -a "$BACKEND_JAR" "$CURRENT_BACKUP_DIR/backend/"
|
||||
fi
|
||||
|
||||
if [ -d "$FRONTEND_DIST_DIR" ]; then
|
||||
cp -a "$FRONTEND_DIST_DIR" "$CURRENT_BACKUP_DIR/frontend/"
|
||||
fi
|
||||
|
||||
log_info "旧版本已备份到: $CURRENT_BACKUP_DIR"
|
||||
}
|
||||
|
||||
deploy_backend() {
|
||||
source_jar="$1"
|
||||
|
||||
rm -f "$BACKEND_DIR"/*.jar
|
||||
cp "$source_jar" "$BACKEND_JAR"
|
||||
}
|
||||
|
||||
resolve_frontend_source_dir() {
|
||||
unzip_dir="$1"
|
||||
|
||||
if [ -f "$unzip_dir/index.html" ]; then
|
||||
printf '%s\n' "$unzip_dir"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -f "$unzip_dir/dist/index.html" ]; then
|
||||
printf '%s\n' "$unzip_dir/dist"
|
||||
return 0
|
||||
fi
|
||||
|
||||
candidate=$(find "$unzip_dir" -type f -name 'index.html' | head -n 1)
|
||||
if [ -z "${candidate:-}" ]; then
|
||||
log_error "dist.zip 解压后未找到 index.html"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
dirname "$candidate"
|
||||
}
|
||||
|
||||
deploy_frontend() {
|
||||
dist_zip="$1"
|
||||
dist_unpack_dir="$WORK_DIR/frontend"
|
||||
|
||||
mkdir -p "$dist_unpack_dir"
|
||||
unzip -oq "$dist_zip" -d "$dist_unpack_dir"
|
||||
|
||||
frontend_source_dir=$(resolve_frontend_source_dir "$dist_unpack_dir")
|
||||
rm -rf "$FRONTEND_DIST_DIR"
|
||||
mkdir -p "$FRONTEND_DIST_DIR"
|
||||
cp -a "$frontend_source_dir"/. "$FRONTEND_DIST_DIR"/
|
||||
}
|
||||
|
||||
reload_nginx() {
|
||||
nginx_pid_file="$RUN_DIR/nginx.pid"
|
||||
|
||||
"$NGINX_HOME/sbin/nginx" -t -c "$NGINX_CONF"
|
||||
|
||||
if [ -f "$nginx_pid_file" ]; then
|
||||
nginx_pid=$(cat "$nginx_pid_file" 2>/dev/null || true)
|
||||
if [ -n "${nginx_pid:-}" ] && kill -0 "$nginx_pid" 2>/dev/null; then
|
||||
"$NGINX_HOME/sbin/nginx" -c "$NGINX_CONF" -s reload
|
||||
log_info "Nginx 已重载,前端端口: $FRONTEND_PORT"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
"$NGINX_HOME/sbin/nginx" -c "$NGINX_CONF"
|
||||
log_info "Nginx 已启动,前端端口: $FRONTEND_PORT"
|
||||
}
|
||||
|
||||
main() {
|
||||
if [ "$#" -ne 1 ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
require_root
|
||||
require_command tar
|
||||
require_command unzip
|
||||
require_command find
|
||||
|
||||
release_archive="$1"
|
||||
if [ ! -f "$release_archive" ]; then
|
||||
log_error "发布压缩包不存在: $release_archive"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVA_HOME/bin/java" ]; then
|
||||
log_error "未检测到 Java,请先执行 ./bin/prod/install_env.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$NGINX_HOME/sbin/nginx" ]; then
|
||||
log_error "未检测到 Nginx,请先执行 ./bin/prod/install_env.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -x "$JAVA_RESTART_SCRIPT" ]; then
|
||||
log_error "未检测到 Java 重启脚本: $JAVA_RESTART_SCRIPT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ensure_runtime_dirs
|
||||
WORK_DIR=$(mktemp -d "$TMP_DIR/release.XXXXXX")
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
extract_release_package "$release_archive" "$WORK_DIR/package"
|
||||
|
||||
backend_jar_source=$(assert_single_jar "$WORK_DIR/package")
|
||||
frontend_dist_source=$(assert_single_file "$WORK_DIR/package" 'dist.zip' '前端 dist.zip')
|
||||
|
||||
backup_current_release
|
||||
"$JAVA_RESTART_SCRIPT" stop
|
||||
deploy_backend "$backend_jar_source"
|
||||
deploy_frontend "$frontend_dist_source"
|
||||
"$JAVA_RESTART_SCRIPT" start
|
||||
reload_nginx
|
||||
|
||||
log_info "部署完成"
|
||||
log_info "后端 jar: $BACKEND_JAR"
|
||||
log_info "前端目录: $FRONTEND_DIST_DIR"
|
||||
log_info "备份目录: $CURRENT_BACKUP_DIR"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
244
bin/prod/install_env.sh
Executable file
244
bin/prod/install_env.sh
Executable file
@@ -0,0 +1,244 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
WEBAPP_ROOT="/home/webapp"
|
||||
ENV_ROOT="$WEBAPP_ROOT/env"
|
||||
APP_ROOT="$WEBAPP_ROOT/loan-pricing"
|
||||
JAVA_HOME="$ENV_ROOT/java"
|
||||
NGINX_HOME="$ENV_ROOT/nginx"
|
||||
NGINX_CONF="$NGINX_HOME/conf/nginx.conf"
|
||||
BACKEND_DIR="$APP_ROOT/backend"
|
||||
FRONTEND_DIR="$APP_ROOT/frontend"
|
||||
BACKUP_DIR="$APP_ROOT/backup"
|
||||
LOG_DIR="$APP_ROOT/logs"
|
||||
RUN_DIR="$APP_ROOT/run"
|
||||
TMP_DIR="$APP_ROOT/tmp"
|
||||
BACKEND_PORT=63310
|
||||
FRONTEND_PORT=63311
|
||||
|
||||
timestamp() {
|
||||
date "+%Y-%m-%d %H:%M:%S"
|
||||
}
|
||||
|
||||
log_info() {
|
||||
printf '[%s] %s\n' "$(timestamp)" "$1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
printf '[%s] %s\n' "$(timestamp)" "$1" >&2
|
||||
}
|
||||
|
||||
require_root() {
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
log_error "请使用 root 用户执行安装脚本"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
require_command() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
log_error "缺少命令: $1"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_base_dirs() {
|
||||
mkdir -p "$ENV_ROOT" "$BACKEND_DIR" "$FRONTEND_DIR" "$BACKUP_DIR" "$LOG_DIR" "$RUN_DIR" "$TMP_DIR"
|
||||
}
|
||||
|
||||
find_archive() {
|
||||
search_kind="$1"
|
||||
found=""
|
||||
|
||||
case "$search_kind" in
|
||||
java)
|
||||
set -- "$WEBAPP_ROOT/openjdk" "$WEBAPP_ROOT"
|
||||
patterns='openjdk*.tar.gz openjdk*.tgz jdk*.tar.gz jdk*.tgz'
|
||||
;;
|
||||
nginx)
|
||||
set -- "$WEBAPP_ROOT/nginx" "$ENV_ROOT" "$WEBAPP_ROOT"
|
||||
patterns='nginx-*.tar.gz nginx-*.tgz'
|
||||
;;
|
||||
*)
|
||||
log_error "未知的安装包类型: $search_kind"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
for dir in "$@"; do
|
||||
if [ ! -d "$dir" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
for pattern in $patterns; do
|
||||
candidate=$(find "$dir" -maxdepth 1 -type f -name "$pattern" | sort | head -n 1)
|
||||
if [ -n "${candidate:-}" ]; then
|
||||
found="$candidate"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "${found:-}" ]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "${found:-}" ]; then
|
||||
log_error "未找到 $search_kind 安装包"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '%s\n' "$found"
|
||||
}
|
||||
|
||||
install_yum_dependencies() {
|
||||
require_command yum
|
||||
|
||||
log_info "安装系统依赖"
|
||||
yum install -y \
|
||||
gcc \
|
||||
make \
|
||||
pcre \
|
||||
pcre-devel \
|
||||
zlib \
|
||||
zlib-devel \
|
||||
openssl \
|
||||
openssl-devel \
|
||||
tar \
|
||||
gzip \
|
||||
unzip \
|
||||
which \
|
||||
findutils \
|
||||
procps-ng \
|
||||
iproute
|
||||
}
|
||||
|
||||
install_java() {
|
||||
java_archive="$1"
|
||||
|
||||
log_info "安装 Java: $java_archive"
|
||||
rm -rf "$JAVA_HOME"
|
||||
mkdir -p "$JAVA_HOME"
|
||||
tar -xzf "$java_archive" -C "$JAVA_HOME" --strip-components=1
|
||||
|
||||
if [ ! -x "$JAVA_HOME/bin/java" ]; then
|
||||
log_error "Java 安装失败,未找到 $JAVA_HOME/bin/java"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
"$JAVA_HOME/bin/java" -version >/dev/null 2>&1
|
||||
}
|
||||
|
||||
install_nginx() {
|
||||
nginx_archive="$1"
|
||||
build_dir=$(mktemp -d "$ENV_ROOT/nginx-build.XXXXXX")
|
||||
|
||||
log_info "编译安装 Nginx: $nginx_archive"
|
||||
rm -rf "$NGINX_HOME"
|
||||
mkdir -p "$NGINX_HOME"
|
||||
|
||||
tar -xzf "$nginx_archive" -C "$build_dir"
|
||||
source_dir=$(find "$build_dir" -mindepth 1 -maxdepth 1 -type d | head -n 1)
|
||||
if [ -z "${source_dir:-}" ]; then
|
||||
rm -rf "$build_dir"
|
||||
log_error "Nginx 源码目录解析失败"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
jobs=$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1)
|
||||
(
|
||||
cd "$source_dir"
|
||||
./configure --prefix="$NGINX_HOME" --with-http_ssl_module
|
||||
make -j"$jobs"
|
||||
make install
|
||||
)
|
||||
|
||||
rm -rf "$build_dir"
|
||||
|
||||
if [ ! -x "$NGINX_HOME/sbin/nginx" ]; then
|
||||
log_error "Nginx 安装失败,未找到 $NGINX_HOME/sbin/nginx"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
write_nginx_conf() {
|
||||
log_info "写入 Nginx 配置: $NGINX_CONF"
|
||||
|
||||
mkdir -p "$NGINX_HOME/conf" "$NGINX_HOME/logs" "$FRONTEND_DIR/dist"
|
||||
|
||||
cat > "$NGINX_CONF" <<EOF
|
||||
user nobody;
|
||||
worker_processes 1;
|
||||
|
||||
error_log $LOG_DIR/nginx-error.log warn;
|
||||
pid $RUN_DIR/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include $NGINX_HOME/conf/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" '
|
||||
'\$status \$body_bytes_sent "\$http_referer" '
|
||||
'"\$http_user_agent" "\$http_x_forwarded_for"';
|
||||
|
||||
access_log $LOG_DIR/nginx-access.log main;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
client_max_body_size 100m;
|
||||
|
||||
server {
|
||||
listen $FRONTEND_PORT;
|
||||
server_name _;
|
||||
|
||||
root $FRONTEND_DIR/dist;
|
||||
index index.html;
|
||||
|
||||
location /prod-api/ {
|
||||
proxy_pass http://127.0.0.1:$BACKEND_PORT/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host \$host;
|
||||
proxy_set_header X-Real-IP \$remote_addr;
|
||||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files \$uri \$uri/ /index.html;
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
"$NGINX_HOME/sbin/nginx" -t -c "$NGINX_CONF"
|
||||
}
|
||||
|
||||
main() {
|
||||
require_root
|
||||
require_command tar
|
||||
require_command find
|
||||
ensure_base_dirs
|
||||
install_yum_dependencies
|
||||
|
||||
java_archive=$(find_archive java)
|
||||
nginx_archive=$(find_archive nginx)
|
||||
|
||||
log_info "检测到 Java 安装包: $java_archive"
|
||||
log_info "检测到 Nginx 安装包: $nginx_archive"
|
||||
|
||||
install_java "$java_archive"
|
||||
install_nginx "$nginx_archive"
|
||||
write_nginx_conf
|
||||
|
||||
log_info "环境安装完成"
|
||||
log_info "JAVA_HOME=$JAVA_HOME"
|
||||
log_info "NGINX_HOME=$NGINX_HOME"
|
||||
log_info "前端端口=$FRONTEND_PORT,后端端口=$BACKEND_PORT"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
208
bin/prod/restart_java.sh
Executable file
208
bin/prod/restart_java.sh
Executable file
@@ -0,0 +1,208 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
WEBAPP_ROOT="/home/webapp"
|
||||
ENV_ROOT="$WEBAPP_ROOT/env"
|
||||
APP_ROOT="$WEBAPP_ROOT/loan-pricing"
|
||||
JAVA_HOME="$ENV_ROOT/jdk"
|
||||
BACKEND_DIR="$APP_ROOT/backend"
|
||||
LOG_DIR="$APP_ROOT/logs"
|
||||
RUN_DIR="$APP_ROOT/run"
|
||||
BACKEND_PID_FILE="$RUN_DIR/backend.pid"
|
||||
BACKEND_JAR="$BACKEND_DIR/ruoyi-admin.jar"
|
||||
BACKEND_CONSOLE_LOG="$LOG_DIR/backend-console.log"
|
||||
BACKEND_PORT=63310
|
||||
BACKEND_MARKER="-Dloan.pricing.home=$APP_ROOT"
|
||||
JAVA_OPTS="$BACKEND_MARKER -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError"
|
||||
|
||||
timestamp() {
|
||||
date "+%Y-%m-%d %H:%M:%S"
|
||||
}
|
||||
|
||||
log_info() {
|
||||
printf '[%s] %s\n' "$(timestamp)" "$1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
printf '[%s] %s\n' "$(timestamp)" "$1" >&2
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
用法: ./restart_java.sh [start|stop|restart|status]
|
||||
|
||||
默认动作:
|
||||
restart 重启后端 Java 进程
|
||||
EOF
|
||||
}
|
||||
|
||||
ensure_runtime_dirs() {
|
||||
mkdir -p "$BACKEND_DIR" "$LOG_DIR" "$RUN_DIR"
|
||||
}
|
||||
|
||||
is_managed_backend_pid() {
|
||||
pid="$1"
|
||||
if [ -z "${pid:-}" ] || ! kill -0 "$pid" 2>/dev/null; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
args=$(ps -o args= -p "$pid" 2>/dev/null || true)
|
||||
if [ -z "${args:-}" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "$args" in
|
||||
*"$BACKEND_MARKER"*"$BACKEND_JAR"*|*"$BACKEND_JAR"*"$BACKEND_MARKER"*)
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
collect_backend_pids() {
|
||||
pids=""
|
||||
|
||||
if [ -f "$BACKEND_PID_FILE" ]; then
|
||||
file_pid=$(cat "$BACKEND_PID_FILE" 2>/dev/null || true)
|
||||
if [ -n "${file_pid:-}" ] && is_managed_backend_pid "$file_pid"; then
|
||||
pids="$pids $file_pid"
|
||||
fi
|
||||
fi
|
||||
|
||||
marker_pids=$(ps -ef | awk -v marker="$BACKEND_MARKER" -v jar="$BACKEND_JAR" '
|
||||
index($0, "<defunct>") == 0 && index($0, marker) > 0 {
|
||||
for (i = 1; i < NF; i++) {
|
||||
if ($i == "-jar" && $(i + 1) == jar) {
|
||||
print $2
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
' | xargs 2>/dev/null || true)
|
||||
if [ -n "${marker_pids:-}" ]; then
|
||||
for pid in $marker_pids; do
|
||||
if is_managed_backend_pid "$pid"; then
|
||||
pids="$pids $pid"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
printf '%s\n' "$(echo "$pids" | xargs 2>/dev/null || true)"
|
||||
}
|
||||
|
||||
stop_backend() {
|
||||
pids=$(collect_backend_pids)
|
||||
|
||||
if [ -z "${pids:-}" ]; then
|
||||
rm -f "$BACKEND_PID_FILE"
|
||||
log_info "未发现运行中的后端进程"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "停止后端进程: $pids"
|
||||
for pid in $pids; do
|
||||
kill -TERM "$pid" 2>/dev/null || true
|
||||
done
|
||||
|
||||
elapsed=0
|
||||
while [ "$elapsed" -lt 30 ]; do
|
||||
remaining=""
|
||||
for pid in $pids; do
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
remaining="$remaining $pid"
|
||||
fi
|
||||
done
|
||||
|
||||
remaining=$(echo "$remaining" | xargs 2>/dev/null || true)
|
||||
if [ -z "${remaining:-}" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
elapsed=$((elapsed + 1))
|
||||
done
|
||||
|
||||
if [ -n "${remaining:-}" ]; then
|
||||
log_info "执行强制停止: $remaining"
|
||||
for pid in $remaining; do
|
||||
kill -KILL "$pid" 2>/dev/null || true
|
||||
done
|
||||
fi
|
||||
|
||||
rm -f "$BACKEND_PID_FILE"
|
||||
}
|
||||
|
||||
start_backend() {
|
||||
ensure_runtime_dirs
|
||||
|
||||
if [ ! -x "$JAVA_HOME/bin/java" ]; then
|
||||
log_error "未检测到可执行 Java: $JAVA_HOME/bin/java"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$BACKEND_JAR" ]; then
|
||||
log_error "未找到后端 jar: $BACKEND_JAR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -n "$(collect_backend_pids)" ]; then
|
||||
log_error "检测到后端已在运行,请先执行 stop 或 restart"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '\n===== %s restart =====\n' "$(timestamp)" >> "$BACKEND_CONSOLE_LOG"
|
||||
|
||||
(
|
||||
cd "$BACKEND_DIR"
|
||||
nohup "$JAVA_HOME/bin/java" $JAVA_OPTS -jar "$BACKEND_JAR" --spring.profiles.active=pro --server.port="$BACKEND_PORT" >> "$BACKEND_CONSOLE_LOG" 2>&1 &
|
||||
echo $! > "$BACKEND_PID_FILE"
|
||||
)
|
||||
|
||||
sleep 3
|
||||
|
||||
backend_pid=$(cat "$BACKEND_PID_FILE" 2>/dev/null || true)
|
||||
if [ -z "${backend_pid:-}" ] || ! kill -0 "$backend_pid" 2>/dev/null; then
|
||||
log_error "后端启动失败,请检查日志: $BACKEND_CONSOLE_LOG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "后端已启动,PID: $backend_pid"
|
||||
}
|
||||
|
||||
status_backend() {
|
||||
pids=$(collect_backend_pids)
|
||||
if [ -n "${pids:-}" ]; then
|
||||
log_info "后端正在运行,进程: $pids"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "后端未运行"
|
||||
}
|
||||
|
||||
main() {
|
||||
action="${1:-restart}"
|
||||
|
||||
case "$action" in
|
||||
start)
|
||||
start_backend
|
||||
;;
|
||||
stop)
|
||||
stop_backend
|
||||
;;
|
||||
restart)
|
||||
stop_backend
|
||||
start_backend
|
||||
;;
|
||||
status)
|
||||
status_backend
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main "$@"
|
||||
116
bin/prod/restart_java_test.sh
Normal file
116
bin/prod/restart_java_test.sh
Normal file
@@ -0,0 +1,116 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
ROOT_DIR=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd)
|
||||
SCRIPT_UNDER_TEST="$ROOT_DIR/bin/prod/restart_java.sh"
|
||||
|
||||
fail() {
|
||||
printf 'FAIL: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
assert_grep() {
|
||||
pattern="$1"
|
||||
target="$2"
|
||||
if ! grep -Eq -- "$pattern" "$target"; then
|
||||
fail "expected pattern [$pattern] in $target"
|
||||
fi
|
||||
}
|
||||
|
||||
assert_not_grep() {
|
||||
pattern="$1"
|
||||
target="$2"
|
||||
if grep -Eq -- "$pattern" "$target"; then
|
||||
fail "did not expect pattern [$pattern] in $target"
|
||||
fi
|
||||
}
|
||||
|
||||
create_fake_java() {
|
||||
fake_java="$1"
|
||||
|
||||
cat > "$fake_java" <<'EOF'
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
while :; do
|
||||
sleep 1
|
||||
done
|
||||
EOF
|
||||
|
||||
chmod +x "$fake_java"
|
||||
}
|
||||
|
||||
prepare_script_env() {
|
||||
work_dir="$1"
|
||||
|
||||
mkdir -p "$work_dir/env/jdk/bin" "$work_dir/loan-pricing/backend" "$work_dir/loan-pricing/logs" "$work_dir/loan-pricing/run"
|
||||
create_fake_java "$work_dir/env/jdk/bin/java"
|
||||
printf 'fake-jar\n' > "$work_dir/loan-pricing/backend/ruoyi-admin.jar"
|
||||
cp "$SCRIPT_UNDER_TEST" "$work_dir/restart_java.sh"
|
||||
perl -0pi -e "s#WEBAPP_ROOT=\"/home/webapp\"#WEBAPP_ROOT=\"$work_dir\"#" "$work_dir/restart_java.sh"
|
||||
chmod +x "$work_dir/restart_java.sh"
|
||||
}
|
||||
|
||||
cleanup_work_dir() {
|
||||
work_dir="$1"
|
||||
|
||||
if [ -f "$work_dir/loan-pricing/run/backend.pid" ]; then
|
||||
backend_pid=$(cat "$work_dir/loan-pricing/run/backend.pid" 2>/dev/null || true)
|
||||
if [ -n "${backend_pid:-}" ]; then
|
||||
kill "$backend_pid" 2>/dev/null || true
|
||||
wait "$backend_pid" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
rm -rf "$work_dir"
|
||||
}
|
||||
|
||||
test_script_contract() {
|
||||
assert_grep 'JAVA_HOME="\$ENV_ROOT/jdk"' "$SCRIPT_UNDER_TEST"
|
||||
assert_grep '--spring\.profiles\.active=pro' "$SCRIPT_UNDER_TEST"
|
||||
assert_grep 'ps -ef' "$SCRIPT_UNDER_TEST"
|
||||
assert_not_grep 'pgrep' "$SCRIPT_UNDER_TEST"
|
||||
assert_not_grep 'mvn' "$SCRIPT_UNDER_TEST"
|
||||
assert_not_grep 'require_root' "$SCRIPT_UNDER_TEST"
|
||||
assert_not_grep '\b(ss|lsof|netstat)\b' "$SCRIPT_UNDER_TEST"
|
||||
}
|
||||
|
||||
test_restart_flow() {
|
||||
work_dir=$(mktemp -d)
|
||||
trap 'cleanup_work_dir "$work_dir"' EXIT INT TERM
|
||||
|
||||
prepare_script_env "$work_dir"
|
||||
|
||||
"$work_dir/restart_java.sh" start
|
||||
if [ ! -f "$work_dir/loan-pricing/run/backend.pid" ]; then
|
||||
fail "expected backend pid file after start"
|
||||
fi
|
||||
|
||||
backend_pid=$(cat "$work_dir/loan-pricing/run/backend.pid")
|
||||
kill -0 "$backend_pid" 2>/dev/null || fail "expected backend process to be running after start"
|
||||
|
||||
status_output=$("$work_dir/restart_java.sh" status 2>&1 || true)
|
||||
printf '%s\n' "$status_output" | grep -q '后端正在运行' || fail "expected status output to show running"
|
||||
|
||||
"$work_dir/restart_java.sh" restart
|
||||
restarted_pid=$(cat "$work_dir/loan-pricing/run/backend.pid")
|
||||
kill -0 "$restarted_pid" 2>/dev/null || fail "expected backend process to be running after restart"
|
||||
|
||||
"$work_dir/restart_java.sh" stop
|
||||
if [ -f "$work_dir/loan-pricing/run/backend.pid" ]; then
|
||||
fail "expected backend pid file to be removed after stop"
|
||||
fi
|
||||
|
||||
trap - EXIT INT TERM
|
||||
cleanup_work_dir "$work_dir"
|
||||
}
|
||||
|
||||
main() {
|
||||
[ -f "$SCRIPT_UNDER_TEST" ] || fail "script under test not found: $SCRIPT_UNDER_TEST"
|
||||
test_script_contract
|
||||
test_restart_flow
|
||||
printf 'PASS: restart_java tests\n'
|
||||
}
|
||||
|
||||
main "$@"
|
||||
190
deploy/2026-03-31-local-nginx-java-install-manual.md
Normal file
190
deploy/2026-03-31-local-nginx-java-install-manual.md
Normal file
@@ -0,0 +1,190 @@
|
||||
# 本地安装 Nginx 和 Java 手册
|
||||
|
||||
## 适用范围
|
||||
|
||||
本手册适用于需要在本地 Linux 环境手动安装贷款定价系统运行环境的场景,安装结果与当前生产脚本约定保持一致:
|
||||
|
||||
- Java 安装到 `/home/webapp/env/java`
|
||||
- Nginx 安装到 `/home/webapp/env/nginx`
|
||||
- 项目部署目录使用 `/home/webapp/loan-pricing`
|
||||
- 后端服务端口固定为 `63310`
|
||||
- 前端 Nginx 端口固定为 `63311`
|
||||
|
||||
## 前置条件
|
||||
|
||||
安装前请先确认:
|
||||
|
||||
- 当前用户具备 `root` 权限
|
||||
- 本机已配置可用的 `yum` 源
|
||||
- `/home/webapp` 目录已存在
|
||||
- `/home/webapp` 下已准备安装包:
|
||||
- `openjdk-21.0.2_linux-aarch64_bin.tar.gz`
|
||||
- `nginx-1.20.2.tar.gz`
|
||||
|
||||
如果安装包文件名不同,只要仍是 Java 的 `tar.gz` 包和 Nginx 的源码 `tar.gz` 包,也可以使用同样步骤。
|
||||
|
||||
## 目录规划
|
||||
|
||||
安装完成后目录结构如下:
|
||||
|
||||
```text
|
||||
/home/webapp
|
||||
├── env
|
||||
│ ├── java
|
||||
│ └── nginx
|
||||
└── loan-pricing
|
||||
├── backend
|
||||
├── frontend
|
||||
├── backup
|
||||
├── logs
|
||||
├── run
|
||||
└── tmp
|
||||
```
|
||||
|
||||
## 第一步:安装系统依赖
|
||||
|
||||
执行以下命令安装编译 Nginx 和运行部署脚本所需依赖:
|
||||
|
||||
```sh
|
||||
yum install -y \
|
||||
gcc \
|
||||
make \
|
||||
pcre \
|
||||
pcre-devel \
|
||||
zlib \
|
||||
zlib-devel \
|
||||
openssl \
|
||||
openssl-devel \
|
||||
tar \
|
||||
gzip \
|
||||
unzip \
|
||||
which \
|
||||
findutils \
|
||||
procps-ng \
|
||||
iproute
|
||||
```
|
||||
|
||||
## 第二步:创建目录
|
||||
|
||||
执行以下命令初始化目录:
|
||||
|
||||
```sh
|
||||
mkdir -p \
|
||||
/home/webapp/env \
|
||||
/home/webapp/loan-pricing/backend \
|
||||
/home/webapp/loan-pricing/frontend \
|
||||
/home/webapp/loan-pricing/backup \
|
||||
/home/webapp/loan-pricing/logs \
|
||||
/home/webapp/loan-pricing/run \
|
||||
/home/webapp/loan-pricing/tmp
|
||||
```
|
||||
|
||||
## 第三步:安装 Java
|
||||
|
||||
解压 Java 安装包到目标目录:
|
||||
|
||||
```sh
|
||||
rm -rf /home/webapp/env/java
|
||||
mkdir -p /home/webapp/env/java
|
||||
tar -xzf /home/webapp/openjdk-21.0.2_linux-aarch64_bin.tar.gz -C /home/webapp/env/java --strip-components=1
|
||||
```
|
||||
|
||||
验证安装结果:
|
||||
|
||||
```sh
|
||||
/home/webapp/env/java/bin/java -version
|
||||
```
|
||||
|
||||
如果能正常输出 Java 版本,说明安装成功。
|
||||
|
||||
## 第四步:安装 Nginx
|
||||
|
||||
Nginx 安装包为源码包,需要先解压、编译、安装:
|
||||
|
||||
```sh
|
||||
rm -rf /home/webapp/env/nginx
|
||||
mkdir -p /home/webapp/env/nginx
|
||||
mkdir -p /home/webapp/env/nginx-build
|
||||
tar -xzf /home/webapp/nginx-1.20.2.tar.gz -C /home/webapp/env/nginx-build
|
||||
cd /home/webapp/env/nginx-build/nginx-1.20.2
|
||||
./configure --prefix=/home/webapp/env/nginx --with-http_ssl_module
|
||||
make -j"$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 1)"
|
||||
make install
|
||||
```
|
||||
|
||||
安装完成后可执行文件位置为:
|
||||
|
||||
```text
|
||||
/home/webapp/env/nginx/sbin/nginx
|
||||
```
|
||||
|
||||
## 第五步:写入 Nginx 配置
|
||||
|
||||
仓库已提供可直接参考的配置文件:
|
||||
|
||||
```text
|
||||
deploy/nginx.conf
|
||||
```
|
||||
|
||||
将该文件内容写入 `/home/webapp/env/nginx/conf/nginx.conf` 即可。
|
||||
|
||||
## 第六步:校验 Nginx 配置
|
||||
|
||||
执行:
|
||||
|
||||
```sh
|
||||
/home/webapp/env/nginx/sbin/nginx -t -c /home/webapp/env/nginx/conf/nginx.conf
|
||||
```
|
||||
|
||||
如果输出 `syntax is ok` 和 `test is successful`,说明配置可用。
|
||||
|
||||
## 第七步:启动 Nginx
|
||||
|
||||
执行:
|
||||
|
||||
```sh
|
||||
/home/webapp/env/nginx/sbin/nginx -c /home/webapp/env/nginx/conf/nginx.conf
|
||||
```
|
||||
|
||||
如果后续修改了配置,可执行:
|
||||
|
||||
```sh
|
||||
/home/webapp/env/nginx/sbin/nginx -c /home/webapp/env/nginx/conf/nginx.conf -s reload
|
||||
```
|
||||
|
||||
## 第八步:验证端口
|
||||
|
||||
执行:
|
||||
|
||||
```sh
|
||||
ss -lnt | grep 63311
|
||||
```
|
||||
|
||||
如果能看到 `63311` 监听记录,说明前端 Nginx 已启动成功。
|
||||
|
||||
## 建议执行方式
|
||||
|
||||
如果本机已经放置了以下脚本,也可以直接使用脚本完成安装:
|
||||
|
||||
```sh
|
||||
cd /home/webapp
|
||||
./install_env.sh
|
||||
```
|
||||
|
||||
如果只需要管理后端 Java 进程,可执行:
|
||||
|
||||
```sh
|
||||
cd /home/webapp
|
||||
./restart_java.sh start
|
||||
./restart_java.sh stop
|
||||
./restart_java.sh restart
|
||||
./restart_java.sh status
|
||||
```
|
||||
|
||||
## 常见检查项
|
||||
|
||||
- `yum` 不可用:先确认系统已配置可用的 `yum` 源
|
||||
- Java 未安装成功:检查 `/home/webapp/openjdk-*.tar.gz` 是否存在且未损坏
|
||||
- Nginx 编译失败:检查 `gcc`、`make`、`pcre-devel`、`zlib-devel`、`openssl-devel` 是否已安装
|
||||
- Nginx 启动失败:先执行 `nginx -t` 查看配置是否正确
|
||||
- 前端无法访问后端:检查本机 `63310` 端口是否已有 Java 服务监听
|
||||
BIN
deploy/deploy.zip
Normal file
BIN
deploy/deploy.zip
Normal file
Binary file not shown.
45
deploy/nginx.conf
Normal file
45
deploy/nginx.conf
Normal file
@@ -0,0 +1,45 @@
|
||||
user nobody;
|
||||
worker_processes 1;
|
||||
|
||||
error_log /home/webapp/loan-pricing/logs/nginx-error.log warn;
|
||||
pid /home/webapp/loan-pricing/run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /home/webapp/env/nginx/conf/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /home/webapp/loan-pricing/logs/nginx-access.log main;
|
||||
|
||||
sendfile on;
|
||||
keepalive_timeout 65;
|
||||
client_max_body_size 100m;
|
||||
|
||||
server {
|
||||
listen 63311;
|
||||
server_name _;
|
||||
|
||||
root /home/webapp/loan-pricing/frontend/dist;
|
||||
index index.html;
|
||||
|
||||
location /prod-api/ {
|
||||
proxy_pass http://127.0.0.1:63310/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
}
|
||||
63
doc/2026-04-15-全量迁移892-without-redis前端实施记录.md
Normal file
63
doc/2026-04-15-全量迁移892-without-redis前端实施记录.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# 全量迁移 `892-without-redis` 前端实施记录
|
||||
|
||||
## 修改时间
|
||||
|
||||
- 2026-04-15
|
||||
|
||||
## 本次完成内容
|
||||
|
||||
- 迁入贷款定价前端页面与组件:
|
||||
- [workflow/index.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/views/loanPricing/workflow/index.vue)
|
||||
- [workflow/detail.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/views/loanPricing/workflow/detail.vue)
|
||||
- [workflow/components/PersonalCreateDialog.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/views/loanPricing/workflow/components/PersonalCreateDialog.vue)
|
||||
- [workflow/components/CorporateCreateDialog.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/views/loanPricing/workflow/components/CorporateCreateDialog.vue)
|
||||
- [workflow/components/PersonalWorkflowDetail.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue)
|
||||
- [workflow/components/CorporateWorkflowDetail.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/views/loanPricing/workflow/components/CorporateWorkflowDetail.vue)
|
||||
- [workflow/components/ModelOutputDisplay.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/views/loanPricing/workflow/components/ModelOutputDisplay.vue)
|
||||
- 迁入贷款定价 API:
|
||||
- [workflow.js](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/api/loanPricing/workflow.js)
|
||||
- 迁入密码传输工具:
|
||||
- [passwordTransfer.js](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/utils/passwordTransfer.js)
|
||||
- 接入前端密码传输调用:
|
||||
- [src/api/login.js](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/api/login.js)
|
||||
- [src/api/system/user.js](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/api/system/user.js)
|
||||
- 调整登录页默认值为空,移除默认账号密码回填:
|
||||
- [src/views/login.vue](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/src/views/login.vue)
|
||||
- 补充前端密码传输环境变量:
|
||||
- [ruoyi-ui/.env.development](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/.env.development)
|
||||
- [ruoyi-ui/.env.production](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-ui/.env.production)
|
||||
- 补充前端依赖:
|
||||
- `crypto-js`
|
||||
- `html-webpack-plugin`
|
||||
- 迁入目标分支中的前端静态测试:
|
||||
- `ruoyi-ui/tests/*`
|
||||
|
||||
## 关键整合说明
|
||||
|
||||
- 前端密码传输使用目标分支的 AES ECB 方案,但仍按当前仓库结构挂载到现有 `src/api` 层
|
||||
- 登录页默认用户名和默认密码已清空,同时保留 cookie 回填逻辑
|
||||
- 依赖安装时使用 `nvm use 14.21.3`,满足仓库对前端 Node 版本由 `nvm` 控制的要求
|
||||
- `npm install` 后补了 `html-webpack-plugin`,用于修复现有构建链缺失 peer 依赖导致的生产构建失败
|
||||
|
||||
## 验证结果
|
||||
|
||||
### 前端静态测试
|
||||
|
||||
- `source ~/.nvm/nvm.sh && cd ruoyi-ui && nvm use 14.21.3 >/dev/null && node tests/password-transfer-api.test.js && node tests/login-default-credentials.test.js && node tests/personal-create-input-params.test.js && node tests/retail-display-fields.test.js && node tests/personal-final-calculate-rate-display.test.js && node tests/workflow-detail-card-order.test.js && node tests/workflow-index-refresh.test.js`
|
||||
- 结果:通过
|
||||
|
||||
### 依赖安装
|
||||
|
||||
- `source ~/.nvm/nvm.sh && cd ruoyi-ui && nvm use 14.21.3 && npm install`
|
||||
- 结果:通过
|
||||
|
||||
### 生产构建
|
||||
|
||||
- `source ~/.nvm/nvm.sh && cd ruoyi-ui && nvm use 14.21.3 >/dev/null && npm run build:prod`
|
||||
- 结果:通过
|
||||
- 备注:有 asset size warning,但构建成功,`dist/` 已生成
|
||||
|
||||
## 未在本记录中执行的内容
|
||||
|
||||
- 未启动前端 dev server 做交互式页面冒烟
|
||||
- 因此没有需要额外清理的前端测试进程
|
||||
71
doc/2026-04-15-全量迁移892-without-redis后端实施记录.md
Normal file
71
doc/2026-04-15-全量迁移892-without-redis后端实施记录.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# 全量迁移 `892-without-redis` 后端实施记录
|
||||
|
||||
## 修改时间
|
||||
|
||||
- 2026-04-15
|
||||
|
||||
## 本次完成内容
|
||||
|
||||
- 新增并接入 `ruoyi-loan-pricing` 模块,纳入根 `pom.xml` 与 `ruoyi-admin/pom.xml`
|
||||
- 保留 `MyBatis-Plus + Lombok`,将贷款定价模块中的 `jakarta.*` 兼容替换为当前基线可运行的 `javax.*`
|
||||
- 在 `ruoyi-framework` 中接入 `MyBatis-Plus`:
|
||||
- `MybatisSqlSessionFactoryBean`
|
||||
- `MybatisPlusInterceptor`
|
||||
- MySQL 分页拦截器
|
||||
- 迁入贷款定价后端主链:
|
||||
- Controller / DTO / Entity / VO / Mapper / Service / XML
|
||||
- 敏感字段加解密与脱敏服务
|
||||
- 个人测算入参对齐
|
||||
- 列表联表查询测算利率
|
||||
- 详情页个人最终测算利率取值
|
||||
- 补充 `HttpUtils#doPostFormUrlEncoded`,满足模型表单调用
|
||||
- 新增 `PasswordTransferCryptoService`
|
||||
- 接入登录密码传输后端链路:
|
||||
- [SysLoginController](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java)
|
||||
- [SysRegisterController](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java)
|
||||
- [SysProfileController](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java)
|
||||
- [SysUserController](/Users/wkc/Desktop/loan-pricing/loan-pricing-jdk-1.8/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java)
|
||||
- 补齐密码传输配置:
|
||||
- `security.password-transfer.key`
|
||||
- 迁入目标分支中的部署脚本、环境配置和 SQL 资产:
|
||||
- `bin/prod/*`
|
||||
- `deploy/*`
|
||||
- `sql/loan_pricing_*.sql`
|
||||
- `sql/model_*.sql`
|
||||
- `test_api/*`
|
||||
|
||||
## 关键整合说明
|
||||
|
||||
- 没有回退当前分支的 `JDK8` 与“去 Redis 改为内存缓存”基线
|
||||
- 贷款定价模块没有改写为普通 MyBatis,而是保留 `MyBatis-Plus` 风格实现
|
||||
- 由于当前主工程是 `Spring Boot 2.5 / JDK8`,没有原样保留 `jakarta.*`,而是按你的确认改成 `javax.*`
|
||||
- 贷款定价模块中的 Swagger v3 注解未继续保留,避免为非业务注解引入额外运行时依赖
|
||||
|
||||
## 验证结果
|
||||
|
||||
### 构建验证
|
||||
|
||||
- `mvn -pl ruoyi-loan-pricing -am -DskipTests package`
|
||||
- 结果:通过
|
||||
- `mvn -pl ruoyi-admin -am -DskipTests package`
|
||||
- 结果:通过
|
||||
|
||||
### 定向测试
|
||||
|
||||
- `mvn -pl ruoyi-loan-pricing -am -Dtest=LoanPricingWorkflowMapperXmlTest,LoanPricingWorkflowServiceImplTest,LoanPricingModelServicePersonalParamsTest,SensitiveFieldCryptoServiceTest,LoanPricingSensitiveDisplayServiceTest,ModelRetailOutputFieldsTest -Dsurefire.failIfNoSpecifiedTests=false test`
|
||||
- 结果:通过
|
||||
- 统计:22 tests run, 0 failures, 0 errors
|
||||
|
||||
- `mvn -pl ruoyi-admin -am -Dtest=SysLoginControllerPasswordTransferTest,SysRegisterControllerPasswordTransferTest,SysProfileControllerPasswordTransferTest,SysUserControllerPasswordTransferTest,CacheControllerTest -Dsurefire.failIfNoSpecifiedTests=false test`
|
||||
- 结果:通过
|
||||
- 统计:7 tests run, 0 failures, 0 errors
|
||||
|
||||
### 全量后端测试
|
||||
|
||||
- `mvn test`
|
||||
- 结果:通过
|
||||
|
||||
## 未在本记录中执行的内容
|
||||
|
||||
- 未执行真实数据库初始化和真实模型接口联调
|
||||
- 未在本记录中启动长期运行的后端进程,因此无需额外清理测试进程
|
||||
63
pom.xml
63
pom.xml
@@ -34,8 +34,9 @@
|
||||
<tomcat.version>9.0.112</tomcat.version>
|
||||
<logback.version>1.2.13</logback.version>
|
||||
<spring-security.version>5.7.14</spring-security.version>
|
||||
<spring-framework.version>5.3.39</spring-framework.version>
|
||||
</properties>
|
||||
<spring-framework.version>5.3.39</spring-framework.version>
|
||||
<mybatis-plus.version>3.5.7</mybatis-plus.version>
|
||||
</properties>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
<dependencyManagement>
|
||||
@@ -114,12 +115,18 @@
|
||||
<version>${yauaa.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- pagehelper 分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
<version>${pagehelper.boot.version}</version>
|
||||
</dependency>
|
||||
<!-- pagehelper 分页插件 -->
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
||||
<version>${pagehelper.boot.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 获取系统信息 -->
|
||||
<dependency>
|
||||
@@ -204,17 +211,24 @@
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 系统模块-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<!-- 系统模块-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 利率定价模块-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-loan-pricing</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
<version>${ruoyi.version}</version>
|
||||
</dependency>
|
||||
|
||||
@@ -225,10 +239,11 @@
|
||||
<module>ruoyi-admin</module>
|
||||
<module>ruoyi-framework</module>
|
||||
<module>ruoyi-system</module>
|
||||
<module>ruoyi-quartz</module>
|
||||
<module>ruoyi-generator</module>
|
||||
<module>ruoyi-common</module>
|
||||
</modules>
|
||||
<module>ruoyi-quartz</module>
|
||||
<module>ruoyi-generator</module>
|
||||
<module>ruoyi-common</module>
|
||||
<module>ruoyi-loan-pricing</module>
|
||||
</modules>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<build>
|
||||
@@ -271,4 +286,4 @@
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -61,6 +61,12 @@
|
||||
<artifactId>ruoyi-generator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 利率定价模块-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-loan-pricing</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
||||
@@ -13,14 +13,15 @@ import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.entity.SysMenu;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginBody;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.core.text.Convert;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.framework.web.service.SysLoginService;
|
||||
import com.ruoyi.framework.web.service.SysPermissionService;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.core.text.Convert;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.SysLoginService;
|
||||
import com.ruoyi.framework.web.service.SysPermissionService;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
import com.ruoyi.system.service.ISysMenuService;
|
||||
|
||||
@@ -44,8 +45,11 @@ public class SysLoginController
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private PasswordTransferCryptoService passwordTransferCryptoService;
|
||||
|
||||
/**
|
||||
* 登录方法
|
||||
@@ -54,12 +58,13 @@ public class SysLoginController
|
||||
* @return 结果
|
||||
*/
|
||||
@PostMapping("/login")
|
||||
public AjaxResult login(@RequestBody LoginBody loginBody)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
// 生成令牌
|
||||
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
|
||||
loginBody.getUuid());
|
||||
public AjaxResult login(@RequestBody LoginBody loginBody)
|
||||
{
|
||||
AjaxResult ajax = AjaxResult.success();
|
||||
loginBody.setPassword(passwordTransferCryptoService.decrypt(loginBody.getPassword()));
|
||||
// 生成令牌
|
||||
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
|
||||
loginBody.getUuid());
|
||||
ajax.put(Constants.TOKEN, token);
|
||||
return ajax;
|
||||
}
|
||||
|
||||
@@ -18,13 +18,14 @@ import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.file.FileUploadUtils;
|
||||
import com.ruoyi.common.utils.file.FileUtils;
|
||||
import com.ruoyi.common.utils.file.MimeTypeUtils;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.file.FileUploadUtils;
|
||||
import com.ruoyi.common.utils.file.FileUtils;
|
||||
import com.ruoyi.common.utils.file.MimeTypeUtils;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
* 个人信息 业务处理
|
||||
@@ -38,8 +39,11 @@ public class SysProfileController extends BaseController
|
||||
@Autowired
|
||||
private ISysUserService userService;
|
||||
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
@Autowired
|
||||
private TokenService tokenService;
|
||||
|
||||
@Autowired
|
||||
private PasswordTransferCryptoService passwordTransferCryptoService;
|
||||
|
||||
/**
|
||||
* 个人信息
|
||||
@@ -90,13 +94,13 @@ public class SysProfileController extends BaseController
|
||||
*/
|
||||
@Log(title = "个人信息", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/updatePwd")
|
||||
public AjaxResult updatePwd(@RequestBody Map<String, String> params)
|
||||
{
|
||||
String oldPassword = params.get("oldPassword");
|
||||
String newPassword = params.get("newPassword");
|
||||
LoginUser loginUser = getLoginUser();
|
||||
Long userId = loginUser.getUserId();
|
||||
SysUser user = userService.selectUserById(userId);
|
||||
public AjaxResult updatePwd(@RequestBody Map<String, String> params)
|
||||
{
|
||||
String oldPassword = passwordTransferCryptoService.decrypt(params.get("oldPassword"));
|
||||
String newPassword = passwordTransferCryptoService.decrypt(params.get("newPassword"));
|
||||
LoginUser loginUser = getLoginUser();
|
||||
Long userId = loginUser.getUserId();
|
||||
SysUser user = userService.selectUserById(userId);
|
||||
String password = user.getPassword();
|
||||
if (!SecurityUtils.matchesPassword(oldPassword, password))
|
||||
{
|
||||
|
||||
@@ -4,12 +4,13 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.model.RegisterBody;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.framework.web.service.SysRegisterService;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.domain.model.RegisterBody;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.SysRegisterService;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
|
||||
/**
|
||||
* 注册验证
|
||||
@@ -22,17 +23,21 @@ public class SysRegisterController extends BaseController
|
||||
@Autowired
|
||||
private SysRegisterService registerService;
|
||||
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
@Autowired
|
||||
private ISysConfigService configService;
|
||||
|
||||
@Autowired
|
||||
private PasswordTransferCryptoService passwordTransferCryptoService;
|
||||
|
||||
@PostMapping("/register")
|
||||
public AjaxResult register(@RequestBody RegisterBody user)
|
||||
{
|
||||
if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
|
||||
{
|
||||
return error("当前系统没有开启注册功能!");
|
||||
}
|
||||
String msg = registerService.register(user);
|
||||
return StringUtils.isEmpty(msg) ? success() : error(msg);
|
||||
}
|
||||
}
|
||||
if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
|
||||
{
|
||||
return error("当前系统没有开启注册功能!");
|
||||
}
|
||||
user.setPassword(passwordTransferCryptoService.decrypt(user.getPassword()));
|
||||
String msg = registerService.register(user);
|
||||
return StringUtils.isEmpty(msg) ? success() : error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,12 +24,13 @@ import com.ruoyi.common.core.domain.entity.SysRole;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.system.service.ISysDeptService;
|
||||
import com.ruoyi.system.service.ISysPostService;
|
||||
import com.ruoyi.system.service.ISysRoleService;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.poi.ExcelUtil;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.system.service.ISysDeptService;
|
||||
import com.ruoyi.system.service.ISysPostService;
|
||||
import com.ruoyi.system.service.ISysRoleService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
/**
|
||||
@@ -50,8 +51,11 @@ public class SysUserController extends BaseController
|
||||
@Autowired
|
||||
private ISysDeptService deptService;
|
||||
|
||||
@Autowired
|
||||
private ISysPostService postService;
|
||||
@Autowired
|
||||
private ISysPostService postService;
|
||||
|
||||
@Autowired
|
||||
private PasswordTransferCryptoService passwordTransferCryptoService;
|
||||
|
||||
/**
|
||||
* 获取用户列表
|
||||
@@ -134,13 +138,14 @@ public class SysUserController extends BaseController
|
||||
{
|
||||
return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
|
||||
{
|
||||
return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
|
||||
}
|
||||
user.setCreateBy(getUsername());
|
||||
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
|
||||
return toAjax(userService.insertUser(user));
|
||||
else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
|
||||
{
|
||||
return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
|
||||
}
|
||||
user.setCreateBy(getUsername());
|
||||
user.setPassword(passwordTransferCryptoService.decrypt(user.getPassword()));
|
||||
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
|
||||
return toAjax(userService.insertUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,13 +197,14 @@ public class SysUserController extends BaseController
|
||||
@PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
|
||||
@Log(title = "用户管理", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/resetPwd")
|
||||
public AjaxResult resetPwd(@RequestBody SysUser user)
|
||||
{
|
||||
userService.checkUserAllowed(user);
|
||||
userService.checkUserDataScope(user.getUserId());
|
||||
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
|
||||
user.setUpdateBy(getUsername());
|
||||
return toAjax(userService.resetPwd(user));
|
||||
public AjaxResult resetPwd(@RequestBody SysUser user)
|
||||
{
|
||||
userService.checkUserAllowed(user);
|
||||
userService.checkUserDataScope(user.getUserId());
|
||||
user.setPassword(passwordTransferCryptoService.decrypt(user.getPassword()));
|
||||
user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
|
||||
user.setUpdateBy(getUsername());
|
||||
return toAjax(userService.resetPwd(user));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
86
ruoyi-admin/src/main/resources/application-pro.yml
Normal file
86
ruoyi-admin/src/main/resources/application-pro.yml
Normal file
@@ -0,0 +1,86 @@
|
||||
# 开发环境配置
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为63310
|
||||
port: 63310
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /
|
||||
tomcat:
|
||||
# tomcat的URI编码
|
||||
uri-encoding: UTF-8
|
||||
# 连接数满后的排队数,默认为100
|
||||
accept-count: 1000
|
||||
threads:
|
||||
# tomcat最大线程数,默认为200
|
||||
max: 800
|
||||
# Tomcat启动初始化的线程数,默认值10
|
||||
min-spare: 100
|
||||
|
||||
|
||||
# 数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
druid:
|
||||
# 主库数据源
|
||||
master:
|
||||
url: jdbc:mysql://64.127.23.7:3306/loan-pricing?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: lrdb
|
||||
password: Synx2024
|
||||
# 从库数据源
|
||||
slave:
|
||||
# 从数据源开关/默认关闭
|
||||
enabled: false
|
||||
url:
|
||||
username:
|
||||
password:
|
||||
# 初始连接数
|
||||
initialSize: 5
|
||||
# 最小连接池数量
|
||||
minIdle: 10
|
||||
# 最大连接池数量
|
||||
maxActive: 20
|
||||
# 配置获取连接等待超时的时间
|
||||
maxWait: 60000
|
||||
# 配置连接超时时间
|
||||
connectTimeout: 30000
|
||||
# 配置网络超时时间
|
||||
socketTimeout: 60000
|
||||
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
timeBetweenEvictionRunsMillis: 60000
|
||||
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||
minEvictableIdleTimeMillis: 300000
|
||||
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
||||
maxEvictableIdleTimeMillis: 900000
|
||||
# 配置检测连接是否有效
|
||||
validationQuery: SELECT 1 FROM DUAL
|
||||
testWhileIdle: true
|
||||
testOnBorrow: false
|
||||
testOnReturn: false
|
||||
webStatFilter:
|
||||
enabled: true
|
||||
statViewServlet:
|
||||
enabled: true
|
||||
# 设置白名单,不填则允许所有访问
|
||||
allow:
|
||||
url-pattern: /druid/*
|
||||
# 控制台管理用户名和密码
|
||||
login-username: ruoyi
|
||||
login-password: 123456
|
||||
filter:
|
||||
stat:
|
||||
enabled: true
|
||||
# 慢SQL记录
|
||||
log-slow-sql: true
|
||||
slow-sql-millis: 1000
|
||||
merge-sql: true
|
||||
wall:
|
||||
config:
|
||||
multi-statement-allow: true
|
||||
model:
|
||||
url: http://64.202.32.40:8083/api/service/interface/invokeService/syllcs
|
||||
|
||||
security:
|
||||
password-transfer:
|
||||
key: "1234567890abcdef"
|
||||
86
ruoyi-admin/src/main/resources/application-uat.yml
Normal file
86
ruoyi-admin/src/main/resources/application-uat.yml
Normal file
@@ -0,0 +1,86 @@
|
||||
# 开发环境配置
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为63310
|
||||
port: 63310
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /
|
||||
tomcat:
|
||||
# tomcat的URI编码
|
||||
uri-encoding: UTF-8
|
||||
# 连接数满后的排队数,默认为100
|
||||
accept-count: 1000
|
||||
threads:
|
||||
# tomcat最大线程数,默认为200
|
||||
max: 800
|
||||
# Tomcat启动初始化的线程数,默认值10
|
||||
min-spare: 100
|
||||
|
||||
|
||||
# 数据源配置
|
||||
spring:
|
||||
datasource:
|
||||
type: com.alibaba.druid.pool.DruidDataSource
|
||||
driverClassName: com.mysql.cj.jdbc.Driver
|
||||
druid:
|
||||
# 主库数据源
|
||||
master:
|
||||
url: jdbc:mysql://192.168.0.111:40628/loan-pricing?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||
username: root
|
||||
password: Kfcx@1234
|
||||
# 从库数据源
|
||||
slave:
|
||||
# 从数据源开关/默认关闭
|
||||
enabled: false
|
||||
url:
|
||||
username:
|
||||
password:
|
||||
# 初始连接数
|
||||
initialSize: 5
|
||||
# 最小连接池数量
|
||||
minIdle: 10
|
||||
# 最大连接池数量
|
||||
maxActive: 20
|
||||
# 配置获取连接等待超时的时间
|
||||
maxWait: 60000
|
||||
# 配置连接超时时间
|
||||
connectTimeout: 30000
|
||||
# 配置网络超时时间
|
||||
socketTimeout: 60000
|
||||
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
|
||||
timeBetweenEvictionRunsMillis: 60000
|
||||
# 配置一个连接在池中最小生存的时间,单位是毫秒
|
||||
minEvictableIdleTimeMillis: 300000
|
||||
# 配置一个连接在池中最大生存的时间,单位是毫秒
|
||||
maxEvictableIdleTimeMillis: 900000
|
||||
# 配置检测连接是否有效
|
||||
validationQuery: SELECT 1 FROM DUAL
|
||||
testWhileIdle: true
|
||||
testOnBorrow: false
|
||||
testOnReturn: false
|
||||
webStatFilter:
|
||||
enabled: true
|
||||
statViewServlet:
|
||||
enabled: true
|
||||
# 设置白名单,不填则允许所有访问
|
||||
allow:
|
||||
url-pattern: /druid/*
|
||||
# 控制台管理用户名和密码
|
||||
login-username: ruoyi
|
||||
login-password: 123456
|
||||
filter:
|
||||
stat:
|
||||
enabled: true
|
||||
# 慢SQL记录
|
||||
log-slow-sql: true
|
||||
slow-sql-millis: 1000
|
||||
merge-sql: true
|
||||
wall:
|
||||
config:
|
||||
multi-statement-allow: true
|
||||
model:
|
||||
url: http://localhost:63310/rate/pricing/mock/invokeModel
|
||||
|
||||
security:
|
||||
password-transfer:
|
||||
key: "1234567890abcdef"
|
||||
@@ -98,14 +98,18 @@ swagger:
|
||||
pathMapping: /dev-api
|
||||
|
||||
# 防盗链配置
|
||||
referer:
|
||||
# 防盗链开关
|
||||
enabled: false
|
||||
# 允许的域名列表
|
||||
allowed-domains: localhost,127.0.0.1,ruoyi.vip,www.ruoyi.vip
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
referer:
|
||||
# 防盗链开关
|
||||
enabled: false
|
||||
# 允许的域名列表
|
||||
allowed-domains: localhost,127.0.0.1,ruoyi.vip,www.ruoyi.vip
|
||||
|
||||
security:
|
||||
password-transfer:
|
||||
key: "1234567890abcdef"
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
# 排除链接(多个用逗号分隔)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.SysLoginService;
|
||||
|
||||
class SysLoginControllerPasswordTransferTest
|
||||
{
|
||||
@Test
|
||||
void shouldDecryptPasswordBeforeCallingLoginService() throws Exception
|
||||
{
|
||||
SysLoginService loginService = mock(SysLoginService.class);
|
||||
PasswordTransferCryptoService passwordTransferCryptoService = mock(PasswordTransferCryptoService.class);
|
||||
when(passwordTransferCryptoService.decrypt("cipher")).thenReturn("admin123");
|
||||
when(loginService.login("admin", "admin123", "1", "u")).thenReturn("token");
|
||||
|
||||
SysLoginController controller = new SysLoginController();
|
||||
ReflectionTestUtils.setField(controller, "loginService", loginService);
|
||||
ReflectionTestUtils.setField(controller, "passwordTransferCryptoService", passwordTransferCryptoService);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
||||
|
||||
mockMvc.perform(post("/login")
|
||||
.contentType("application/json")
|
||||
.content("{\"username\":\"admin\",\"password\":\"cipher\",\"code\":\"1\",\"uuid\":\"u\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(passwordTransferCryptoService).decrypt("cipher");
|
||||
verify(loginService).login("admin", "admin123", "1", "u");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.Collections;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.TokenService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
class SysProfileControllerPasswordTransferTest
|
||||
{
|
||||
@AfterEach
|
||||
void tearDown()
|
||||
{
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDecryptPasswordsBeforeCheckingOldPassword() throws Exception
|
||||
{
|
||||
ISysUserService userService = mock(ISysUserService.class);
|
||||
TokenService tokenService = mock(TokenService.class);
|
||||
PasswordTransferCryptoService passwordTransferCryptoService = mock(PasswordTransferCryptoService.class);
|
||||
when(passwordTransferCryptoService.decrypt("oldCipher")).thenReturn("oldPlain");
|
||||
when(passwordTransferCryptoService.decrypt("newCipher")).thenReturn("newPlain");
|
||||
when(userService.resetUserPwd(org.mockito.ArgumentMatchers.anyLong(), org.mockito.ArgumentMatchers.anyString()))
|
||||
.thenReturn(1);
|
||||
|
||||
SysUser storedUser = new SysUser();
|
||||
storedUser.setUserId(2L);
|
||||
storedUser.setPassword(SecurityUtils.encryptPassword("oldPlain"));
|
||||
when(userService.selectUserById(2L)).thenReturn(storedUser);
|
||||
|
||||
SysUser currentUser = new SysUser();
|
||||
currentUser.setUserId(2L);
|
||||
currentUser.setUserName("admin");
|
||||
LoginUser loginUser = new LoginUser(2L, 1L, currentUser, Collections.emptySet());
|
||||
SecurityContextHolder.getContext()
|
||||
.setAuthentication(new UsernamePasswordAuthenticationToken(loginUser, null, Collections.emptyList()));
|
||||
|
||||
SysProfileController controller = new SysProfileController();
|
||||
ReflectionTestUtils.setField(controller, "userService", userService);
|
||||
ReflectionTestUtils.setField(controller, "tokenService", tokenService);
|
||||
ReflectionTestUtils.setField(controller, "passwordTransferCryptoService", passwordTransferCryptoService);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
||||
|
||||
mockMvc.perform(put("/system/user/profile/updatePwd")
|
||||
.contentType("application/json")
|
||||
.content("{\"oldPassword\":\"oldCipher\",\"newPassword\":\"newCipher\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(passwordTransferCryptoService).decrypt("oldCipher");
|
||||
verify(passwordTransferCryptoService).decrypt("newCipher");
|
||||
verify(userService).resetUserPwd(org.mockito.ArgumentMatchers.eq(2L), org.mockito.ArgumentMatchers.anyString());
|
||||
verify(tokenService).setLoginUser(loginUser);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import com.ruoyi.common.core.domain.model.RegisterBody;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.framework.web.service.SysRegisterService;
|
||||
import com.ruoyi.system.service.ISysConfigService;
|
||||
|
||||
class SysRegisterControllerPasswordTransferTest
|
||||
{
|
||||
@Test
|
||||
void shouldDecryptPasswordBeforeCallingRegisterService() throws Exception
|
||||
{
|
||||
SysRegisterService registerService = mock(SysRegisterService.class);
|
||||
ISysConfigService configService = mock(ISysConfigService.class);
|
||||
PasswordTransferCryptoService passwordTransferCryptoService = mock(PasswordTransferCryptoService.class);
|
||||
when(configService.selectConfigByKey("sys.account.registerUser")).thenReturn("true");
|
||||
when(passwordTransferCryptoService.decrypt("cipher")).thenReturn("admin123");
|
||||
when(registerService.register(any(RegisterBody.class))).thenReturn("");
|
||||
|
||||
SysRegisterController controller = new SysRegisterController();
|
||||
ReflectionTestUtils.setField(controller, "registerService", registerService);
|
||||
ReflectionTestUtils.setField(controller, "configService", configService);
|
||||
ReflectionTestUtils.setField(controller, "passwordTransferCryptoService", passwordTransferCryptoService);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
||||
|
||||
mockMvc.perform(post("/register")
|
||||
.contentType("application/json")
|
||||
.content("{\"username\":\"u1\",\"password\":\"cipher\",\"code\":\"1\",\"uuid\":\"u\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(passwordTransferCryptoService).decrypt("cipher");
|
||||
ArgumentCaptor<RegisterBody> captor = ArgumentCaptor.forClass(RegisterBody.class);
|
||||
verify(registerService).register(captor.capture());
|
||||
assertEquals("admin123", captor.getValue().getPassword());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.ruoyi.web.controller.system;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.Collections;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||
import com.ruoyi.common.utils.SecurityUtils;
|
||||
import com.ruoyi.framework.web.service.PasswordTransferCryptoService;
|
||||
import com.ruoyi.system.service.ISysDeptService;
|
||||
import com.ruoyi.system.service.ISysPostService;
|
||||
import com.ruoyi.system.service.ISysRoleService;
|
||||
import com.ruoyi.system.service.ISysUserService;
|
||||
|
||||
class SysUserControllerPasswordTransferTest
|
||||
{
|
||||
@AfterEach
|
||||
void tearDown()
|
||||
{
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDecryptPasswordBeforeAddingUser() throws Exception
|
||||
{
|
||||
ISysUserService userService = mock(ISysUserService.class);
|
||||
ISysRoleService roleService = mock(ISysRoleService.class);
|
||||
ISysDeptService deptService = mock(ISysDeptService.class);
|
||||
ISysPostService postService = mock(ISysPostService.class);
|
||||
PasswordTransferCryptoService passwordTransferCryptoService = mock(PasswordTransferCryptoService.class);
|
||||
when(passwordTransferCryptoService.decrypt("cipher")).thenReturn("initPwd");
|
||||
when(userService.checkUserNameUnique(org.mockito.ArgumentMatchers.any(SysUser.class))).thenReturn(true);
|
||||
when(userService.insertUser(org.mockito.ArgumentMatchers.any(SysUser.class))).thenReturn(1);
|
||||
|
||||
setAuthentication();
|
||||
|
||||
SysUserController controller = new SysUserController();
|
||||
ReflectionTestUtils.setField(controller, "userService", userService);
|
||||
ReflectionTestUtils.setField(controller, "roleService", roleService);
|
||||
ReflectionTestUtils.setField(controller, "deptService", deptService);
|
||||
ReflectionTestUtils.setField(controller, "postService", postService);
|
||||
ReflectionTestUtils.setField(controller, "passwordTransferCryptoService", passwordTransferCryptoService);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
||||
|
||||
mockMvc.perform(post("/system/user")
|
||||
.contentType("application/json")
|
||||
.content("{\"userName\":\"u1\",\"nickName\":\"n1\",\"deptId\":1,\"password\":\"cipher\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(passwordTransferCryptoService).decrypt("cipher");
|
||||
ArgumentCaptor<SysUser> captor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userService).insertUser(captor.capture());
|
||||
assertTrue(SecurityUtils.matchesPassword("initPwd", captor.getValue().getPassword()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDecryptPasswordBeforeResettingUserPassword() throws Exception
|
||||
{
|
||||
ISysUserService userService = mock(ISysUserService.class);
|
||||
ISysRoleService roleService = mock(ISysRoleService.class);
|
||||
ISysDeptService deptService = mock(ISysDeptService.class);
|
||||
ISysPostService postService = mock(ISysPostService.class);
|
||||
PasswordTransferCryptoService passwordTransferCryptoService = mock(PasswordTransferCryptoService.class);
|
||||
when(passwordTransferCryptoService.decrypt("cipher")).thenReturn("resetPwd");
|
||||
when(userService.resetPwd(org.mockito.ArgumentMatchers.any(SysUser.class))).thenReturn(1);
|
||||
|
||||
setAuthentication();
|
||||
|
||||
SysUserController controller = new SysUserController();
|
||||
ReflectionTestUtils.setField(controller, "userService", userService);
|
||||
ReflectionTestUtils.setField(controller, "roleService", roleService);
|
||||
ReflectionTestUtils.setField(controller, "deptService", deptService);
|
||||
ReflectionTestUtils.setField(controller, "postService", postService);
|
||||
ReflectionTestUtils.setField(controller, "passwordTransferCryptoService", passwordTransferCryptoService);
|
||||
|
||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
|
||||
|
||||
mockMvc.perform(put("/system/user/resetPwd")
|
||||
.contentType("application/json")
|
||||
.content("{\"userId\":2,\"password\":\"cipher\"}"))
|
||||
.andExpect(status().isOk());
|
||||
|
||||
verify(passwordTransferCryptoService).decrypt("cipher");
|
||||
ArgumentCaptor<SysUser> captor = ArgumentCaptor.forClass(SysUser.class);
|
||||
verify(userService).resetPwd(captor.capture());
|
||||
assertTrue(SecurityUtils.matchesPassword("resetPwd", captor.getValue().getPassword()));
|
||||
}
|
||||
|
||||
private void setAuthentication()
|
||||
{
|
||||
SysUser currentUser = new SysUser();
|
||||
currentUser.setUserId(1L);
|
||||
currentUser.setUserName("admin");
|
||||
LoginUser loginUser = new LoginUser(1L, 1L, currentUser, Collections.emptySet());
|
||||
SecurityContextHolder.getContext()
|
||||
.setAuthentication(new UsernamePasswordAuthenticationToken(loginUser, null, Collections.emptyList()));
|
||||
}
|
||||
}
|
||||
@@ -10,18 +10,27 @@ import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import com.ruoyi.common.constant.Constants;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* 通用http发送方法
|
||||
@@ -282,12 +291,38 @@ public class HttpUtils
|
||||
}
|
||||
}
|
||||
|
||||
private static class TrustAnyHostnameVerifier implements HostnameVerifier
|
||||
{
|
||||
@Override
|
||||
public boolean verify(String hostname, SSLSession session)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static class TrustAnyHostnameVerifier implements HostnameVerifier
|
||||
{
|
||||
@Override
|
||||
public boolean verify(String hostname, SSLSession session)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T doPostFormUrlEncoded(String url, Map<String, String> params, HttpHeaders headers, Class<T> responseType)
|
||||
{
|
||||
MultiValueMap<String, String> formParams = new LinkedMultiValueMap<String, String>();
|
||||
if (params != null && !params.isEmpty())
|
||||
{
|
||||
formParams.setAll(params);
|
||||
}
|
||||
|
||||
HttpHeaders requestHeaders = headers == null ? new HttpHeaders() : headers;
|
||||
requestHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||
requestHeaders.setAcceptCharset(Collections.singletonList(StandardCharsets.UTF_8));
|
||||
|
||||
HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(formParams, requestHeaders);
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
try
|
||||
{
|
||||
ResponseEntity<T> response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, responseType);
|
||||
log.info("POST(form-urlencoded) 请求成功,URL:{},响应结果:{}", url, response.getBody());
|
||||
return response.getBody();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException("POST(form-urlencoded) 请求失败,URL:" + url + ",异常信息:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,11 +29,16 @@
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 阿里数据库连接池 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- 阿里数据库连接池 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 验证码 -->
|
||||
<dependency>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package com.ruoyi.framework.config;
|
||||
|
||||
import java.util.TimeZone;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
package com.ruoyi.framework.config;
|
||||
|
||||
import java.util.TimeZone;
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
@@ -23,8 +26,16 @@ public class ApplicationConfig
|
||||
* 时区配置
|
||||
*/
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
|
||||
{
|
||||
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
|
||||
}
|
||||
}
|
||||
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
|
||||
{
|
||||
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor()
|
||||
{
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
|
||||
return interceptor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
package com.ruoyi.framework.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import javax.sql.DataSource;
|
||||
import org.apache.ibatis.io.VFS;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
package com.ruoyi.framework.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import javax.sql.DataSource;
|
||||
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
|
||||
import org.apache.ibatis.io.VFS;
|
||||
import org.apache.ibatis.plugin.Interceptor;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
|
||||
/**
|
||||
* Mybatis支持*匹配扫描包
|
||||
@@ -32,8 +33,11 @@ import com.ruoyi.common.utils.StringUtils;
|
||||
@Configuration
|
||||
public class MyBatisConfig
|
||||
{
|
||||
@Autowired
|
||||
private Environment env;
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
@Autowired(required = false)
|
||||
private Interceptor[] interceptors;
|
||||
|
||||
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
|
||||
|
||||
@@ -122,11 +126,15 @@ public class MyBatisConfig
|
||||
typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
|
||||
VFS.addImplClass(SpringBootVFS.class);
|
||||
|
||||
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
|
||||
sessionFactory.setDataSource(dataSource);
|
||||
sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
|
||||
sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
|
||||
sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
|
||||
return sessionFactory.getObject();
|
||||
}
|
||||
}
|
||||
final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
|
||||
sessionFactory.setDataSource(dataSource);
|
||||
sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
|
||||
sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
|
||||
sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
|
||||
if (interceptors != null)
|
||||
{
|
||||
sessionFactory.setPlugins(interceptors);
|
||||
}
|
||||
return sessionFactory.getObject();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.ruoyi.framework.web.service;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
|
||||
@Service
|
||||
public class PasswordTransferCryptoService
|
||||
{
|
||||
@Value("${security.password-transfer.key}")
|
||||
private String key;
|
||||
|
||||
public String decrypt(String cipherText)
|
||||
{
|
||||
try
|
||||
{
|
||||
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES"));
|
||||
return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)), StandardCharsets.UTF_8);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ServiceException("密码解密失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
52
ruoyi-loan-pricing/pom.xml
Normal file
52
ruoyi-loan-pricing/pom.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>ruoyi</artifactId>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<version>3.9.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<artifactId>ruoyi-loan-pricing</artifactId>
|
||||
|
||||
<description>
|
||||
利率定价模块
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- 通用工具-->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-framework</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
<artifactId>ruoyi-system</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.36</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.ruoyi.loanpricing.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.annotation.Log;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.PageDomain;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.page.TableSupport;
|
||||
import com.ruoyi.common.enums.BusinessType;
|
||||
import com.ruoyi.loanpricing.domain.dto.CorporateLoanPricingCreateDTO;
|
||||
import com.ruoyi.loanpricing.domain.dto.PersonalLoanPricingCreateDTO;
|
||||
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
|
||||
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowListVO;
|
||||
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowVO;
|
||||
import com.ruoyi.loanpricing.service.ILoanPricingWorkflowService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 利率定价流程Controller
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-19
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/loanPricing/workflow")
|
||||
public class LoanPricingWorkflowController extends BaseController
|
||||
{
|
||||
@Autowired
|
||||
private ILoanPricingWorkflowService loanPricingWorkflowService;
|
||||
|
||||
/**
|
||||
* 发起个人客户利率定价流程
|
||||
*/
|
||||
@Log(title = "个人客户利率定价流程", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/create/personal")
|
||||
public AjaxResult createPersonal(@Validated @RequestBody PersonalLoanPricingCreateDTO dto) {
|
||||
LoanPricingWorkflow result = loanPricingWorkflowService.createPersonalLoanPricing(dto);
|
||||
return success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起企业客户利率定价流程
|
||||
*/
|
||||
@Log(title = "企业客户利率定价流程", businessType = BusinessType.INSERT)
|
||||
@PostMapping("/create/corporate")
|
||||
public AjaxResult createCorporate(@Validated @RequestBody CorporateLoanPricingCreateDTO dto)
|
||||
{
|
||||
LoanPricingWorkflow result = loanPricingWorkflowService.createCorporateLoanPricing(dto);
|
||||
return success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询利率定价流程列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(LoanPricingWorkflow loanPricingWorkflow)
|
||||
{
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
Page<LoanPricingWorkflowListVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||
IPage<LoanPricingWorkflowListVO> result = loanPricingWorkflowService.selectLoanPricingPage(page, loanPricingWorkflow);
|
||||
TableDataInfo rspData = new TableDataInfo();
|
||||
rspData.setCode(200);
|
||||
rspData.setMsg("查询成功");
|
||||
rspData.setRows(result.getRecords());
|
||||
rspData.setTotal(result.getTotal());
|
||||
return rspData;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询利率定价流程详情
|
||||
*/
|
||||
@GetMapping("/{serialNum}")
|
||||
public AjaxResult getInfo(@PathVariable("serialNum") String serialNum)
|
||||
{
|
||||
LoanPricingWorkflowVO workflow = loanPricingWorkflowService.selectLoanPricingBySerialNum(serialNum);
|
||||
if (workflow == null)
|
||||
{
|
||||
return error("记录不存在");
|
||||
}
|
||||
return success(workflow);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设定执行利率
|
||||
*/
|
||||
@Log(title = "利率定价流程", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/{serialNum}/executeRate")
|
||||
public AjaxResult setExecuteRate(@PathVariable("serialNum") String serialNum,
|
||||
@RequestBody Map<String, String> request) {
|
||||
String executeRate = request.get("executeRate");
|
||||
boolean success = loanPricingWorkflowService.setExecuteRate(serialNum, executeRate);
|
||||
return success ? success() : error("设定失败");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.ruoyi.loanpricing.controller;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.ruoyi.common.annotation.Anonymous;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.loanpricing.domain.dto.ModelInvokeDTO;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
|
||||
/**
|
||||
* @Author 吴凯程
|
||||
* @Date 2025/11/10
|
||||
**/
|
||||
@RestController
|
||||
@RequestMapping("/rate/pricing/mock")
|
||||
public class LoanRatePricingMockController extends BaseController {
|
||||
|
||||
@Anonymous
|
||||
@PostMapping("/invokeModel")
|
||||
public AjaxResult invokeModel( ModelInvokeDTO modelInvokeDTO) {
|
||||
ObjectNode jsonNodes;
|
||||
if (modelInvokeDTO.getCustType().equals("个人")) {
|
||||
jsonNodes = loadJsonFromResource("data/retail_output.json");
|
||||
} else {
|
||||
jsonNodes = loadJsonFromResource("data/corp_output.json");
|
||||
}
|
||||
|
||||
return new AjaxResult(10000, "success", jsonNodes);
|
||||
}
|
||||
|
||||
private ObjectNode loadJsonFromResource(String resourcePath){
|
||||
ClassPathResource classPathResource = new ClassPathResource(resourcePath);
|
||||
try (InputStream inputStream = classPathResource.getInputStream();){
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
return objectMapper.readValue(inputStream, ObjectNode.class);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.ruoyi.loanpricing.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
/**
|
||||
* 企业客户利率定价发起DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-19
|
||||
*/
|
||||
@Data
|
||||
public class CorporateLoanPricingCreateDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotBlank(message = "客户内码不能为空")
|
||||
private String custIsn;
|
||||
|
||||
private String custName;
|
||||
|
||||
private String idType;
|
||||
|
||||
private String idNum;
|
||||
|
||||
@NotBlank(message = "担保方式不能为空")
|
||||
@Pattern(regexp = "^(信用|保证|抵押|质押)$", message = "担保方式必须是:信用、保证、抵押、质押之一")
|
||||
private String guarType;
|
||||
|
||||
@NotBlank(message = "申请金额不能为空")
|
||||
private String applyAmt;
|
||||
|
||||
private String loanTerm;
|
||||
|
||||
private String isAgriGuar;
|
||||
|
||||
private String isGreenLoan;
|
||||
|
||||
private String isTechEnt;
|
||||
|
||||
private String isTradeConstruction;
|
||||
|
||||
private String collType;
|
||||
|
||||
private String collThirdParty;
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package com.ruoyi.loanpricing.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author 吴凯程
|
||||
* @Date 2025/12/23
|
||||
**/
|
||||
@Data
|
||||
public class ModelInvokeDTO {
|
||||
/**
|
||||
* 业务方流水号(必填)
|
||||
* 可使用时间戳,或自定义随机生成
|
||||
*/
|
||||
private String serialNum;
|
||||
|
||||
/**
|
||||
* 机构编码(必填)
|
||||
* 固定值:892000
|
||||
*/
|
||||
private String orgCode;
|
||||
|
||||
/**
|
||||
* 运行模式(必填)
|
||||
* 固定值:1:同步
|
||||
*/
|
||||
private String runType = "1";
|
||||
|
||||
/**
|
||||
* 客户内码(必填)
|
||||
*/
|
||||
private String custIsn;
|
||||
|
||||
/**
|
||||
* 客户类型(必填)
|
||||
* 可选值:个人/企业
|
||||
*/
|
||||
private String custType;
|
||||
|
||||
/**
|
||||
* 担保方式(必填)
|
||||
* 可选值:信用,保证,抵押,质押
|
||||
*/
|
||||
private String guarType;
|
||||
|
||||
/**
|
||||
* 中间业务_个人_快捷支付(非必填)
|
||||
* 可选值:true/false
|
||||
*/
|
||||
private String midPerQuickPay;
|
||||
|
||||
/**
|
||||
* 中间业务_个人_电费代扣(非必填)
|
||||
* 可选值:true/false
|
||||
*/
|
||||
private String midPerEleDdc;
|
||||
|
||||
/**
|
||||
* 中间业务_企业_电费代扣(非必填)
|
||||
* 可选值:true/false
|
||||
*/
|
||||
private String midEntEleDdc;
|
||||
|
||||
/**
|
||||
* 中间业务_企业_水费代扣(非必填)
|
||||
* 可选值:true/false
|
||||
*/
|
||||
private String midEntWaterDdc;
|
||||
|
||||
/**
|
||||
* 申请金额(必填)
|
||||
* 单位:元
|
||||
*/
|
||||
private String applyAmt;
|
||||
|
||||
/**
|
||||
* 贷款期限(必填)
|
||||
* 单位:年
|
||||
*/
|
||||
private String loanTerm;
|
||||
|
||||
/**
|
||||
* 净身企业(非必填)
|
||||
* 可选值:true/false
|
||||
*/
|
||||
private String isCleanEnt;
|
||||
|
||||
/**
|
||||
* 开立基本结算账户(非必填)
|
||||
* 可选值:true/false
|
||||
*/
|
||||
private String hasSettleAcct;
|
||||
|
||||
/**
|
||||
* 制造业企业(非必填)
|
||||
* 可选值:true/false
|
||||
*/
|
||||
private String isManufacturing;
|
||||
|
||||
/**
|
||||
* 省农担担保贷款(非必填)
|
||||
* 可选值:true/false
|
||||
*/
|
||||
private String isAgriGuar;
|
||||
|
||||
/**
|
||||
* 是否纳税信用等级A级(非必填)
|
||||
* 可选值:true/false
|
||||
*/
|
||||
private String isTaxA;
|
||||
|
||||
/**
|
||||
* 是否县级及以上农业龙头企业(非必填)
|
||||
* 可选值:true/false
|
||||
*/
|
||||
private String isAgriLeading;
|
||||
|
||||
private String isInclusiveFinance;
|
||||
|
||||
/**
|
||||
* 贷款用途(非必填)
|
||||
* 可选值:consumer/business
|
||||
*/
|
||||
private String loanPurpose;
|
||||
|
||||
/**
|
||||
* 是否有经营佐证(非必填)
|
||||
* 可选值:0/1
|
||||
*/
|
||||
private String bizProof;
|
||||
|
||||
/**
|
||||
* 循环功能(非必填)
|
||||
* 可选值:0/1
|
||||
*/
|
||||
private String loanLoop;
|
||||
|
||||
/**
|
||||
* 抵质押类型(非必填)
|
||||
* 可选值:一类/二类/三类
|
||||
*/
|
||||
private String collType;
|
||||
|
||||
/**
|
||||
* 抵质押物是否三方所有(非必填)
|
||||
* 可选值:0/1
|
||||
*/
|
||||
private String collThirdParty;
|
||||
|
||||
// /**
|
||||
// * 贷款利率(必填)
|
||||
// */
|
||||
// private String loanRate;
|
||||
|
||||
/**
|
||||
* 客户名称(非必填)
|
||||
*/
|
||||
private String custName;
|
||||
|
||||
/**
|
||||
* 证件类型(非必填)
|
||||
*/
|
||||
private String idType;
|
||||
|
||||
/**
|
||||
* 证件号码(非必填)
|
||||
*/
|
||||
private String idNum;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.ruoyi.loanpricing.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import java.io.Serializable;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
/**
|
||||
* 个人客户利率定价发起DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-19
|
||||
*/
|
||||
@Data
|
||||
public class PersonalLoanPricingCreateDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotBlank(message = "客户内码不能为空")
|
||||
private String custIsn;
|
||||
|
||||
private String custName;
|
||||
|
||||
private String idType;
|
||||
|
||||
private String idNum;
|
||||
|
||||
@NotBlank(message = "担保方式不能为空")
|
||||
@Pattern(regexp = "^(信用|保证|抵押|质押)$", message = "担保方式必须是:信用、保证、抵押、质押之一")
|
||||
private String guarType;
|
||||
|
||||
@NotBlank(message = "申请金额不能为空")
|
||||
private String applyAmt;
|
||||
|
||||
@NotBlank(message = "贷款用途不能为空")
|
||||
@Pattern(regexp = "^(consumer|business)$", message = "贷款用途必须是:consumer、business之一")
|
||||
private String loanPurpose;
|
||||
|
||||
@NotBlank(message = "借款期限不能为空")
|
||||
private String loanTerm;
|
||||
|
||||
private String bizProof;
|
||||
|
||||
private String loanLoop;
|
||||
|
||||
private String collType;
|
||||
|
||||
private String collThirdParty;
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package com.ruoyi.loanpricing.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 利率定价流程对象 loan_pricing_workflow
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-19
|
||||
*/
|
||||
@Data
|
||||
@TableName("loan_pricing_workflow")
|
||||
public class LoanPricingWorkflow implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/** 模型输出ID */
|
||||
private Long modelOutputId;
|
||||
|
||||
/** 业务方流水号 */
|
||||
private String serialNum;
|
||||
|
||||
/** 机构编码 */
|
||||
private String orgCode;
|
||||
|
||||
/** 运行模式: 1-同步 */
|
||||
private String runType;
|
||||
|
||||
/** 客户内码 */
|
||||
@NotBlank(message = "客户内码不能为空")
|
||||
private String custIsn;
|
||||
|
||||
/** 客户类型: 个人/企业 */
|
||||
@NotBlank(message = "客户类型不能为空")
|
||||
private String custType;
|
||||
|
||||
/** 担保方式: 信用/保证/抵押/质押 */
|
||||
@NotBlank(message = "担保方式不能为空")
|
||||
private String guarType;
|
||||
|
||||
/** 中间业务_个人_快捷支付: true/false */
|
||||
private String midPerQuickPay;
|
||||
|
||||
/** 中间业务_个人_电费代扣: true/false */
|
||||
private String midPerEleDdc;
|
||||
|
||||
/** 中间业务_企业_电费代扣: true/false */
|
||||
private String midEntEleDdc;
|
||||
|
||||
/** 中间业务_企业_水费代扣: true/false */
|
||||
private String midEntWaterDdc;
|
||||
|
||||
/** 申请金额(元) */
|
||||
@NotBlank(message = "申请金额不能为空")
|
||||
private String applyAmt;
|
||||
|
||||
/**
|
||||
* 贷款期限
|
||||
*/
|
||||
private String loanTerm;
|
||||
|
||||
/** 净身企业: true/false */
|
||||
private String isCleanEnt;
|
||||
|
||||
/** 开立基本结算账户: true/false */
|
||||
private String hasSettleAcct;
|
||||
|
||||
/** 制造业企业: true/false */
|
||||
private String isManufacturing;
|
||||
|
||||
/** 省农担担保贷款: true/false */
|
||||
private String isAgriGuar;
|
||||
|
||||
/**
|
||||
* 贸易和建筑业企业标识: true/false
|
||||
*/
|
||||
private String isTradeConstruction;
|
||||
|
||||
/**
|
||||
* 绿色贷款: true/false
|
||||
*/
|
||||
private String isGreenLoan;
|
||||
|
||||
/**
|
||||
* 科技型企业: true/false
|
||||
*/
|
||||
private String isTechEnt;
|
||||
|
||||
/** 是否纳税信用等级A级: true/false */
|
||||
private String isTaxA;
|
||||
|
||||
/** 是否县级及以上农业龙头企业: true/false */
|
||||
private String isAgriLeading;
|
||||
|
||||
/** 贷款用途: consumer-消费/business-经营 */
|
||||
private String loanPurpose;
|
||||
|
||||
/** 是否有经营佐证: true/false */
|
||||
private String bizProof;
|
||||
|
||||
/** 循环功能: true/false */
|
||||
private String loanLoop;
|
||||
|
||||
/** 抵质押类型: 一线/一类/二类 */
|
||||
private String collType;
|
||||
|
||||
/** 抵质押物是否三方所有: true/false */
|
||||
private String collThirdParty;
|
||||
|
||||
/** 贷款利率 */
|
||||
private String loanRate;
|
||||
|
||||
/**
|
||||
* 执行利率(%)
|
||||
*/
|
||||
private String executeRate;
|
||||
|
||||
/** 客户名称 */
|
||||
private String custName;
|
||||
|
||||
/**
|
||||
* 证件类型
|
||||
*/
|
||||
private String idType;
|
||||
|
||||
/** 证件号码 */
|
||||
private String idNum;
|
||||
|
||||
/** 是否普惠小微借款人: true/false */
|
||||
private String isInclusiveFinance;
|
||||
|
||||
/** 创建者 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
/** 更新者 */
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private String updateBy;
|
||||
|
||||
/** 更新时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@TableField(fill = FieldFill.INSERT_UPDATE)
|
||||
private Date updateTime;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.ruoyi.loanpricing.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 贷款定价模型输入参数对象
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-21
|
||||
*/
|
||||
@Data
|
||||
public class ModelCorpOutputFields {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
// 客户内码
|
||||
private String custIsn;
|
||||
// 客户类型
|
||||
private String custType;
|
||||
// 担保方式
|
||||
private String guarType;
|
||||
// 客户名称
|
||||
private String custName;
|
||||
// 证件类型
|
||||
private String idType;
|
||||
// 证件号码
|
||||
private String idNum;
|
||||
// 基准利率
|
||||
private String baseLoanRate;
|
||||
// 我行首贷客户
|
||||
private String isFirstLoan;
|
||||
// 用信天数
|
||||
private String faithDay;
|
||||
// BP_首贷
|
||||
private String bpFirstLoan;
|
||||
// BP_贷龄
|
||||
private String bpAgeLoan;
|
||||
// TOTAL_BP_忠诚度
|
||||
private String totalBpLoyalty;
|
||||
// 存款年日均
|
||||
private String balanceAvg;
|
||||
// 贷款年日均
|
||||
private String loanAvg;
|
||||
// 派生率
|
||||
private String derivationRate;
|
||||
// TOTAL_BP_贡献度
|
||||
private String totalBpContribution;
|
||||
// 中间业务_企业_企业互联
|
||||
private String midEntConnect;
|
||||
// 中间业务_企业_有效价值客户
|
||||
private String midEntEffect;
|
||||
// 中间业务_企业_国际业务
|
||||
private String midEntInter;
|
||||
// 中间业务_企业_承兑
|
||||
private String midEntAccept;
|
||||
// 中间业务_企业_贴现
|
||||
private String midEntDiscount;
|
||||
// 中间业务_企业_电费代扣
|
||||
private String midEntEleDdc;
|
||||
// 中间业务_企业_水费代扣
|
||||
private String midEntWaterDdc;
|
||||
// 中间业务_企业_税务代扣
|
||||
private String midEntTax;
|
||||
// BP_中间业务
|
||||
private String bpMid;
|
||||
// 代发工资户数
|
||||
private String payroll;
|
||||
// 存量贷款余额
|
||||
private String invLoanAmount;
|
||||
// BP_代发工资
|
||||
private String bpPayroll;
|
||||
// 净身企业
|
||||
private String isCleanEnt;
|
||||
// 开立基本结算账户
|
||||
private String hasSettleAcct;
|
||||
// 省农担担保贷款
|
||||
private String isAgriGuar;
|
||||
// 绿色贷款
|
||||
private String isGreenLoan;
|
||||
// 科技型企业
|
||||
private String isTechEnt;
|
||||
// BP_企业客户类别
|
||||
private String bpEntType;
|
||||
// TOTAL_BP_关联度
|
||||
private String totoalBpRelevance;
|
||||
// 贷款期限
|
||||
private String loanTerm;
|
||||
// BP_贷款期限
|
||||
private String bpLoanTerm;
|
||||
// 申请金额
|
||||
private String applyAmt;
|
||||
// BP_贷款额度
|
||||
private String bpLoanAmount;
|
||||
// 抵质押类型
|
||||
private String collType;
|
||||
// 抵质押物是否三方所有
|
||||
private String collThirdParty;
|
||||
// BP_抵押物
|
||||
private String bpCollateral;
|
||||
// 灰名单客户
|
||||
private String greyCust;
|
||||
// 本金逾期
|
||||
private String prinOverdue;
|
||||
// 利息逾期
|
||||
private String interestOverdue;
|
||||
// 信用卡逾期
|
||||
private String cardOverdue;
|
||||
// BP_灰名单与逾期
|
||||
private String bpGreyOverdue;
|
||||
// TOTAL_BP_风险度
|
||||
private String totoalBpRisk;
|
||||
// 浮动BP
|
||||
private String totalBp;
|
||||
// 测算利率
|
||||
private String calculateRate;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package com.ruoyi.loanpricing.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 贷款定价模型输入参数对象
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-21
|
||||
*/
|
||||
@Data
|
||||
public class ModelRetailOutputFields {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
// 客户内码
|
||||
private String custIsn;
|
||||
|
||||
// 客户类型
|
||||
private String custType;
|
||||
|
||||
// 担保方式
|
||||
private String guarType;
|
||||
|
||||
// 客户名称
|
||||
private String custName;
|
||||
|
||||
// 证件类型
|
||||
private String idType;
|
||||
|
||||
// 证件号码
|
||||
private String idNum;
|
||||
|
||||
// 基准利率
|
||||
private String baseLoanRate;
|
||||
|
||||
// 我行首贷客户
|
||||
private String isFirstLoan;
|
||||
|
||||
// 用信天数
|
||||
private String faithDay;
|
||||
|
||||
// 客户年龄
|
||||
private String custAge;
|
||||
|
||||
// BP_首贷
|
||||
private String bpFirstLoan;
|
||||
|
||||
// BP_贷龄
|
||||
private String bpAgeLoan;
|
||||
|
||||
// BP_年龄
|
||||
private String bpAge;
|
||||
|
||||
// TOTAL_BP_忠诚度
|
||||
private String totalBpLoyalty;
|
||||
|
||||
// 存款年日均
|
||||
private String balanceAvg;
|
||||
|
||||
// 贷款年日均
|
||||
private String loanAvg;
|
||||
|
||||
// 派生率
|
||||
private String derivationRate;
|
||||
|
||||
// TOTAL_BP_贡献度
|
||||
private String totalBpContribution;
|
||||
|
||||
// 中间业务_个人_信用卡
|
||||
private String midPerCard;
|
||||
|
||||
// 中间业务_个人_一码通
|
||||
private String midPerPass;
|
||||
|
||||
// 中间业务_个人_丰收互联
|
||||
private String midPerHarvest;
|
||||
|
||||
// 中间业务_个人_有效客户
|
||||
private String midPerEffect;
|
||||
|
||||
// 中间业务_个人_快捷支付
|
||||
private String midPerQuickPay;
|
||||
|
||||
// 中间业务_个人_电费代扣
|
||||
private String midPerEleDdc;
|
||||
|
||||
// 中间业务_个人_水费代扣
|
||||
private String midPerWaterDdc;
|
||||
|
||||
// 中间业务_个人_华数费代扣
|
||||
private String midPerHuashuDdc;
|
||||
|
||||
// 中间业务_个人_煤气费代扣
|
||||
private String MidPerGasDdc;
|
||||
|
||||
// 中间业务_个人_市民卡
|
||||
private String midPerCitizencard;
|
||||
|
||||
// 中间业务_个人_理财业务
|
||||
private String midPerFinMan;
|
||||
|
||||
// 中间业务_个人_etc
|
||||
private String midPerEtc;
|
||||
|
||||
// BP_中间业务
|
||||
private String bpMid;
|
||||
|
||||
// TOTAL_BP_关联度(注意原字段名拼写错误:totoalBpRelevance,已保留原拼写)
|
||||
private String totoalBpRelevance;
|
||||
|
||||
// 申请金额
|
||||
private String applyAmt;
|
||||
|
||||
// BP_贷款额度
|
||||
private String bpLoanAmount;
|
||||
|
||||
// 贷款用途
|
||||
private String loanPurpose;
|
||||
|
||||
// 是否有经营佐证
|
||||
private String bizProof;
|
||||
|
||||
// BP_贷款用途
|
||||
private String bpLoanUse;
|
||||
|
||||
// 循环功能
|
||||
private String loanLoop;
|
||||
|
||||
// BP_循环功能
|
||||
private String bpLoanLoop;
|
||||
|
||||
// 抵质押类型
|
||||
private String collType;
|
||||
|
||||
// 抵质押物是否三方所有
|
||||
private String collThirdParty;
|
||||
|
||||
// BP_抵押物
|
||||
private String bpCollateral;
|
||||
|
||||
// 灰名单客户
|
||||
private String greyCust;
|
||||
|
||||
// 本金逾期
|
||||
private String prinOverdue;
|
||||
|
||||
// 利息逾期
|
||||
private String interestOverdue;
|
||||
|
||||
// 信用卡逾期
|
||||
private String cardOverdue;
|
||||
|
||||
// BP_灰名单与逾期
|
||||
private String bpGreyOverdue;
|
||||
|
||||
// TOTAL_BP_风险度(注意原字段名拼写错误:totoalBpRisk,已保留原拼写)
|
||||
private String totoalBpRisk;
|
||||
|
||||
// 浮动BP
|
||||
private String totalBp;
|
||||
|
||||
// 测算利率
|
||||
private String calculateRate;
|
||||
|
||||
// 历史利率
|
||||
private String loanRateHistory;
|
||||
|
||||
// 产品最低利率下限
|
||||
private String minRateProduct;
|
||||
|
||||
// 平滑幅度
|
||||
private String smoothRange;
|
||||
|
||||
// 最终测算利率
|
||||
private String finalCalculateRate;
|
||||
|
||||
// 参考利率
|
||||
private String referenceRate;
|
||||
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.ruoyi.loanpricing.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class LoanPricingWorkflowListVO
|
||||
{
|
||||
private String serialNum;
|
||||
|
||||
private String custName;
|
||||
|
||||
private String custType;
|
||||
|
||||
private String guarType;
|
||||
|
||||
private String applyAmt;
|
||||
|
||||
private String calculateRate;
|
||||
|
||||
private String executeRate;
|
||||
|
||||
private Date createTime;
|
||||
|
||||
private String createBy;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ruoyi.loanpricing.domain.vo;
|
||||
|
||||
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
|
||||
import com.ruoyi.loanpricing.domain.entity.ModelCorpOutputFields;
|
||||
import com.ruoyi.loanpricing.domain.entity.ModelRetailOutputFields;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author: wkc
|
||||
* @CreateTime: 2026-01-21
|
||||
*/
|
||||
@Data
|
||||
public class LoanPricingWorkflowVO {
|
||||
|
||||
private LoanPricingWorkflow loanPricingWorkflow;
|
||||
|
||||
private ModelRetailOutputFields modelRetailOutputFields;
|
||||
|
||||
private ModelCorpOutputFields modelCorpOutputFields;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.ruoyi.loanpricing.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
|
||||
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowListVO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 利率定价流程Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-19
|
||||
*/
|
||||
public interface LoanPricingWorkflowMapper extends BaseMapper<LoanPricingWorkflow>
|
||||
{
|
||||
IPage<LoanPricingWorkflowListVO> selectWorkflowPageWithRates(Page<?> page,
|
||||
@Param("query") LoanPricingWorkflow query);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ruoyi.loanpricing.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.loanpricing.domain.entity.ModelCorpOutputFields;
|
||||
|
||||
/**
|
||||
* 对公贷款定价模型输出字段Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-21
|
||||
*/
|
||||
public interface ModelCorpOutputFieldsMapper extends BaseMapper<ModelCorpOutputFields>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.ruoyi.loanpricing.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.ruoyi.loanpricing.domain.entity.ModelRetailOutputFields;
|
||||
|
||||
/**
|
||||
* 零售贷款定价模型输出字段Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-21
|
||||
*/
|
||||
public interface ModelRetailOutputFieldsMapper extends BaseMapper<ModelRetailOutputFields>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.ruoyi.loanpricing.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.loanpricing.domain.dto.CorporateLoanPricingCreateDTO;
|
||||
import com.ruoyi.loanpricing.domain.dto.PersonalLoanPricingCreateDTO;
|
||||
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
|
||||
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowListVO;
|
||||
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 利率定价流程Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-19
|
||||
*/
|
||||
public interface ILoanPricingWorkflowService
|
||||
{
|
||||
/**
|
||||
* 发起个人客户利率定价流程
|
||||
*
|
||||
* @param dto 个人客户发起DTO
|
||||
* @return 结果
|
||||
*/
|
||||
public LoanPricingWorkflow createPersonalLoanPricing(PersonalLoanPricingCreateDTO dto);
|
||||
|
||||
/**
|
||||
* 发起企业客户利率定价流程
|
||||
*
|
||||
* @param dto 企业客户发起DTO
|
||||
* @return 结果
|
||||
*/
|
||||
public LoanPricingWorkflow createCorporateLoanPricing(CorporateLoanPricingCreateDTO dto);
|
||||
|
||||
/**
|
||||
* 查询利率定价流程列表
|
||||
*
|
||||
* @param loanPricingWorkflow 利率定价流程信息
|
||||
* @return 利率定价流程集合
|
||||
*/
|
||||
public List<LoanPricingWorkflow> selectLoanPricingList(LoanPricingWorkflow loanPricingWorkflow);
|
||||
|
||||
/**
|
||||
* 分页查询利率定价流程列表
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param loanPricingWorkflow 利率定价流程信息
|
||||
* @return 分页结果
|
||||
*/
|
||||
public IPage<LoanPricingWorkflowListVO> selectLoanPricingPage(Page<LoanPricingWorkflowListVO> page, LoanPricingWorkflow loanPricingWorkflow);
|
||||
|
||||
/**
|
||||
* 查询利率定价流程详情
|
||||
*
|
||||
* @param serialNum 业务方流水号
|
||||
* @return 利率定价流程
|
||||
*/
|
||||
public LoanPricingWorkflowVO selectLoanPricingBySerialNum(String serialNum);
|
||||
|
||||
/**
|
||||
* 设定执行利率
|
||||
*
|
||||
* @param serialNum 业务方流水号
|
||||
* @param executeRate 执行利率
|
||||
* @return 是否成功
|
||||
*/
|
||||
public boolean setExecuteRate(String serialNum, String executeRate);
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package com.ruoyi.loanpricing.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.common.utils.bean.BeanUtils;
|
||||
import com.ruoyi.loanpricing.domain.dto.ModelInvokeDTO;
|
||||
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
|
||||
import com.ruoyi.loanpricing.domain.entity.ModelCorpOutputFields;
|
||||
import com.ruoyi.loanpricing.domain.entity.ModelRetailOutputFields;
|
||||
import com.ruoyi.loanpricing.mapper.LoanPricingWorkflowMapper;
|
||||
import com.ruoyi.loanpricing.mapper.ModelCorpOutputFieldsMapper;
|
||||
import com.ruoyi.loanpricing.mapper.ModelRetailOutputFieldsMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @Author: wkc
|
||||
* @CreateTime: 2026-01-21
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
@EnableAsync
|
||||
public class LoanPricingModelService {
|
||||
|
||||
@Resource
|
||||
private ModelService modelService;
|
||||
|
||||
@Resource
|
||||
private LoanPricingWorkflowMapper loanPricingWorkflowMapper;
|
||||
|
||||
@Resource
|
||||
private ModelRetailOutputFieldsMapper modelRetailOutputFieldsMapper;
|
||||
|
||||
@Resource
|
||||
private ModelCorpOutputFieldsMapper modelCorpOutputFieldsMapper;
|
||||
|
||||
@Resource
|
||||
private SensitiveFieldCryptoService sensitiveFieldCryptoService;
|
||||
|
||||
public void invokeModelAsync(Long workflowId) {
|
||||
LoanPricingWorkflow loanPricingWorkflow = loanPricingWorkflowMapper.selectById(workflowId);
|
||||
if (Objects.isNull(loanPricingWorkflow)){
|
||||
log.error("未找到对应的流程信息,未调用模型服务");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
loanPricingWorkflow.setCustName(sensitiveFieldCryptoService.decrypt(loanPricingWorkflow.getCustName()));
|
||||
loanPricingWorkflow.setIdNum(sensitiveFieldCryptoService.decrypt(loanPricingWorkflow.getIdNum()));
|
||||
}
|
||||
catch (RuntimeException ex)
|
||||
{
|
||||
log.error("贷款定价模型调用前敏感字段解密失败", ex);
|
||||
throw ex;
|
||||
}
|
||||
ModelInvokeDTO modelInvokeDTO = new ModelInvokeDTO();
|
||||
BeanUtils.copyProperties(loanPricingWorkflow, modelInvokeDTO);
|
||||
if ("个人".equals(loanPricingWorkflow.getCustType()))
|
||||
{
|
||||
normalizePersonalModelInvokeDTO(modelInvokeDTO);
|
||||
}
|
||||
JSONObject response = modelService.invokeModel(modelInvokeDTO);
|
||||
if (loanPricingWorkflow.getCustType().equals("个人")){
|
||||
// 个人模型
|
||||
ModelRetailOutputFields modelRetailOutputFields = JSON.parseObject(response.toJSONString(), ModelRetailOutputFields.class);
|
||||
modelRetailOutputFieldsMapper.insert(modelRetailOutputFields);
|
||||
log.info("个人模型调用成功");
|
||||
LoanPricingWorkflow workflowToUpdate = new LoanPricingWorkflow();
|
||||
workflowToUpdate.setId(loanPricingWorkflow.getId());
|
||||
workflowToUpdate.setModelOutputId(modelRetailOutputFields.getId());
|
||||
loanPricingWorkflowMapper.updateById(workflowToUpdate);
|
||||
log.info("更新流程信息成功");
|
||||
}else if (loanPricingWorkflow.getCustType().equals("企业")){
|
||||
// 企业模型
|
||||
ModelCorpOutputFields modelCorpOutputFields = JSON.parseObject(response.toJSONString(), ModelCorpOutputFields.class);
|
||||
modelCorpOutputFieldsMapper.insert(modelCorpOutputFields);
|
||||
log.info("企业模型调用成功");
|
||||
LoanPricingWorkflow workflowToUpdate = new LoanPricingWorkflow();
|
||||
workflowToUpdate.setId(loanPricingWorkflow.getId());
|
||||
workflowToUpdate.setModelOutputId(modelCorpOutputFields.getId());
|
||||
loanPricingWorkflowMapper.updateById(workflowToUpdate);
|
||||
log.info("更新流程信息成功");
|
||||
}
|
||||
}
|
||||
|
||||
private void normalizePersonalModelInvokeDTO(ModelInvokeDTO modelInvokeDTO)
|
||||
{
|
||||
modelInvokeDTO.setBizProof(toZeroOne(modelInvokeDTO.getBizProof()));
|
||||
modelInvokeDTO.setLoanLoop(toZeroOne(modelInvokeDTO.getLoanLoop()));
|
||||
modelInvokeDTO.setCollThirdParty(toZeroOne(modelInvokeDTO.getCollThirdParty()));
|
||||
}
|
||||
|
||||
private String toZeroOne(String value)
|
||||
{
|
||||
if ("true".equals(value) || "1".equals(value))
|
||||
{
|
||||
return "1";
|
||||
}
|
||||
if ("false".equals(value) || "0".equals(value))
|
||||
{
|
||||
return "0";
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.ruoyi.loanpricing.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@Service
|
||||
public class LoanPricingSensitiveDisplayService
|
||||
{
|
||||
public String maskCustName(String custName)
|
||||
{
|
||||
if (!StringUtils.hasText(custName))
|
||||
{
|
||||
return custName;
|
||||
}
|
||||
if (custName.contains("公司") && custName.length() > 4)
|
||||
{
|
||||
return custName.substring(0, 2) + "*".repeat(custName.length() - 4) + custName.substring(custName.length() - 2);
|
||||
}
|
||||
if (custName.length() == 1)
|
||||
{
|
||||
return custName;
|
||||
}
|
||||
return custName.substring(0, 1) + "*".repeat(custName.length() - 1);
|
||||
}
|
||||
|
||||
public String maskIdNum(String idNum)
|
||||
{
|
||||
if (!StringUtils.hasText(idNum))
|
||||
{
|
||||
return idNum;
|
||||
}
|
||||
if (idNum.startsWith("91") && idNum.length() == 18)
|
||||
{
|
||||
return idNum.substring(0, 2) + "*".repeat(13) + idNum.substring(idNum.length() - 3);
|
||||
}
|
||||
if (idNum.matches("\\d{17}[\\dXx]"))
|
||||
{
|
||||
return idNum.substring(0, 4) + "*".repeat(8) + idNum.substring(idNum.length() - 4);
|
||||
}
|
||||
if (idNum.length() > 5)
|
||||
{
|
||||
return idNum.substring(0, 2) + "*".repeat(idNum.length() - 5) + idNum.substring(idNum.length() - 3);
|
||||
}
|
||||
return "*".repeat(idNum.length());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package com.ruoyi.loanpricing.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import com.ruoyi.common.core.domain.entity.SysDictData;
|
||||
import com.ruoyi.common.core.redis.RedisCache;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.http.HttpUtils;
|
||||
import com.ruoyi.loanpricing.domain.dto.ModelInvokeDTO;
|
||||
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @Author 吴凯程
|
||||
* @Date 2025/12/11
|
||||
**/
|
||||
@Service
|
||||
@Slf4j
|
||||
@EnableAsync
|
||||
public class ModelService {
|
||||
|
||||
@Value("${model.url}")
|
||||
private String modelUrl;
|
||||
|
||||
|
||||
|
||||
public JSONObject invokeModel(ModelInvokeDTO modelInvokeDTO) {
|
||||
Map<String, String> requestBody = entityToMap(modelInvokeDTO);
|
||||
JSONObject response = HttpUtils.doPostFormUrlEncoded(modelUrl, requestBody, null, JSONObject.class);
|
||||
log.info("------------------->调用模型返回结果:" + JSON.toJSONString(response));
|
||||
if(Objects.nonNull(response) && response.containsKey("code") && response.getInteger("code") == 10000){
|
||||
JSONObject mappingOutputFields = response.getJSONObject("data").getJSONObject("mappingOutputFields");
|
||||
// return JSON.parseObject(mappingOutputFields.toJSONString(), ModelOutputFields.class);
|
||||
return mappingOutputFields;
|
||||
}else{
|
||||
log.error("------------------->调用模型失败,失败原因为:" + response.getString("message"));
|
||||
throw new ServiceException("调用模型失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用FastJSON将实体类转换为Map<String, String>
|
||||
* @param obj 待转换的实体类对象
|
||||
* @return 转换后的Map
|
||||
*/
|
||||
public static Map<String, String> entityToMap(Object obj) {
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
// 先转为JSON字符串,再转换为指定类型的Map
|
||||
String jsonStr = JSON.toJSONString(obj);
|
||||
return JSON.parseObject(jsonStr, new TypeReference<Map<String, String>>() {});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.ruoyi.loanpricing.service;
|
||||
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
|
||||
@Service
|
||||
public class SensitiveFieldCryptoService
|
||||
{
|
||||
private final String key;
|
||||
|
||||
public SensitiveFieldCryptoService(@Value("${loan-pricing.sensitive.key:}") String key)
|
||||
{
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String encrypt(String plainText)
|
||||
{
|
||||
validateKey();
|
||||
if (!StringUtils.hasText(plainText))
|
||||
{
|
||||
return plainText;
|
||||
}
|
||||
try
|
||||
{
|
||||
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES"));
|
||||
return Base64.getEncoder().encodeToString(cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ServiceException("贷款定价敏感字段加密失败");
|
||||
}
|
||||
}
|
||||
|
||||
public String decrypt(String cipherText)
|
||||
{
|
||||
validateKey();
|
||||
if (!StringUtils.hasText(cipherText))
|
||||
{
|
||||
return cipherText;
|
||||
}
|
||||
try
|
||||
{
|
||||
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES"));
|
||||
return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)), StandardCharsets.UTF_8);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ServiceException("贷款定价敏感字段解密失败");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateKey()
|
||||
{
|
||||
if (!StringUtils.hasText(key))
|
||||
{
|
||||
throw new IllegalStateException("loan-pricing.sensitive.key 未配置");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
package com.ruoyi.loanpricing.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.loanpricing.domain.dto.CorporateLoanPricingCreateDTO;
|
||||
import com.ruoyi.loanpricing.domain.dto.PersonalLoanPricingCreateDTO;
|
||||
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
|
||||
import com.ruoyi.loanpricing.domain.entity.ModelCorpOutputFields;
|
||||
import com.ruoyi.loanpricing.domain.entity.ModelRetailOutputFields;
|
||||
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowListVO;
|
||||
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowVO;
|
||||
import com.ruoyi.loanpricing.mapper.LoanPricingWorkflowMapper;
|
||||
import com.ruoyi.loanpricing.mapper.ModelCorpOutputFieldsMapper;
|
||||
import com.ruoyi.loanpricing.mapper.ModelRetailOutputFieldsMapper;
|
||||
import com.ruoyi.loanpricing.service.ILoanPricingWorkflowService;
|
||||
import com.ruoyi.loanpricing.service.LoanPricingSensitiveDisplayService;
|
||||
import com.ruoyi.loanpricing.service.LoanPricingModelService;
|
||||
import com.ruoyi.loanpricing.service.SensitiveFieldCryptoService;
|
||||
import com.ruoyi.loanpricing.util.LoanPricingConverter;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 利率定价流程Service业务层处理
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-19
|
||||
*/
|
||||
@Service
|
||||
public class LoanPricingWorkflowServiceImpl implements ILoanPricingWorkflowService
|
||||
{
|
||||
@Resource
|
||||
private LoanPricingWorkflowMapper loanPricingWorkflowMapper;
|
||||
|
||||
@Resource
|
||||
private LoanPricingModelService loanPricingModelService;
|
||||
|
||||
@Resource
|
||||
private ModelRetailOutputFieldsMapper modelRetailOutputFieldsMapper;
|
||||
|
||||
@Resource
|
||||
private ModelCorpOutputFieldsMapper modelCorpOutputFieldsMapper;
|
||||
|
||||
@Resource
|
||||
private SensitiveFieldCryptoService sensitiveFieldCryptoService;
|
||||
|
||||
@Resource
|
||||
private LoanPricingSensitiveDisplayService loanPricingSensitiveDisplayService;
|
||||
|
||||
|
||||
/**
|
||||
* 发起利率定价流程
|
||||
*
|
||||
* @param loanPricingWorkflow 利率定价流程信息
|
||||
* @return 结果
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public LoanPricingWorkflow createLoanPricing(LoanPricingWorkflow loanPricingWorkflow)
|
||||
{
|
||||
// 自动生成业务方流水号(时间戳)
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
|
||||
String serialNum = sdf.format(new Date());
|
||||
loanPricingWorkflow.setSerialNum(serialNum);
|
||||
|
||||
// 设置默认值
|
||||
if (!StringUtils.hasText(loanPricingWorkflow.getOrgCode()))
|
||||
{
|
||||
loanPricingWorkflow.setOrgCode("892000");
|
||||
}
|
||||
if (!StringUtils.hasText(loanPricingWorkflow.getRunType()))
|
||||
{
|
||||
loanPricingWorkflow.setRunType("1");
|
||||
}
|
||||
|
||||
loanPricingWorkflow.setCustName(sensitiveFieldCryptoService.encrypt(loanPricingWorkflow.getCustName()));
|
||||
loanPricingWorkflow.setIdNum(sensitiveFieldCryptoService.encrypt(loanPricingWorkflow.getIdNum()));
|
||||
loanPricingWorkflowMapper.insert(loanPricingWorkflow);
|
||||
loanPricingModelService.invokeModelAsync(loanPricingWorkflow.getId());
|
||||
|
||||
return loanPricingWorkflow;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起个人客户利率定价流程
|
||||
*
|
||||
* @param dto 个人客户发起DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public LoanPricingWorkflow createPersonalLoanPricing(PersonalLoanPricingCreateDTO dto) {
|
||||
LoanPricingWorkflow entity = LoanPricingConverter.toEntity(dto);
|
||||
return createLoanPricing(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发起企业客户利率定价流程
|
||||
*
|
||||
* @param dto 企业客户发起DTO
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public LoanPricingWorkflow createCorporateLoanPricing(CorporateLoanPricingCreateDTO dto) {
|
||||
LoanPricingWorkflow entity = LoanPricingConverter.toEntity(dto);
|
||||
return createLoanPricing(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询利率定价流程列表
|
||||
*
|
||||
* @param loanPricingWorkflow 利率定价流程信息
|
||||
* @return 利率定价流程
|
||||
*/
|
||||
@Override
|
||||
public List<LoanPricingWorkflow> selectLoanPricingList(LoanPricingWorkflow loanPricingWorkflow)
|
||||
{
|
||||
LambdaQueryWrapper<LoanPricingWorkflow> wrapper = buildQueryWrapper(loanPricingWorkflow);
|
||||
// 按更新时间倒序
|
||||
wrapper.orderByDesc(LoanPricingWorkflow::getUpdateTime);
|
||||
return loanPricingWorkflowMapper.selectList(wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询利率定价流程列表
|
||||
*
|
||||
* @param page 分页参数
|
||||
* @param loanPricingWorkflow 利率定价流程信息
|
||||
* @return 利率定价流程
|
||||
*/
|
||||
@Override
|
||||
public IPage<LoanPricingWorkflowListVO> selectLoanPricingPage(Page<LoanPricingWorkflowListVO> page, LoanPricingWorkflow loanPricingWorkflow)
|
||||
{
|
||||
IPage<LoanPricingWorkflowListVO> pageResult = loanPricingWorkflowMapper.selectWorkflowPageWithRates(page, loanPricingWorkflow);
|
||||
pageResult.getRecords().forEach(row -> row.setCustName(
|
||||
loanPricingSensitiveDisplayService.maskCustName(
|
||||
sensitiveFieldCryptoService.decrypt(row.getCustName()))));
|
||||
return pageResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询利率定价流程详情
|
||||
*
|
||||
* @param serialNum 业务方流水号
|
||||
* @return 利率定价流程
|
||||
*/
|
||||
@Override
|
||||
public LoanPricingWorkflowVO selectLoanPricingBySerialNum(String serialNum)
|
||||
{
|
||||
LoanPricingWorkflowVO loanPricingWorkflowVO = new LoanPricingWorkflowVO();
|
||||
|
||||
LambdaQueryWrapper<LoanPricingWorkflow> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(LoanPricingWorkflow::getSerialNum, serialNum);
|
||||
LoanPricingWorkflow loanPricingWorkflow = loanPricingWorkflowMapper.selectOne(wrapper);
|
||||
String plainCustName = sensitiveFieldCryptoService.decrypt(loanPricingWorkflow.getCustName());
|
||||
String plainIdNum = sensitiveFieldCryptoService.decrypt(loanPricingWorkflow.getIdNum());
|
||||
loanPricingWorkflow.setCustName(loanPricingSensitiveDisplayService.maskCustName(plainCustName));
|
||||
loanPricingWorkflow.setIdNum(loanPricingSensitiveDisplayService.maskIdNum(plainIdNum));
|
||||
loanPricingWorkflowVO.setLoanPricingWorkflow(loanPricingWorkflow);
|
||||
|
||||
if (Objects.nonNull(loanPricingWorkflow.getModelOutputId())){
|
||||
if (loanPricingWorkflow.getCustType().equals("个人")){
|
||||
ModelRetailOutputFields modelRetailOutputFields = modelRetailOutputFieldsMapper.selectById(loanPricingWorkflow.getModelOutputId());
|
||||
if (Objects.nonNull(modelRetailOutputFields))
|
||||
{
|
||||
maskModelRetailOutputBasicInfo(modelRetailOutputFields);
|
||||
loanPricingWorkflow.setLoanRate(modelRetailOutputFields.getFinalCalculateRate());
|
||||
}
|
||||
loanPricingWorkflowVO.setModelRetailOutputFields(modelRetailOutputFields);
|
||||
}
|
||||
if (loanPricingWorkflow.getCustType().equals("企业")){
|
||||
ModelCorpOutputFields modelCorpOutputFields = modelCorpOutputFieldsMapper.selectById(loanPricingWorkflow.getModelOutputId());
|
||||
if (Objects.nonNull(modelCorpOutputFields))
|
||||
{
|
||||
maskModelCorpOutputBasicInfo(modelCorpOutputFields);
|
||||
loanPricingWorkflow.setLoanRate(modelCorpOutputFields.getCalculateRate());
|
||||
}
|
||||
loanPricingWorkflowVO.setModelCorpOutputFields(modelCorpOutputFields);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return loanPricingWorkflowVO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
*
|
||||
* @param loanPricingWorkflow 利率定价流程信息
|
||||
* @return LambdaQueryWrapper
|
||||
*/
|
||||
private LambdaQueryWrapper<LoanPricingWorkflow> buildQueryWrapper(LoanPricingWorkflow loanPricingWorkflow)
|
||||
{
|
||||
LambdaQueryWrapper<LoanPricingWorkflow> wrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
// 按创建者筛选
|
||||
if (StringUtils.hasText(loanPricingWorkflow.getCreateBy()))
|
||||
{
|
||||
wrapper.like(LoanPricingWorkflow::getCreateBy, loanPricingWorkflow.getCreateBy());
|
||||
}
|
||||
|
||||
// 按客户内码模糊查询
|
||||
if (StringUtils.hasText(loanPricingWorkflow.getCustIsn()))
|
||||
{
|
||||
wrapper.like(LoanPricingWorkflow::getCustIsn, loanPricingWorkflow.getCustIsn());
|
||||
}
|
||||
|
||||
// 按机构号筛选
|
||||
if (StringUtils.hasText(loanPricingWorkflow.getOrgCode()))
|
||||
{
|
||||
wrapper.like(LoanPricingWorkflow::getOrgCode, loanPricingWorkflow.getOrgCode());
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
private void maskModelRetailOutputBasicInfo(ModelRetailOutputFields modelRetailOutputFields)
|
||||
{
|
||||
modelRetailOutputFields.setCustName(
|
||||
loanPricingSensitiveDisplayService.maskCustName(modelRetailOutputFields.getCustName()));
|
||||
modelRetailOutputFields.setIdNum(
|
||||
loanPricingSensitiveDisplayService.maskIdNum(modelRetailOutputFields.getIdNum()));
|
||||
}
|
||||
|
||||
private void maskModelCorpOutputBasicInfo(ModelCorpOutputFields modelCorpOutputFields)
|
||||
{
|
||||
modelCorpOutputFields.setCustName(
|
||||
loanPricingSensitiveDisplayService.maskCustName(modelCorpOutputFields.getCustName()));
|
||||
modelCorpOutputFields.setIdNum(
|
||||
loanPricingSensitiveDisplayService.maskIdNum(modelCorpOutputFields.getIdNum()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设定执行利率
|
||||
*
|
||||
* @param serialNum 业务方流水号
|
||||
* @param executeRate 执行利率
|
||||
* @return 是否成功
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean setExecuteRate(String serialNum, String executeRate) {
|
||||
LambdaQueryWrapper<LoanPricingWorkflow> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(LoanPricingWorkflow::getSerialNum, serialNum);
|
||||
LoanPricingWorkflow workflow = loanPricingWorkflowMapper.selectOne(wrapper);
|
||||
|
||||
if (workflow == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
workflow.setExecuteRate(executeRate);
|
||||
int result = loanPricingWorkflowMapper.updateById(workflow);
|
||||
return result > 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.ruoyi.loanpricing.util;
|
||||
|
||||
import com.ruoyi.loanpricing.domain.dto.CorporateLoanPricingCreateDTO;
|
||||
import com.ruoyi.loanpricing.domain.dto.PersonalLoanPricingCreateDTO;
|
||||
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
|
||||
|
||||
/**
|
||||
* 利率定价转换器
|
||||
*
|
||||
* @author ruoyi
|
||||
* @date 2025-01-19
|
||||
*/
|
||||
public class LoanPricingConverter {
|
||||
|
||||
/**
|
||||
* 个人客户DTO转Entity
|
||||
*
|
||||
* @param dto 个人客户发起DTO
|
||||
* @return 利率定价流程实体
|
||||
*/
|
||||
public static LoanPricingWorkflow toEntity(PersonalLoanPricingCreateDTO dto) {
|
||||
LoanPricingWorkflow entity = new LoanPricingWorkflow();
|
||||
// 映射共同字段
|
||||
entity.setCustIsn(dto.getCustIsn());
|
||||
entity.setCustType("个人");
|
||||
entity.setCustName(dto.getCustName());
|
||||
entity.setIdType(dto.getIdType());
|
||||
entity.setIdNum(dto.getIdNum());
|
||||
entity.setGuarType(dto.getGuarType());
|
||||
entity.setApplyAmt(dto.getApplyAmt());
|
||||
entity.setLoanPurpose(dto.getLoanPurpose());
|
||||
entity.setLoanTerm(dto.getLoanTerm());
|
||||
entity.setCollType(dto.getCollType());
|
||||
entity.setCollThirdParty(dto.getCollThirdParty());
|
||||
// 映射个人特有字段
|
||||
entity.setBizProof(dto.getBizProof());
|
||||
entity.setLoanLoop(dto.getLoanLoop());
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 企业客户DTO转Entity
|
||||
*
|
||||
* @param dto 企业客户发起DTO
|
||||
* @return 利率定价流程实体
|
||||
*/
|
||||
public static LoanPricingWorkflow toEntity(CorporateLoanPricingCreateDTO dto) {
|
||||
LoanPricingWorkflow entity = new LoanPricingWorkflow();
|
||||
// 映射共同字段
|
||||
entity.setCustIsn(dto.getCustIsn());
|
||||
entity.setCustType("企业");
|
||||
entity.setCustName(dto.getCustName());
|
||||
entity.setIdType(dto.getIdType());
|
||||
entity.setIdNum(dto.getIdNum());
|
||||
entity.setGuarType(dto.getGuarType());
|
||||
entity.setApplyAmt(dto.getApplyAmt());
|
||||
entity.setCollType(dto.getCollType());
|
||||
entity.setCollThirdParty(dto.getCollThirdParty());
|
||||
// 映射企业特有字段
|
||||
entity.setIsAgriGuar(dto.getIsAgriGuar());
|
||||
entity.setIsGreenLoan(dto.getIsGreenLoan());
|
||||
entity.setIsTechEnt(dto.getIsTechEnt());
|
||||
entity.setIsTradeConstruction(dto.getIsTradeConstruction());
|
||||
entity.setLoanTerm(dto.getLoanTerm());
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
68
ruoyi-loan-pricing/src/main/resources/data/corp_output.json
Normal file
68
ruoyi-loan-pricing/src/main/resources/data/corp_output.json
Normal file
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"traceId": "350626558347246735E7F4722CUZRWOMNRR53O0",
|
||||
"cost": 2267,
|
||||
"tokenId": "17364055486305E7F4722M8IPFWNL8TOBEB",
|
||||
"mappingOutputFields": {
|
||||
"custIsn": "CUST20260121001",
|
||||
"custType": "企业客户",
|
||||
"guarType": "抵押担保",
|
||||
"custName": "北京智联科技有限公司",
|
||||
"idType": "营业执照",
|
||||
"idNum": "91110108MA00XXXXXX",
|
||||
"baseLoanRate": "3.45",
|
||||
"isFirstLoan": "N",
|
||||
"faithDay": "730",
|
||||
"bpFirstLoan": "0",
|
||||
"bpAgeLoan": "5.2",
|
||||
"totalBpLoyalty": "8.5",
|
||||
"balanceAvg": "5000000.00",
|
||||
"loanAvg": "3000000.00",
|
||||
"derivationRate": "1.8",
|
||||
"totalBpContribution": "12.3",
|
||||
"midEntConnect": "100000.00",
|
||||
"midEntEffect": "50000.00",
|
||||
"midEntInter": "80000.00",
|
||||
"midEntAccept": "200000.00",
|
||||
"midEntDiscount": "150000.00",
|
||||
"midEntEleDdc": "30000.00",
|
||||
"midEntWaterDdc": "10000.00",
|
||||
"midEntTax": "40000.00",
|
||||
"bpMid": "6.8",
|
||||
"payroll": "200",
|
||||
"invLoanAmount": "2500000.00",
|
||||
"bpPayroll": "4.1",
|
||||
"isCleanEnt": "Y",
|
||||
"hasSettleAcct": "Y",
|
||||
"isAgriGuar": "N",
|
||||
"isGreenLoan": "Y",
|
||||
"isTechEnt": "Y",
|
||||
"bpEntType": "7.5",
|
||||
"totoalBpRelevance": "9.2",
|
||||
"loanTerm": "36",
|
||||
"bpLoanTerm": "3.3",
|
||||
"applyAmt": "5000000.00",
|
||||
"bpLoanAmount": "5.8",
|
||||
"collType": "房产抵押",
|
||||
"collThirdParty": "N",
|
||||
"bpCollateral": "4.5",
|
||||
"greyCust": "N",
|
||||
"prinOverdue": "N",
|
||||
"interestOverdue": "N",
|
||||
"cardOverdue": "N",
|
||||
"bpGreyOverdue": "0",
|
||||
"totoalBpRisk": "1.2",
|
||||
"totalBp": "48.2",
|
||||
"calculateRate": "3.932"
|
||||
},
|
||||
"extensionMap": {},
|
||||
"reasonMessage": "Running successfully",
|
||||
"bizTime": 1736405548630,
|
||||
"outputFields": {},
|
||||
"workflowCode": "TBKH",
|
||||
"orgCode": "802000",
|
||||
"bizId": "2025010914345",
|
||||
"reasonCode": 200,
|
||||
"workflowVersion": 14,
|
||||
"callTime": 1736405548630,
|
||||
"status": 1
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"traceId": "350626558347246735E7F4722CUZRWOMNRR53O0",
|
||||
"cost": 2267,
|
||||
"tokenId": "17364055486305E7F4722M8IPFWNL8TOBEB",
|
||||
"mappingOutputFields": {
|
||||
"custIsn": "CUST20260121001",
|
||||
"custType": "个人",
|
||||
"guarType": "信用担保",
|
||||
"custName": "张三",
|
||||
"idType": "身份证",
|
||||
"idNum": "330106199001011234",
|
||||
"baseLoanRate": "4.35",
|
||||
"isFirstLoan": "是",
|
||||
"faithDay": "365",
|
||||
"custAge": "36",
|
||||
"bpFirstLoan": "50",
|
||||
"bpAgeLoan": "30",
|
||||
"bpAge": "20",
|
||||
"totalBpLoyalty": "95",
|
||||
"balanceAvg": "50000.00",
|
||||
"loanAvg": "100000.00",
|
||||
"derivationRate": "1.2",
|
||||
"totalBpContribution": "88",
|
||||
"midPerCard": "1000.50",
|
||||
"midPerPass": "500.00",
|
||||
"midPerHarvest": "800.20",
|
||||
"midPerEffect": "是",
|
||||
"midPerQuickPay": "300.00",
|
||||
"midPerEleDdc": "150.00",
|
||||
"midPerWaterDdc": "80.00",
|
||||
"midPerHuashuDdc": "120.00",
|
||||
"MidPerGasDdc": "90.00",
|
||||
"midPerCitizencard": "200.00",
|
||||
"midPerFinMan": "5000.00",
|
||||
"midPerEtc": "180.00",
|
||||
"bpMid": "45",
|
||||
"totoalBpRelevance": "90",
|
||||
"applyAmt": "200000.00",
|
||||
"bpLoanAmount": "60",
|
||||
"loanPurpose": "个人消费",
|
||||
"bizProof": "有",
|
||||
"bpLoanUse": "55",
|
||||
"loanLoop": "支持",
|
||||
"bpLoanLoop": "40",
|
||||
"collType": "无抵质押",
|
||||
"collThirdParty": "否",
|
||||
"bpCollateral": "0",
|
||||
"greyCust": "否",
|
||||
"prinOverdue": "否",
|
||||
"interestOverdue": "否",
|
||||
"cardOverdue": "否",
|
||||
"bpGreyOverdue": "98",
|
||||
"totoalBpRisk": "95",
|
||||
"totalBp": "350",
|
||||
"calculateRate": "6.15",
|
||||
"loanRateHistory": "6.40",
|
||||
"minRateProduct": "5.50",
|
||||
"smoothRange": "-0.10",
|
||||
"finalCalculateRate": "6.05",
|
||||
"referenceRate": "5.95"
|
||||
},
|
||||
"extensionMap": {},
|
||||
"reasonMessage": "Running successfully",
|
||||
"bizTime": 1736405548630,
|
||||
"outputFields": {},
|
||||
"workflowCode": "TBKH",
|
||||
"orgCode": "802000",
|
||||
"bizId": "2025010914345",
|
||||
"reasonCode": 200,
|
||||
"workflowVersion": 14,
|
||||
"callTime": 1736405548630,
|
||||
"status": 1
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.loanpricing.mapper.LoanPricingWorkflowMapper">
|
||||
|
||||
<select id="selectWorkflowPageWithRates" resultType="com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowListVO">
|
||||
SELECT
|
||||
lpw.serial_num AS serialNum,
|
||||
lpw.cust_name AS custName,
|
||||
lpw.cust_type AS custType,
|
||||
lpw.guar_type AS guarType,
|
||||
lpw.apply_amt AS applyAmt,
|
||||
CASE
|
||||
WHEN lpw.cust_type = '个人' THEN mr.final_calculate_rate
|
||||
WHEN lpw.cust_type = '企业' THEN mc.calculate_rate
|
||||
ELSE NULL
|
||||
END AS calculateRate,
|
||||
lpw.execute_rate AS executeRate,
|
||||
lpw.create_time AS createTime,
|
||||
lpw.create_by AS createBy
|
||||
FROM loan_pricing_workflow lpw
|
||||
LEFT JOIN model_retail_output_fields mr ON lpw.model_output_id = mr.id
|
||||
LEFT JOIN model_corp_output_fields mc ON lpw.model_output_id = mc.id
|
||||
<where>
|
||||
<if test="query != null and query.createBy != null and query.createBy != ''">
|
||||
AND lpw.create_by LIKE CONCAT('%', #{query.createBy}, '%')
|
||||
</if>
|
||||
<if test="query != null and query.custIsn != null and query.custIsn != ''">
|
||||
AND lpw.cust_isn LIKE CONCAT('%', #{query.custIsn}, '%')
|
||||
</if>
|
||||
<if test="query != null and query.orgCode != null and query.orgCode != ''">
|
||||
AND lpw.org_code LIKE CONCAT('%', #{query.orgCode}, '%')
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY lpw.update_time DESC
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.ruoyi.loanpricing.domain.entity;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class ModelRetailOutputFieldsTest
|
||||
{
|
||||
@Test
|
||||
void shouldContainLatestRetailDisplayRateFields()
|
||||
{
|
||||
Set<String> fieldNames = Arrays.stream(ModelRetailOutputFields.class.getDeclaredFields())
|
||||
.map(Field::getName)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
assertTrue(fieldNames.contains("loanRateHistory"), "缺少字段 loanRateHistory");
|
||||
assertTrue(fieldNames.contains("minRateProduct"), "缺少字段 minRateProduct");
|
||||
assertTrue(fieldNames.contains("smoothRange"), "缺少字段 smoothRange");
|
||||
assertTrue(fieldNames.contains("finalCalculateRate"), "缺少字段 finalCalculateRate");
|
||||
assertTrue(fieldNames.contains("referenceRate"), "缺少字段 referenceRate");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.ruoyi.loanpricing.domain.vo;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class LoanPricingWorkflowListVOTest
|
||||
{
|
||||
@Test
|
||||
void shouldExposeCalculateRateAndExecuteRateFields()
|
||||
{
|
||||
LoanPricingWorkflowListVO vo = new LoanPricingWorkflowListVO();
|
||||
vo.setCalculateRate("6.15");
|
||||
vo.setExecuteRate("5.80");
|
||||
|
||||
assertEquals("6.15", vo.getCalculateRate());
|
||||
assertEquals("5.80", vo.getExecuteRate());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.ruoyi.loanpricing.mapper;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
class LoanPricingWorkflowMapperXmlTest
|
||||
{
|
||||
@Test
|
||||
void shouldUseRetailFinalCalculateRateInWorkflowListQuery() throws IOException
|
||||
{
|
||||
ClassPathResource resource = new ClassPathResource("mapper/loanpricing/LoanPricingWorkflowMapper.xml");
|
||||
String xml = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
|
||||
|
||||
assertTrue(xml.contains("WHEN lpw.cust_type = '个人' THEN mr.final_calculate_rate"));
|
||||
assertTrue(xml.contains("WHEN lpw.cust_type = '企业' THEN mc.calculate_rate"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.ruoyi.loanpricing.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.loanpricing.domain.dto.ModelInvokeDTO;
|
||||
import com.ruoyi.loanpricing.domain.dto.PersonalLoanPricingCreateDTO;
|
||||
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
|
||||
import com.ruoyi.loanpricing.mapper.LoanPricingWorkflowMapper;
|
||||
import com.ruoyi.loanpricing.mapper.ModelCorpOutputFieldsMapper;
|
||||
import com.ruoyi.loanpricing.mapper.ModelRetailOutputFieldsMapper;
|
||||
import com.ruoyi.loanpricing.util.LoanPricingConverter;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class LoanPricingModelServicePersonalParamsTest {
|
||||
|
||||
@Mock
|
||||
private ModelService modelService;
|
||||
|
||||
@Mock
|
||||
private LoanPricingWorkflowMapper loanPricingWorkflowMapper;
|
||||
|
||||
@Mock
|
||||
private ModelRetailOutputFieldsMapper modelRetailOutputFieldsMapper;
|
||||
|
||||
@Mock
|
||||
private ModelCorpOutputFieldsMapper modelCorpOutputFieldsMapper;
|
||||
|
||||
@Mock
|
||||
private SensitiveFieldCryptoService sensitiveFieldCryptoService;
|
||||
|
||||
@InjectMocks
|
||||
private LoanPricingModelService loanPricingModelService;
|
||||
|
||||
@Test
|
||||
void shouldContainLoanPurposeAndLoanTermInPersonalCreateDto() throws NoSuchFieldException {
|
||||
assertNotNull(PersonalLoanPricingCreateDTO.class.getDeclaredField("loanPurpose"));
|
||||
assertNotNull(PersonalLoanPricingCreateDTO.class.getDeclaredField("loanTerm"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMapLoanPurposeAndLoanTermFromPersonalDto() {
|
||||
PersonalLoanPricingCreateDTO dto = new PersonalLoanPricingCreateDTO();
|
||||
dto.setCustIsn("CUST001");
|
||||
dto.setCustName("张三");
|
||||
dto.setGuarType("信用");
|
||||
dto.setApplyAmt("100000");
|
||||
dto.setLoanPurpose("business");
|
||||
dto.setLoanTerm("3");
|
||||
|
||||
LoanPricingWorkflow workflow = LoanPricingConverter.toEntity(dto);
|
||||
|
||||
assertEquals("business", workflow.getLoanPurpose());
|
||||
assertEquals("3", workflow.getLoanTerm());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldContainLoanTermAndLoanLoopInModelInvokeDto() throws NoSuchFieldException {
|
||||
assertNotNull(ModelInvokeDTO.class.getDeclaredField("loanTerm"));
|
||||
assertNotNull(ModelInvokeDTO.class.getDeclaredField("loanLoop"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldInvokePersonalModelWithExpectedParams() {
|
||||
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
||||
workflow.setId(1L);
|
||||
workflow.setSerialNum("202604090001");
|
||||
workflow.setOrgCode("892000");
|
||||
workflow.setRunType("1");
|
||||
workflow.setCustIsn("CUST001");
|
||||
workflow.setCustType("个人");
|
||||
workflow.setCustName("cipher-name");
|
||||
workflow.setIdType("身份证");
|
||||
workflow.setIdNum("cipher-id");
|
||||
workflow.setGuarType("信用");
|
||||
workflow.setApplyAmt("100000");
|
||||
workflow.setLoanPurpose("business");
|
||||
workflow.setLoanTerm("3");
|
||||
workflow.setBizProof("true");
|
||||
workflow.setLoanLoop("false");
|
||||
workflow.setCollThirdParty("true");
|
||||
workflow.setCollType("一类");
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("calculateRate", "6.15");
|
||||
|
||||
when(loanPricingWorkflowMapper.selectById(1L)).thenReturn(workflow);
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("张三");
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-id")).thenReturn("110101199001011234");
|
||||
when(modelService.invokeModel(any())).thenReturn(response);
|
||||
|
||||
loanPricingModelService.invokeModelAsync(1L);
|
||||
|
||||
verify(modelService).invokeModel(argThat((ModelInvokeDTO dto) ->
|
||||
Objects.equals("202604090001", dto.getSerialNum())
|
||||
&& Objects.equals("892000", dto.getOrgCode())
|
||||
&& Objects.equals("1", dto.getRunType())
|
||||
&& Objects.equals("CUST001", dto.getCustIsn())
|
||||
&& Objects.equals("个人", dto.getCustType())
|
||||
&& Objects.equals("张三", dto.getCustName())
|
||||
&& Objects.equals("身份证", dto.getIdType())
|
||||
&& Objects.equals("110101199001011234", dto.getIdNum())
|
||||
&& Objects.equals("信用", dto.getGuarType())
|
||||
&& Objects.equals("100000", dto.getApplyAmt())
|
||||
&& Objects.equals("business", dto.getLoanPurpose())
|
||||
&& Objects.equals("3", dto.getLoanTerm())
|
||||
&& Objects.equals("1", dto.getBizProof())
|
||||
&& Objects.equals("0", dto.getLoanLoop())
|
||||
&& Objects.equals("1", dto.getCollThirdParty())
|
||||
&& Objects.equals("一类", dto.getCollType())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.ruoyi.loanpricing.service;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.loanpricing.domain.dto.ModelInvokeDTO;
|
||||
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
|
||||
import com.ruoyi.loanpricing.mapper.LoanPricingWorkflowMapper;
|
||||
import com.ruoyi.loanpricing.mapper.ModelCorpOutputFieldsMapper;
|
||||
import com.ruoyi.loanpricing.mapper.ModelRetailOutputFieldsMapper;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class LoanPricingModelServiceTest
|
||||
{
|
||||
@Mock
|
||||
private ModelService modelService;
|
||||
|
||||
@Mock
|
||||
private LoanPricingWorkflowMapper loanPricingWorkflowMapper;
|
||||
|
||||
@Mock
|
||||
private ModelRetailOutputFieldsMapper modelRetailOutputFieldsMapper;
|
||||
|
||||
@Mock
|
||||
private ModelCorpOutputFieldsMapper modelCorpOutputFieldsMapper;
|
||||
|
||||
@Mock
|
||||
private SensitiveFieldCryptoService sensitiveFieldCryptoService;
|
||||
|
||||
@InjectMocks
|
||||
private LoanPricingModelService loanPricingModelService;
|
||||
|
||||
@Test
|
||||
void shouldDecryptCustNameAndIdNumBeforeInvokeModel()
|
||||
{
|
||||
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
||||
workflow.setId(1L);
|
||||
workflow.setCustType("个人");
|
||||
workflow.setCustName("cipher-name");
|
||||
workflow.setIdNum("cipher-id");
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("calculateRate", "6.15");
|
||||
|
||||
when(loanPricingWorkflowMapper.selectById(1L)).thenReturn(workflow);
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("张三");
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-id")).thenReturn("110101199001011234");
|
||||
when(modelService.invokeModel(any())).thenReturn(response);
|
||||
|
||||
loanPricingModelService.invokeModelAsync(1L);
|
||||
|
||||
verify(modelService).invokeModel(argThat((ModelInvokeDTO dto) ->
|
||||
Objects.equals("张三", dto.getCustName())
|
||||
&& Objects.equals("110101199001011234", dto.getIdNum())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotWritePlainCustNameAndIdNumBackWhenUpdatingWorkflow()
|
||||
{
|
||||
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
||||
workflow.setId(2L);
|
||||
workflow.setCustType("个人");
|
||||
workflow.setCustName("cipher-name");
|
||||
workflow.setIdNum("cipher-id");
|
||||
|
||||
JSONObject response = new JSONObject();
|
||||
response.put("calculateRate", "6.15");
|
||||
|
||||
when(loanPricingWorkflowMapper.selectById(2L)).thenReturn(workflow);
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("张三");
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-id")).thenReturn("110101199001011234");
|
||||
when(modelService.invokeModel(any())).thenReturn(response);
|
||||
|
||||
loanPricingModelService.invokeModelAsync(2L);
|
||||
|
||||
verify(loanPricingWorkflowMapper).updateById(argThat((LoanPricingWorkflow entity) ->
|
||||
!Objects.equals("张三", entity.getCustName())
|
||||
&& !Objects.equals("110101199001011234", entity.getIdNum())));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.ruoyi.loanpricing.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class LoanPricingSensitiveDisplayServiceTest
|
||||
{
|
||||
private final LoanPricingSensitiveDisplayService displayService = new LoanPricingSensitiveDisplayService();
|
||||
|
||||
@Test
|
||||
void shouldMaskPersonalNameAndIdNum()
|
||||
{
|
||||
assertEquals("张*", displayService.maskCustName("张三"));
|
||||
assertEquals("1101********1234", displayService.maskIdNum("110101199001011234"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMaskCorporateNameAndCreditCode()
|
||||
{
|
||||
assertEquals("测试****公司", displayService.maskCustName("测试科技有限公司"));
|
||||
assertEquals("91*************00X", displayService.maskIdNum("91110000100000000X"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.ruoyi.loanpricing.service;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class SensitiveFieldCryptoServiceTest
|
||||
{
|
||||
@Test
|
||||
void shouldEncryptAndDecryptCustNameAndIdNum()
|
||||
{
|
||||
SensitiveFieldCryptoService service = new SensitiveFieldCryptoService("1234567890abcdef");
|
||||
|
||||
String nameCipher = service.encrypt("张三");
|
||||
String idNumCipher = service.encrypt("110101199001011234");
|
||||
|
||||
assertNotEquals("张三", nameCipher);
|
||||
assertNotEquals("110101199001011234", idNumCipher);
|
||||
assertEquals("张三", service.decrypt(nameCipher));
|
||||
assertEquals("110101199001011234", service.decrypt(idNumCipher));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectBlankKeyConfiguration()
|
||||
{
|
||||
SensitiveFieldCryptoService service = new SensitiveFieldCryptoService("");
|
||||
|
||||
assertThrows(IllegalStateException.class, () -> service.encrypt("张三"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
package com.ruoyi.loanpricing.service.impl;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.argThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.loanpricing.domain.entity.LoanPricingWorkflow;
|
||||
import com.ruoyi.loanpricing.domain.entity.ModelCorpOutputFields;
|
||||
import com.ruoyi.loanpricing.domain.entity.ModelRetailOutputFields;
|
||||
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowListVO;
|
||||
import com.ruoyi.loanpricing.domain.vo.LoanPricingWorkflowVO;
|
||||
import com.ruoyi.loanpricing.mapper.LoanPricingWorkflowMapper;
|
||||
import com.ruoyi.loanpricing.mapper.ModelCorpOutputFieldsMapper;
|
||||
import com.ruoyi.loanpricing.mapper.ModelRetailOutputFieldsMapper;
|
||||
import com.ruoyi.loanpricing.service.LoanPricingSensitiveDisplayService;
|
||||
import com.ruoyi.loanpricing.service.LoanPricingModelService;
|
||||
import com.ruoyi.loanpricing.service.SensitiveFieldCryptoService;
|
||||
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class LoanPricingWorkflowServiceImplTest
|
||||
{
|
||||
@Mock
|
||||
private LoanPricingWorkflowMapper loanPricingWorkflowMapper;
|
||||
|
||||
@Mock
|
||||
private LoanPricingModelService loanPricingModelService;
|
||||
|
||||
@Mock
|
||||
private ModelRetailOutputFieldsMapper modelRetailOutputFieldsMapper;
|
||||
|
||||
@Mock
|
||||
private ModelCorpOutputFieldsMapper modelCorpOutputFieldsMapper;
|
||||
|
||||
@Mock
|
||||
private SensitiveFieldCryptoService sensitiveFieldCryptoService;
|
||||
|
||||
@Mock
|
||||
private LoanPricingSensitiveDisplayService loanPricingSensitiveDisplayService;
|
||||
|
||||
@InjectMocks
|
||||
private LoanPricingWorkflowServiceImpl loanPricingWorkflowService;
|
||||
|
||||
@Test
|
||||
void shouldEncryptCustNameAndIdNumBeforeInsert()
|
||||
{
|
||||
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
||||
workflow.setCustName("张三");
|
||||
workflow.setIdNum("110101199001011234");
|
||||
workflow.setCustIsn("CUST001");
|
||||
|
||||
when(sensitiveFieldCryptoService.encrypt("张三")).thenReturn("cipher-name");
|
||||
when(sensitiveFieldCryptoService.encrypt("110101199001011234")).thenReturn("cipher-id");
|
||||
|
||||
loanPricingWorkflowService.createLoanPricing(workflow);
|
||||
|
||||
verify(loanPricingWorkflowMapper).insert(argThat((LoanPricingWorkflow entity) ->
|
||||
Objects.equals("cipher-name", entity.getCustName())
|
||||
&& Objects.equals("cipher-id", entity.getIdNum())
|
||||
&& Objects.equals("CUST001", entity.getCustIsn())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReturnPagedWorkflowListWithCalculateRate()
|
||||
{
|
||||
LoanPricingWorkflowListVO row = new LoanPricingWorkflowListVO();
|
||||
row.setCalculateRate("6.15");
|
||||
|
||||
Page<LoanPricingWorkflowListVO> pageResult = new Page<>(1, 10);
|
||||
pageResult.setRecords(java.util.List.of(row));
|
||||
|
||||
when(loanPricingWorkflowMapper.selectWorkflowPageWithRates(any(), any())).thenReturn(pageResult);
|
||||
|
||||
IPage<LoanPricingWorkflowListVO> result = loanPricingWorkflowService.selectLoanPricingPage(new Page<>(1, 10), new LoanPricingWorkflow());
|
||||
|
||||
assertEquals("6.15", result.getRecords().get(0).getCalculateRate());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMaskCustNameWhenReturningPagedWorkflowList()
|
||||
{
|
||||
LoanPricingWorkflowListVO row = new LoanPricingWorkflowListVO();
|
||||
row.setCustName("cipher-name");
|
||||
|
||||
Page<LoanPricingWorkflowListVO> pageResult = new Page<>(1, 10);
|
||||
pageResult.setRecords(Collections.singletonList(row));
|
||||
|
||||
when(loanPricingWorkflowMapper.selectWorkflowPageWithRates(any(), any())).thenReturn(pageResult);
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("张三");
|
||||
when(loanPricingSensitiveDisplayService.maskCustName("张三")).thenReturn("张*");
|
||||
|
||||
IPage<LoanPricingWorkflowListVO> result = loanPricingWorkflowService.selectLoanPricingPage(new Page<>(1, 10), new LoanPricingWorkflow());
|
||||
|
||||
assertEquals("张*", result.getRecords().get(0).getCustName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUseCustIsnInsteadOfCustNameAsQueryCondition()
|
||||
{
|
||||
LoanPricingWorkflow query = new LoanPricingWorkflow();
|
||||
query.setCustIsn("CUST001");
|
||||
query.setCustName("张三");
|
||||
|
||||
when(loanPricingWorkflowMapper.selectList(any())).thenReturn(Collections.emptyList());
|
||||
|
||||
loanPricingWorkflowService.selectLoanPricingList(query);
|
||||
|
||||
ArgumentCaptor<LambdaQueryWrapper<LoanPricingWorkflow>> wrapperCaptor = ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
||||
verify(loanPricingWorkflowMapper).selectList(wrapperCaptor.capture());
|
||||
|
||||
LambdaQueryWrapper<LoanPricingWorkflow> wrapper = wrapperCaptor.getValue();
|
||||
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), LoanPricingWorkflow.class);
|
||||
String sqlSegment = wrapper.getSqlSegment();
|
||||
|
||||
assertTrue(sqlSegment.contains("cust_isn"), sqlSegment);
|
||||
assertTrue(!sqlSegment.contains("cust_name"), sqlSegment);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUseRetailModelOutputFinalCalculateRateForWorkflowDetail()
|
||||
{
|
||||
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
||||
workflow.setSerialNum("P20260328001");
|
||||
workflow.setCustType("个人");
|
||||
workflow.setModelOutputId(11L);
|
||||
workflow.setLoanRate("4.35");
|
||||
|
||||
ModelRetailOutputFields retailOutputFields = new ModelRetailOutputFields();
|
||||
retailOutputFields.setCalculateRate("6.15");
|
||||
retailOutputFields.setFinalCalculateRate("6.05");
|
||||
|
||||
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
|
||||
when(modelRetailOutputFieldsMapper.selectById(11L)).thenReturn(retailOutputFields);
|
||||
|
||||
LoanPricingWorkflowVO result = loanPricingWorkflowService.selectLoanPricingBySerialNum("P20260328001");
|
||||
|
||||
assertEquals("6.05", result.getLoanPricingWorkflow().getLoanRate());
|
||||
assertEquals("6.15", result.getModelRetailOutputFields().getCalculateRate());
|
||||
assertEquals("6.05", result.getModelRetailOutputFields().getFinalCalculateRate());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMaskCustNameAndIdNumWhenReturningWorkflowDetail()
|
||||
{
|
||||
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
||||
workflow.setSerialNum("P20260328001");
|
||||
workflow.setCustType("个人");
|
||||
workflow.setCustName("cipher-name");
|
||||
workflow.setIdNum("cipher-id");
|
||||
|
||||
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("张三");
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-id")).thenReturn("110101199001011234");
|
||||
when(loanPricingSensitiveDisplayService.maskCustName("张三")).thenReturn("张*");
|
||||
when(loanPricingSensitiveDisplayService.maskIdNum("110101199001011234")).thenReturn("1101********1234");
|
||||
|
||||
LoanPricingWorkflowVO result = loanPricingWorkflowService.selectLoanPricingBySerialNum("P20260328001");
|
||||
|
||||
assertEquals("张*", result.getLoanPricingWorkflow().getCustName());
|
||||
assertEquals("1101********1234", result.getLoanPricingWorkflow().getIdNum());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMaskCustNameAndIdNumInRetailModelOutputBasicInfo()
|
||||
{
|
||||
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
||||
workflow.setSerialNum("P20260328001");
|
||||
workflow.setCustType("个人");
|
||||
workflow.setCustName("cipher-name");
|
||||
workflow.setIdNum("cipher-id");
|
||||
workflow.setModelOutputId(11L);
|
||||
|
||||
ModelRetailOutputFields retailOutputFields = new ModelRetailOutputFields();
|
||||
retailOutputFields.setCustName("张三");
|
||||
retailOutputFields.setIdNum("110101199001011234");
|
||||
retailOutputFields.setCalculateRate("6.15");
|
||||
|
||||
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
|
||||
when(modelRetailOutputFieldsMapper.selectById(11L)).thenReturn(retailOutputFields);
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("张三");
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-id")).thenReturn("110101199001011234");
|
||||
when(loanPricingSensitiveDisplayService.maskCustName("张三")).thenReturn("张*");
|
||||
when(loanPricingSensitiveDisplayService.maskIdNum("110101199001011234")).thenReturn("1101********1234");
|
||||
|
||||
LoanPricingWorkflowVO result = loanPricingWorkflowService.selectLoanPricingBySerialNum("P20260328001");
|
||||
|
||||
assertEquals("张*", result.getModelRetailOutputFields().getCustName());
|
||||
assertEquals("1101********1234", result.getModelRetailOutputFields().getIdNum());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldUseCorporateModelOutputCalculateRateForWorkflowDetail()
|
||||
{
|
||||
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
||||
workflow.setSerialNum("C20260328001");
|
||||
workflow.setCustType("企业");
|
||||
workflow.setModelOutputId(22L);
|
||||
workflow.setLoanRate("3.80");
|
||||
|
||||
ModelCorpOutputFields corpOutputFields = new ModelCorpOutputFields();
|
||||
corpOutputFields.setCalculateRate("3.932");
|
||||
|
||||
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
|
||||
when(modelCorpOutputFieldsMapper.selectById(22L)).thenReturn(corpOutputFields);
|
||||
|
||||
LoanPricingWorkflowVO result = loanPricingWorkflowService.selectLoanPricingBySerialNum("C20260328001");
|
||||
|
||||
assertEquals("3.932", result.getLoanPricingWorkflow().getLoanRate());
|
||||
assertEquals("3.932", result.getModelCorpOutputFields().getCalculateRate());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldMaskCustNameAndIdNumInCorporateModelOutputBasicInfo()
|
||||
{
|
||||
LoanPricingWorkflow workflow = new LoanPricingWorkflow();
|
||||
workflow.setSerialNum("C20260328001");
|
||||
workflow.setCustType("企业");
|
||||
workflow.setCustName("cipher-name");
|
||||
workflow.setIdNum("cipher-id");
|
||||
workflow.setModelOutputId(22L);
|
||||
|
||||
ModelCorpOutputFields corpOutputFields = new ModelCorpOutputFields();
|
||||
corpOutputFields.setCustName("测试科技有限公司");
|
||||
corpOutputFields.setIdNum("91110000100000000X");
|
||||
corpOutputFields.setCalculateRate("3.932");
|
||||
|
||||
when(loanPricingWorkflowMapper.selectOne(any())).thenReturn(workflow);
|
||||
when(modelCorpOutputFieldsMapper.selectById(22L)).thenReturn(corpOutputFields);
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-name")).thenReturn("测试科技有限公司");
|
||||
when(sensitiveFieldCryptoService.decrypt("cipher-id")).thenReturn("91110000100000000X");
|
||||
when(loanPricingSensitiveDisplayService.maskCustName("测试科技有限公司")).thenReturn("测试****公司");
|
||||
when(loanPricingSensitiveDisplayService.maskIdNum("91110000100000000X")).thenReturn("91*************00X");
|
||||
|
||||
LoanPricingWorkflowVO result = loanPricingWorkflowService.selectLoanPricingBySerialNum("C20260328001");
|
||||
|
||||
assertEquals("测试****公司", result.getModelCorpOutputFields().getCustName());
|
||||
assertEquals("91*************00X", result.getModelCorpOutputFields().getIdNum());
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,9 @@ VUE_APP_TITLE = 若依管理系统
|
||||
# 开发环境配置
|
||||
ENV = 'development'
|
||||
|
||||
# 若依管理系统/开发环境
|
||||
VUE_APP_BASE_API = '/dev-api'
|
||||
|
||||
# 路由懒加载
|
||||
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||
# 若依管理系统/开发环境
|
||||
VUE_APP_BASE_API = '/dev-api'
|
||||
VUE_APP_PASSWORD_TRANSFER_KEY = '1234567890abcdef'
|
||||
|
||||
# 路由懒加载
|
||||
VUE_CLI_BABEL_TRANSPILE_MODULES = true
|
||||
|
||||
@@ -4,5 +4,6 @@ VUE_APP_TITLE = 若依管理系统
|
||||
# 生产环境配置
|
||||
ENV = 'production'
|
||||
|
||||
# 若依管理系统/生产环境
|
||||
VUE_APP_BASE_API = '/prod-api'
|
||||
# 若依管理系统/生产环境
|
||||
VUE_APP_BASE_API = '/prod-api'
|
||||
VUE_APP_PASSWORD_TRANSFER_KEY = '1234567890abcdef'
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
"axios": "0.30.3",
|
||||
"clipboard": "2.0.8",
|
||||
"core-js": "3.37.1",
|
||||
"crypto-js": "4.2.0",
|
||||
"echarts": "5.4.0",
|
||||
"element-ui": "2.15.14",
|
||||
"file-saver": "2.0.5",
|
||||
@@ -54,6 +55,7 @@
|
||||
"chalk": "4.1.0",
|
||||
"compression-webpack-plugin": "6.1.2",
|
||||
"connect": "3.6.6",
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"sass": "1.32.13",
|
||||
"sass-loader": "10.1.1",
|
||||
"script-ext-html-webpack-plugin": "2.1.5",
|
||||
|
||||
45
ruoyi-ui/src/api/loanPricing/workflow.js
Normal file
45
ruoyi-ui/src/api/loanPricing/workflow.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询利率定价流程列表
|
||||
export function listWorkflow(query) {
|
||||
return request({
|
||||
url: '/loanPricing/workflow/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询利率定价流程详情
|
||||
export function getWorkflow(serialNum) {
|
||||
return request({
|
||||
url: '/loanPricing/workflow/' + serialNum,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 创建个人客户利率定价流程
|
||||
export function createPersonalWorkflow(data) {
|
||||
return request({
|
||||
url: '/loanPricing/workflow/create/personal',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 创建企业客户利率定价流程
|
||||
export function createCorporateWorkflow(data) {
|
||||
return request({
|
||||
url: '/loanPricing/workflow/create/corporate',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 设定执行利率
|
||||
export function setExecuteRate(serialNum, executeRate) {
|
||||
return request({
|
||||
url: '/loanPricing/workflow/' + serialNum + '/executeRate',
|
||||
method: 'put',
|
||||
data: { executeRate: executeRate }
|
||||
})
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 登录方法
|
||||
export function login(username, password, code, uuid) {
|
||||
const data = {
|
||||
username,
|
||||
password,
|
||||
code,
|
||||
uuid
|
||||
}
|
||||
return request({
|
||||
import request from '@/utils/request'
|
||||
import { encryptPasswordFields } from '@/utils/passwordTransfer'
|
||||
|
||||
// 登录方法
|
||||
export function login(username, password, code, uuid) {
|
||||
const data = encryptPasswordFields({
|
||||
username,
|
||||
password,
|
||||
code,
|
||||
uuid
|
||||
}, ['password'], process.env.VUE_APP_PASSWORD_TRANSFER_KEY)
|
||||
return request({
|
||||
url: '/login',
|
||||
headers: {
|
||||
isToken: false,
|
||||
@@ -17,19 +18,20 @@ export function login(username, password, code, uuid) {
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 注册方法
|
||||
export function register(data) {
|
||||
return request({
|
||||
url: '/register',
|
||||
}
|
||||
|
||||
// 注册方法
|
||||
export function register(data) {
|
||||
const payload = encryptPasswordFields(data, ['password'], process.env.VUE_APP_PASSWORD_TRANSFER_KEY)
|
||||
return request({
|
||||
url: '/register',
|
||||
headers: {
|
||||
isToken: false
|
||||
},
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
},
|
||||
method: 'post',
|
||||
data: payload
|
||||
})
|
||||
}
|
||||
|
||||
// 获取用户详细信息
|
||||
export function getInfo() {
|
||||
@@ -66,4 +68,4 @@ export function getCodeImg() {
|
||||
method: 'get',
|
||||
timeout: 20000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import request from '@/utils/request'
|
||||
import { parseStrEmpty } from "@/utils/ruoyi"
|
||||
import request from '@/utils/request'
|
||||
import { parseStrEmpty } from "@/utils/ruoyi"
|
||||
import { encryptPasswordFields } from '@/utils/passwordTransfer'
|
||||
|
||||
// 查询用户列表
|
||||
export function listUser(query) {
|
||||
@@ -19,13 +20,14 @@ export function getUser(userId) {
|
||||
}
|
||||
|
||||
// 新增用户
|
||||
export function addUser(data) {
|
||||
return request({
|
||||
url: '/system/user',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
export function addUser(data) {
|
||||
const payload = encryptPasswordFields(data, ['password'], process.env.VUE_APP_PASSWORD_TRANSFER_KEY)
|
||||
return request({
|
||||
url: '/system/user',
|
||||
method: 'post',
|
||||
data: payload
|
||||
})
|
||||
}
|
||||
|
||||
// 修改用户
|
||||
export function updateUser(data) {
|
||||
@@ -45,12 +47,12 @@ export function delUser(userId) {
|
||||
}
|
||||
|
||||
// 用户密码重置
|
||||
export function resetUserPwd(userId, password) {
|
||||
const data = {
|
||||
userId,
|
||||
password
|
||||
}
|
||||
return request({
|
||||
export function resetUserPwd(userId, password) {
|
||||
const data = encryptPasswordFields({
|
||||
userId,
|
||||
password
|
||||
}, ['password'], process.env.VUE_APP_PASSWORD_TRANSFER_KEY)
|
||||
return request({
|
||||
url: '/system/user/resetPwd',
|
||||
method: 'put',
|
||||
data: data
|
||||
@@ -88,12 +90,12 @@ export function updateUserProfile(data) {
|
||||
}
|
||||
|
||||
// 用户密码重置
|
||||
export function updateUserPwd(oldPassword, newPassword) {
|
||||
const data = {
|
||||
oldPassword,
|
||||
newPassword
|
||||
}
|
||||
return request({
|
||||
export function updateUserPwd(oldPassword, newPassword) {
|
||||
const data = encryptPasswordFields({
|
||||
oldPassword,
|
||||
newPassword
|
||||
}, ['oldPassword', 'newPassword'], process.env.VUE_APP_PASSWORD_TRANSFER_KEY)
|
||||
return request({
|
||||
url: '/system/user/profile/updatePwd',
|
||||
method: 'put',
|
||||
data: data
|
||||
|
||||
14
ruoyi-ui/src/utils/passwordTransfer.js
Normal file
14
ruoyi-ui/src/utils/passwordTransfer.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import CryptoJS from 'crypto-js'
|
||||
|
||||
export function encryptPasswordFields(payload, fields, key) {
|
||||
const next = { ...payload }
|
||||
fields.forEach((field) => {
|
||||
if (next[field]) {
|
||||
next[field] = CryptoJS.AES.encrypt(next[field], CryptoJS.enc.Utf8.parse(key), {
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
}).toString()
|
||||
}
|
||||
})
|
||||
return next
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<el-card class="bargaining-pool-card">
|
||||
<div slot="header" class="card-header">
|
||||
<span class="card-title">议价池</span>
|
||||
</div>
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="网点议价池">
|
||||
{{ displayBranchPool }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="支行议价池">
|
||||
{{ displaySubBranchPool }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="私域池">
|
||||
{{ displayPrivateDomainPool }}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="超利分成">
|
||||
{{ displayExcessProfitShare }}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "BargainingPoolDisplay",
|
||||
props: {
|
||||
branchPool: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
subBranchPool: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
privateDomainPool: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
excessProfitShare: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
displayBranchPool() {
|
||||
const value = this.branchPool
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '0'
|
||||
}
|
||||
return value
|
||||
},
|
||||
displaySubBranchPool() {
|
||||
const value = this.subBranchPool
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '0'
|
||||
}
|
||||
return value
|
||||
},
|
||||
displayPrivateDomainPool() {
|
||||
const value = this.privateDomainPool
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '0'
|
||||
}
|
||||
return value
|
||||
},
|
||||
displayExcessProfitShare() {
|
||||
const value = this.excessProfitShare
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '0'
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.bargaining-pool-card {
|
||||
::v-deep .el-card__header {
|
||||
padding: 16px 20px;
|
||||
background-color: #fafafa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-card__body {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,303 @@
|
||||
<template>
|
||||
<el-dialog title="新增企业利率定价流程" :visible.sync="dialogVisible" width="900px" append-to-body
|
||||
@close="handleClose">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="140px" class="workflow-create-form">
|
||||
<!-- 基本信息 -->
|
||||
<el-divider content-position="left">基本信息</el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="客户内码" prop="custIsn">
|
||||
<el-input v-model="form.custIsn" placeholder="请输入客户内码"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="客户名称" prop="custName">
|
||||
<el-input v-model="form.custName" placeholder="请输入客户名称"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="证件类型" prop="idType">
|
||||
<el-select v-model="form.idType" placeholder="请选择证件类型" style="width: 100%">
|
||||
<el-option label="统一社会信用代码" value="统一社会信用代码"/>
|
||||
<el-option label="其他" value="其他"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="证件号码" prop="idNum">
|
||||
<el-input v-model="form.idNum" placeholder="请输入证件号码"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 贷款信息 -->
|
||||
<el-divider content-position="left">贷款信息</el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="担保方式" prop="guarType">
|
||||
<el-select v-model="form.guarType" placeholder="请选择担保方式" style="width: 100%">
|
||||
<el-option label="信用" value="信用"/>
|
||||
<el-option label="保证" value="保证"/>
|
||||
<el-option label="抵押" value="抵押"/>
|
||||
<el-option label="质押" value="质押"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="申请金额(元)" prop="applyAmt">
|
||||
<el-input v-model="form.applyAmt" placeholder="请输入申请金额"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="贷款期限(月)" prop="loanTerm">
|
||||
<el-input v-model.number="form.loanTerm" type="number" placeholder="请输入贷款期限"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 企业标识 -->
|
||||
<el-divider content-position="left">企业标识</el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="省农担担保贷款" prop="isAgriGuar">
|
||||
<el-switch v-model="form.isAgriGuar"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="绿色贷款" prop="isGreenLoan">
|
||||
<el-switch v-model="form.isGreenLoan"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="科技型企业" prop="isTechEnt">
|
||||
<el-switch v-model="form.isTechEnt"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="贸易和建筑业企业" prop="isTradeConstruction">
|
||||
<el-switch v-model="form.isTradeConstruction"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 抵质押信息 -->
|
||||
<el-divider content-position="left">抵质押信息</el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="抵质押类型" prop="collType">
|
||||
<el-select v-model="form.collType" placeholder="请选择抵质押类型" style="width: 100%">
|
||||
<el-option label="一线" value="一线"/>
|
||||
<el-option label="一类" value="一类"/>
|
||||
<el-option label="二类" value="二类"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="抵质押物三方所有" prop="collThirdParty">
|
||||
<el-switch v-model="form.collThirdParty"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" :loading="submitting" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {createCorporateWorkflow} from "@/api/loanPricing/workflow"
|
||||
|
||||
export default {
|
||||
name: "CorporateCreateDialog",
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
// 金额验证
|
||||
const validateApplyAmt = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error('请输入申请金额'))
|
||||
} else {
|
||||
const num = parseFloat(value)
|
||||
if (isNaN(num) || num <= 0) {
|
||||
callback(new Error('请输入有效的金额'))
|
||||
} else if (num > 999999999.99) {
|
||||
callback(new Error('金额不能超过 999999999.99'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 贷款期限验证
|
||||
const validateLoanTerm = (rule, value, callback) => {
|
||||
if (!value && value !== 0) {
|
||||
callback(new Error('请输入贷款期限'))
|
||||
} else {
|
||||
const num = parseInt(value)
|
||||
if (isNaN(num) || num <= 0) {
|
||||
callback(new Error('请输入有效的贷款期限'))
|
||||
} else if (num > 360) {
|
||||
callback(new Error('贷款期限不能超过 360 个月'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
submitting: false,
|
||||
form: {
|
||||
orgCode: '892000',
|
||||
runType: '1',
|
||||
custIsn: undefined,
|
||||
custName: undefined,
|
||||
idType: undefined,
|
||||
idNum: undefined,
|
||||
guarType: undefined,
|
||||
applyAmt: undefined,
|
||||
loanTerm: undefined,
|
||||
isAgriGuar: false,
|
||||
isGreenLoan: false,
|
||||
isTechEnt: false,
|
||||
isTradeConstruction: false,
|
||||
collType: undefined,
|
||||
collThirdParty: false
|
||||
},
|
||||
rules: {
|
||||
custIsn: [
|
||||
{required: true, message: "客户内码不能为空", trigger: "blur"},
|
||||
{min: 1, max: 50, message: "长度在 1 到 50 个字符", trigger: "blur"}
|
||||
],
|
||||
custName: [
|
||||
{required: true, message: "客户名称不能为空", trigger: "blur"},
|
||||
{min: 1, max: 100, message: "长度在 1 到 100 个字符", trigger: "blur"}
|
||||
],
|
||||
idType: [
|
||||
{required: true, message: "请选择证件类型", trigger: "change"}
|
||||
],
|
||||
idNum: [
|
||||
{required: true, message: "证件号码不能为空", trigger: "blur"}
|
||||
],
|
||||
guarType: [
|
||||
{required: true, message: "请选择担保方式", trigger: "change"}
|
||||
],
|
||||
applyAmt: [
|
||||
{required: true, validator: validateApplyAmt, trigger: "blur"}
|
||||
],
|
||||
loanTerm: [
|
||||
{required: true, validator: validateLoanTerm, trigger: "blur"}
|
||||
],
|
||||
collType: [
|
||||
{required: true, message: "请选择抵质押类型", trigger: "change"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dialogVisible: {
|
||||
get() {
|
||||
return this.visible
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:visible', val)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
if (val) {
|
||||
this.reset()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
orgCode: '892000',
|
||||
runType: '1',
|
||||
custIsn: undefined,
|
||||
custName: undefined,
|
||||
idType: undefined,
|
||||
idNum: undefined,
|
||||
guarType: undefined,
|
||||
applyAmt: undefined,
|
||||
loanTerm: undefined,
|
||||
isAgriGuar: false,
|
||||
isGreenLoan: false,
|
||||
isTechEnt: false,
|
||||
isTradeConstruction: false,
|
||||
collType: undefined,
|
||||
collThirdParty: false
|
||||
}
|
||||
this.submitting = false
|
||||
this.resetForm("form")
|
||||
},
|
||||
/** 对话框关闭处理 */
|
||||
handleClose() {
|
||||
this.cancel()
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.dialogVisible = false
|
||||
this.reset()
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.submitting = true
|
||||
// 转换开关值为字符串
|
||||
const data = {
|
||||
...this.form,
|
||||
isAgriGuar: this.form.isAgriGuar ? 'true' : 'false',
|
||||
isGreenLoan: this.form.isGreenLoan ? 'true' : 'false',
|
||||
isTechEnt: this.form.isTechEnt ? 'true' : 'false',
|
||||
isTradeConstruction: this.form.isTradeConstruction ? 'true' : 'false',
|
||||
collThirdParty: this.form.collThirdParty ? 'true' : 'false'
|
||||
}
|
||||
|
||||
createCorporateWorkflow(data).then(response => {
|
||||
this.$modal.msgSuccess("新增成功")
|
||||
this.dialogVisible = false
|
||||
this.$emit('success')
|
||||
}).catch(error => {
|
||||
// 保留表单,显示错误信息
|
||||
console.error('创建失败:', error)
|
||||
}).finally(() => {
|
||||
this.submitting = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.workflow-create-form .el-divider {
|
||||
margin: 8px 0 16px 0;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.workflow-create-form .el-col {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
flex: 0 0 100% !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,324 @@
|
||||
<template>
|
||||
<div class="corporate-workflow-detail" v-loading="loading">
|
||||
<!-- 两栏布局:左侧关键信息 + 右侧(流程详情+模型输出) -->
|
||||
<div v-if="!loading && detailData" class="detail-layout">
|
||||
<!-- 左侧关键信息卡片 -->
|
||||
<div class="left-panel">
|
||||
<el-card class="summary-card">
|
||||
<div slot="header" class="card-header">
|
||||
<span class="card-title">关键信息</span>
|
||||
</div>
|
||||
<el-descriptions :column="1" direction="vertical" border>
|
||||
<el-descriptions-item label="业务方流水号">{{ detailData.serialNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户名称">{{ detailData.custName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户类型">{{ detailData.custType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请金额">{{ detailData.applyAmt }} 元</el-descriptions-item>
|
||||
<el-descriptions-item label="基准利率">
|
||||
<span class="rate-value">{{ getBaseLoanRate() }}</span> %
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="浮动BP">
|
||||
<span class="total-bp-value">{{ getTotalBp() }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="测算利率">
|
||||
<span class="calculate-rate">{{ getCalculateRate() }}</span> %
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="执行利率">
|
||||
<div class="execute-rate-input-wrapper">
|
||||
<el-input
|
||||
v-model="executeRateInput"
|
||||
class="execute-rate-input"
|
||||
placeholder="请输入执行利率"
|
||||
>
|
||||
<template slot="append">%</template>
|
||||
</el-input>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleSetExecuteRate"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 右侧面板 -->
|
||||
<div class="right-panel">
|
||||
<!-- 模型输出卡片 -->
|
||||
<ModelOutputDisplay
|
||||
:cust-type="detailData.custType"
|
||||
:retail-output="null"
|
||||
:corp-output="corpOutput"
|
||||
/>
|
||||
|
||||
<!-- 流程详情卡片 -->
|
||||
<el-card class="detail-card">
|
||||
<div slot="header" class="card-header">
|
||||
<span class="card-title">流程详情</span>
|
||||
</div>
|
||||
|
||||
<!-- 基本信息组 -->
|
||||
<div class="info-section">
|
||||
<h4 class="section-title">基本信息</h4>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="机构编码">{{ detailData.orgCode }}</el-descriptions-item>
|
||||
<el-descriptions-item label="运行模式">{{ detailData.runType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户内码">{{ detailData.custIsn }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件类型">{{ detailData.idType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件号码">{{ detailData.idNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="贷款期限">{{ detailData.loanTerm || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ detailData.createTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建者">{{ detailData.createBy }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<!-- 业务信息组 -->
|
||||
<div class="info-section">
|
||||
<h4 class="section-title">业务信息</h4>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="担保方式">{{ detailData.guarType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请金额">{{ detailData.applyAmt }} 元</el-descriptions-item>
|
||||
<el-descriptions-item label="省农担担保贷款">{{
|
||||
formatBoolean(detailData.isAgriGuar)
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="绿色贷款">{{ formatBoolean(detailData.isGreenLoan) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="科技型企业">{{ formatBoolean(detailData.isTechEnt) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押类型">{{ detailData.collType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押物是否三方所有">{{
|
||||
formatBoolean(detailData.collThirdParty)
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 议价池卡片 -->
|
||||
<BargainingPoolDisplay
|
||||
v-if="bargainingPool"
|
||||
:branch-pool="bargainingPool.branchPool"
|
||||
:sub-branch-pool="bargainingPool.subBranchPool"
|
||||
:private-domain-pool="bargainingPool.privateDomainPool"
|
||||
:excess-profit-share="bargainingPool.excessProfitShare"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {setExecuteRate} from "@/api/loanPricing/workflow"
|
||||
import ModelOutputDisplay from "./ModelOutputDisplay.vue"
|
||||
import BargainingPoolDisplay from "./BargainingPoolDisplay.vue"
|
||||
|
||||
export default {
|
||||
name: "CorporateWorkflowDetail",
|
||||
components: {
|
||||
ModelOutputDisplay,
|
||||
BargainingPoolDisplay
|
||||
},
|
||||
props: {
|
||||
detailData: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
corpOutput: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
bargainingPool: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
executeRateInput: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'detailData.executeRate': {
|
||||
handler(newVal) {
|
||||
this.executeRateInput = newVal || ''
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 格式化布尔值为中文 */
|
||||
formatBoolean(value) {
|
||||
if (value === 'true' || value === true || value === '1' || value === 1) return '是'
|
||||
if (value === 'false' || value === false || value === '0' || value === 0) return '否'
|
||||
return value || '-'
|
||||
},
|
||||
/** 获取基准利率 */
|
||||
getBaseLoanRate() {
|
||||
return this.corpOutput?.baseLoanRate || '-'
|
||||
},
|
||||
/** 获取浮动BP */
|
||||
getTotalBp() {
|
||||
return this.corpOutput?.totalBp || '-'
|
||||
},
|
||||
/** 获取测算利率 */
|
||||
getCalculateRate() {
|
||||
return this.corpOutput?.calculateRate || '-'
|
||||
},
|
||||
/** 设定执行利率 */
|
||||
handleSetExecuteRate() {
|
||||
const value = this.executeRateInput
|
||||
if (value === null || value === undefined || value === '') {
|
||||
this.$modal.msgError("请输入执行利率")
|
||||
return
|
||||
}
|
||||
|
||||
const numValue = parseFloat(value)
|
||||
if (isNaN(numValue)) {
|
||||
this.$modal.msgError("请输入有效的数字")
|
||||
return
|
||||
}
|
||||
if (numValue < 0 || numValue > 100) {
|
||||
this.$modal.msgError("执行利率必须在 0 到 100 之间")
|
||||
return
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
setExecuteRate(this.detailData.serialNum, value.toString()).then(() => {
|
||||
this.$modal.msgSuccess("执行利率设定成功")
|
||||
this.$emit('refresh')
|
||||
this.loading = false
|
||||
}).catch(error => {
|
||||
this.$modal.msgError("设定失败:" + (error.msg || error.message || "未知错误"))
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.corporate-workflow-detail {
|
||||
.detail-layout {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
align-items: flex-start;
|
||||
|
||||
.left-panel {
|
||||
flex: 0 0 280px;
|
||||
max-width: 280px;
|
||||
|
||||
.summary-card {
|
||||
::v-deep .el-card__header {
|
||||
padding: 16px 20px;
|
||||
background-color: #fafafa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-card__body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.execute-rate-input-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
|
||||
.execute-rate-input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.rate-value {
|
||||
color: #67c23a;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.total-bp-value {
|
||||
color: #e6a23c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.calculate-rate {
|
||||
color: #f56c6c;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right-panel {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
.detail-card {
|
||||
::v-deep .el-card__header {
|
||||
padding: 16px 20px;
|
||||
background-color: #fafafa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-card__body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.info-section {
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin: 0 0 16px 0;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 992px) {
|
||||
.corporate-workflow-detail {
|
||||
.detail-layout {
|
||||
flex-direction: column;
|
||||
|
||||
.left-panel,
|
||||
.right-panel {
|
||||
flex: 1 1 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<el-dialog title="选择客户类型" :visible.sync="dialogVisible" width="500px" append-to-body
|
||||
:close-on-click-modal="false">
|
||||
<div class="customer-type-selector">
|
||||
<div class="type-card" @click="selectType('personal')">
|
||||
<div class="card-icon">
|
||||
<i class="el-icon-user"></i>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">个人客户</div>
|
||||
<div class="card-desc">个人客户利率定价</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="type-card" @click="selectType('corporate')">
|
||||
<div class="card-icon">
|
||||
<i class="el-icon-office-building"></i>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<div class="card-title">企业客户</div>
|
||||
<div class="card-desc">企业客户利率定价</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "CustomerTypeSelector",
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {
|
||||
dialogVisible: {
|
||||
get() {
|
||||
return this.visible
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:visible', val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectType(type) {
|
||||
this.$emit('select', type)
|
||||
this.dialogVisible = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.customer-type-selector {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.type-card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 30px 20px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.type-card:hover {
|
||||
border-color: #409EFF;
|
||||
background-color: #f0f7ff;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.2);
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
font-size: 48px;
|
||||
color: #409EFF;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card-desc {
|
||||
font-size: 14px;
|
||||
color: #909399;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,311 @@
|
||||
<template>
|
||||
<el-card class="model-output-card" v-if="custType && (retailOutput || corpOutput)">
|
||||
<div slot="header" class="card-header">
|
||||
<span class="card-title">模型输出</span>
|
||||
</div>
|
||||
<el-tabs v-model="activeTab">
|
||||
<!-- 个人客户模型输出 -->
|
||||
<template v-if="custType === '个人' && retailOutput">
|
||||
<!-- 基本信息 -->
|
||||
<el-tab-pane label="基本信息" name="retail-basic">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="客户内码">{{ retailOutput.custIsn || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户名称">{{ retailOutput.custName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件类型">{{ retailOutput.idType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件号码">{{ retailOutput.idNum || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="基准利率"><span class="rate-value">{{ retailOutput.baseLoanRate || '-' }}</span> %</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 忠诚度分析 -->
|
||||
<el-tab-pane label="忠诚度分析" name="retail-loyalty">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="我行首贷客户">{{ formatBoolean(retailOutput.isFirstLoan) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="用信天数">{{ retailOutput.faithDay || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户年龄">{{ retailOutput.custAge || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_首贷"><span class="bp-value">{{ retailOutput.bpFirstLoan || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷龄"><span class="bp-value">{{ retailOutput.bpAgeLoan || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="BP_年龄"><span class="bp-value">{{ retailOutput.bpAge || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_忠诚度" :span="2"><span class="total-bp-value">{{ retailOutput.totalBpLoyalty || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 贡献度分析 -->
|
||||
<el-tab-pane label="贡献度分析" name="retail-contribution">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="存款年日均">{{ retailOutput.balanceAvg || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="贷款年日均">{{ retailOutput.loanAvg || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="派生率">{{ retailOutput.derivationRate || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_贡献度"><span class="total-bp-value">{{ retailOutput.totalBpContribution || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 关联度分析 -->
|
||||
<el-tab-pane label="关联度分析" name="retail-relevance">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="中间业务_个人_信用卡">{{ formatBoolean(retailOutput.midPerCard) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_一码通">{{ formatBoolean(retailOutput.midPerPass) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_丰收互联">{{ formatBoolean(retailOutput.midPerHarvest) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_有效客户">{{ formatBoolean(retailOutput.midPerEffect) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_快捷支付">{{ formatBoolean(retailOutput.midPerQuickPay) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_电费代扣">{{ formatBoolean(retailOutput.midPerEleDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_水费代扣">{{ formatBoolean(retailOutput.midPerWaterDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_华数费代扣">{{ formatBoolean(retailOutput.midPerHuashuDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_煤气费代扣">{{ formatBoolean(retailOutput.MidPerGasDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_市民卡">{{ formatBoolean(retailOutput.midPerCitizencard) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_理财业务">{{ formatBoolean(retailOutput.midPerFinMan) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_个人_etc">{{ formatBoolean(retailOutput.midPerEtc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_中间业务"><span class="bp-value">{{ retailOutput.bpMid || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_关联度"><span class="total-bp-value">{{ retailOutput.totoalBpRelevance || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 贷款特征 -->
|
||||
<el-tab-pane label="贷款特征" name="retail-loan">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="申请金额">{{ retailOutput.applyAmt || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷款额度"><span class="bp-value">{{ retailOutput.bpLoanAmount || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="贷款用途">{{ formatLoanPurpose(retailOutput.loanPurpose) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="是否有经营佐证">{{ formatBoolean(retailOutput.bizProof) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷款用途"><span class="bp-value">{{ retailOutput.bpLoanUse || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="循环功能">{{ formatBoolean(retailOutput.loanLoop) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_循环功能"><span class="bp-value">{{ retailOutput.bpLoanLoop || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押类型">{{ retailOutput.collType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押物三方所有">{{ formatBoolean(retailOutput.collThirdParty) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_抵押物"><span class="bp-value">{{ retailOutput.bpCollateral || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 风险度分析 -->
|
||||
<el-tab-pane label="风险度分析" name="retail-risk">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="灰名单客户">{{ formatBoolean(retailOutput.greyCust) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="本金逾期">{{ formatBoolean(retailOutput.prinOverdue) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="利息逾期">{{ formatBoolean(retailOutput.interestOverdue) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="信用卡逾期">{{ formatBoolean(retailOutput.cardOverdue) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_灰名单与逾期"><span class="bp-value">{{ retailOutput.bpGreyOverdue || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_风险度"><span class="total-bp-value">{{ retailOutput.totoalBpRisk || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 测算结果 -->
|
||||
<el-tab-pane label="测算结果" name="retail-result">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="浮动BP"><span class="total-bp-value">{{ retailOutput.totalBp || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="测算利率"><span class="calculate-rate">{{ retailOutput.calculateRate || '-' }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="历史利率">{{ retailOutput.loanRateHistory || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="产品最低利率下限">{{ retailOutput.minRateProduct || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="平滑幅度">{{ retailOutput.smoothRange || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="最终测算利率"><span class="calculate-rate">{{ retailOutput.finalCalculateRate || '-' }}</span> %</el-descriptions-item>
|
||||
<el-descriptions-item label="参考利率"><span class="calculate-rate">{{ retailOutput.referenceRate || '-' }}</span> %</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
</template>
|
||||
|
||||
<!-- 企业客户模型输出 -->
|
||||
<template v-else-if="custType === '企业' && corpOutput">
|
||||
<!-- 基本信息 -->
|
||||
<el-tab-pane label="基本信息" name="corp-basic">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="客户内码">{{ corpOutput.custIsn || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户名称">{{ corpOutput.custName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件类型">{{ corpOutput.idType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件号码">{{ corpOutput.idNum || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="基准利率"><span class="rate-value">{{ corpOutput.baseLoanRate || '-' }}</span> %</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 忠诚度分析 -->
|
||||
<el-tab-pane label="忠诚度分析" name="corp-loyalty">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="我行首贷客户">{{ formatBoolean(corpOutput.isFirstLoan) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="用信天数">{{ corpOutput.faithDay || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_首贷"><span class="bp-value">{{ corpOutput.bpFirstLoan || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷龄"><span class="bp-value">{{ corpOutput.bpAgeLoan || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_忠诚度" :span="2"><span class="total-bp-value">{{ corpOutput.totalBpLoyalty || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 贡献度分析 -->
|
||||
<el-tab-pane label="贡献度分析" name="corp-contribution">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="存款年日均">{{ corpOutput.balanceAvg || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="贷款年日均">{{ corpOutput.loanAvg || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="派生率">{{ corpOutput.derivationRate || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_贡献度"><span class="total-bp-value">{{ corpOutput.totalBpContribution || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 关联度分析 -->
|
||||
<el-tab-pane label="关联度分析" name="corp-relevance">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="中间业务_企业_企业互联">{{ formatBoolean(corpOutput.midEntConnect) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_有效价值客户">{{ formatBoolean(corpOutput.midEntEffect) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_国际业务">{{ formatBoolean(corpOutput.midEntInter) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_承兑">{{ formatBoolean(corpOutput.midEntAccept) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_贴现">{{ formatBoolean(corpOutput.midEntDiscount) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_电费代扣">{{ formatBoolean(corpOutput.midEntEleDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_水费代扣">{{ formatBoolean(corpOutput.midEntWaterDdc) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="中间业务_企业_税务代扣">{{ formatBoolean(corpOutput.midEntTax) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_中间业务"><span class="bp-value">{{ corpOutput.bpMid || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="代发工资户数">{{ corpOutput.payroll || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="存量贷款余额">{{ corpOutput.invLoanAmount || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_代发工资"><span class="bp-value">{{ corpOutput.bpPayroll || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_关联度"><span class="total-bp-value">{{ corpOutput.totoalBpRelevance || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 企业类别 -->
|
||||
<el-tab-pane label="企业类别" name="corp-category">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="净身企业">{{ formatBoolean(corpOutput.isCleanEnt) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="开立基本结算账户">{{ formatBoolean(corpOutput.hasSettleAcct) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="省农担担保贷款">{{ formatBoolean(corpOutput.isAgriGuar) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="绿色贷款">{{ formatBoolean(corpOutput.isGreenLoan) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="科技型企业">{{ formatBoolean(corpOutput.isTechEnt) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_企业客户类别"><span class="bp-value">{{ corpOutput.bpEntType || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 贷款特征 -->
|
||||
<el-tab-pane label="贷款特征" name="corp-loan">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="贷款期限">{{ corpOutput.loanTerm || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷款期限"><span class="bp-value">{{ corpOutput.bpLoanTerm || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="申请金额">{{ corpOutput.applyAmt || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_贷款额度"><span class="bp-value">{{ corpOutput.bpLoanAmount || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押类型">{{ corpOutput.collType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押物三方所有">{{ formatBoolean(corpOutput.collThirdParty) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_抵押物"><span class="bp-value">{{ corpOutput.bpCollateral || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 风险度分析 -->
|
||||
<el-tab-pane label="风险度分析" name="corp-risk">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="灰名单客户">{{ formatBoolean(corpOutput.greyCust) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="本金逾期">{{ formatBoolean(corpOutput.prinOverdue) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="利息逾期">{{ formatBoolean(corpOutput.interestOverdue) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="信用卡逾期">{{ formatBoolean(corpOutput.cardOverdue) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="BP_灰名单与逾期"><span class="bp-value">{{ corpOutput.bpGreyOverdue || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="TOTAL_BP_风险度"><span class="total-bp-value">{{ corpOutput.totoalBpRisk || '-' }}</span></el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 测算结果 -->
|
||||
<el-tab-pane label="测算结果" name="corp-result">
|
||||
<el-descriptions :column="2" border size="small">
|
||||
<el-descriptions-item label="浮动BP"><span class="total-bp-value">{{ corpOutput.totalBp || '-' }}</span></el-descriptions-item>
|
||||
<el-descriptions-item label="测算利率"><span class="calculate-rate">{{ corpOutput.calculateRate || '-' }}</span> %</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-tab-pane>
|
||||
</template>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ModelOutputDisplay",
|
||||
props: {
|
||||
custType: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
retailOutput: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
corpOutput: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeTab: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
custType: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
// 根据客户类型设置默认 tab
|
||||
if (val === '个人') {
|
||||
this.activeTab = 'retail-basic'
|
||||
} else if (val === '企业') {
|
||||
this.activeTab = 'corp-basic'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 格式化布尔值为中文 */
|
||||
formatBoolean(value) {
|
||||
if (value === 'true' || value === true || value === '1' || value === 1) return '是'
|
||||
if (value === 'false' || value === false || value === '0' || value === 0) return '否'
|
||||
return value || '-'
|
||||
},
|
||||
/** 格式化贷款用途 */
|
||||
formatLoanPurpose(value) {
|
||||
if (value === 'consumer') return '消费贷款'
|
||||
if (value === 'business') return '经营贷款'
|
||||
return value || '-'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.model-output-card {
|
||||
::v-deep .el-card__header {
|
||||
padding: 16px 20px;
|
||||
background-color: #fafafa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-card__body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
::v-deep .el-tabs__header {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
// BP 值样式
|
||||
.bp-value {
|
||||
color: #409eff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
// TOTAL_BP 样式
|
||||
.total-bp-value {
|
||||
color: #e6a23c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
// 测算利率高亮样式
|
||||
.calculate-rate {
|
||||
color: #f56c6c;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
// 利率值样式
|
||||
.rate-value {
|
||||
color: #67c23a;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,281 @@
|
||||
<template>
|
||||
<el-dialog title="新增个人利率定价流程" :visible.sync="dialogVisible" width="900px" append-to-body
|
||||
@close="handleClose">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="140px" class="workflow-create-form">
|
||||
<!-- 基本信息 -->
|
||||
<el-divider content-position="left">基本信息</el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="客户内码" prop="custIsn">
|
||||
<el-input v-model="form.custIsn" placeholder="请输入客户内码"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="客户名称" prop="custName">
|
||||
<el-input v-model="form.custName" placeholder="请输入客户名称"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="证件类型" prop="idType">
|
||||
<el-select v-model="form.idType" placeholder="请选择证件类型" style="width: 100%">
|
||||
<el-option label="身份证" value="身份证"/>
|
||||
<el-option label="其他证件" value="其他证件"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="证件号码" prop="idNum">
|
||||
<el-input v-model="form.idNum" placeholder="请输入证件号码"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 贷款信息 -->
|
||||
<el-divider content-position="left">贷款信息</el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="担保方式" prop="guarType">
|
||||
<el-select v-model="form.guarType" placeholder="请选择担保方式" style="width: 100%">
|
||||
<el-option label="信用" value="信用"/>
|
||||
<el-option label="保证" value="保证"/>
|
||||
<el-option label="抵押" value="抵押"/>
|
||||
<el-option label="质押" value="质押"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="申请金额(元)" prop="applyAmt">
|
||||
<el-input v-model="form.applyAmt" placeholder="请输入申请金额"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="贷款用途" prop="loanPurpose">
|
||||
<el-select v-model="form.loanPurpose" placeholder="请选择贷款用途" style="width: 100%">
|
||||
<el-option label="消费" value="consumer"/>
|
||||
<el-option label="经营" value="business"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="借款期限(年)" prop="loanTerm">
|
||||
<el-select v-model="form.loanTerm" placeholder="请选择借款期限" style="width: 100%">
|
||||
<el-option v-for="item in loanTermOptions" :key="item" :label="item" :value="item"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否有经营佐证" prop="bizProof">
|
||||
<el-switch v-model="form.bizProof"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="循环功能" prop="loanLoop">
|
||||
<el-switch v-model="form.loanLoop"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 抵质押信息 -->
|
||||
<el-divider content-position="left">抵质押信息</el-divider>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="抵质押类型" prop="collType">
|
||||
<el-select v-model="form.collType" placeholder="请选择抵质押类型" style="width: 100%">
|
||||
<el-option label="一类" value="一类"/>
|
||||
<el-option label="二类" value="二类"/>
|
||||
<el-option label="三类" value="三类"/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="抵质押物三方所有" prop="collThirdParty">
|
||||
<el-switch v-model="form.collThirdParty"/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" :loading="submitting" @click="submitForm">确 定</el-button>
|
||||
<el-button @click="cancel">取 消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {createPersonalWorkflow} from "@/api/loanPricing/workflow"
|
||||
|
||||
export default {
|
||||
name: "PersonalCreateDialog",
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
// 金额验证
|
||||
const validateApplyAmt = (rule, value, callback) => {
|
||||
if (!value) {
|
||||
callback(new Error('请输入申请金额'))
|
||||
} else {
|
||||
const num = parseFloat(value)
|
||||
if (isNaN(num) || num <= 0) {
|
||||
callback(new Error('请输入有效的金额'))
|
||||
} else if (num > 999999999.99) {
|
||||
callback(new Error('金额不能超过 999999999.99'))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
loanTermOptions: [
|
||||
'1', '2', '3', '4', '5', '6'
|
||||
],
|
||||
submitting: false,
|
||||
form: {
|
||||
orgCode: '892000',
|
||||
runType: '1',
|
||||
custIsn: undefined,
|
||||
custName: undefined,
|
||||
idType: undefined,
|
||||
idNum: undefined,
|
||||
guarType: undefined,
|
||||
applyAmt: undefined,
|
||||
loanPurpose: undefined,
|
||||
loanTerm: undefined,
|
||||
bizProof: false,
|
||||
loanLoop: false,
|
||||
collType: undefined,
|
||||
collThirdParty: false
|
||||
},
|
||||
rules: {
|
||||
custIsn: [
|
||||
{required: true, message: "客户内码不能为空", trigger: "blur"},
|
||||
{min: 1, max: 50, message: "长度在 1 到 50 个字符", trigger: "blur"}
|
||||
],
|
||||
custName: [
|
||||
{required: true, message: "客户名称不能为空", trigger: "blur"},
|
||||
{min: 1, max: 100, message: "长度在 1 到 100 个字符", trigger: "blur"}
|
||||
],
|
||||
idType: [
|
||||
{required: true, message: "请选择证件类型", trigger: "change"}
|
||||
],
|
||||
idNum: [
|
||||
{required: true, message: "证件号码不能为空", trigger: "blur"}
|
||||
],
|
||||
guarType: [
|
||||
{required: true, message: "请选择担保方式", trigger: "change"}
|
||||
],
|
||||
applyAmt: [
|
||||
{required: true, validator: validateApplyAmt, trigger: "blur"}
|
||||
],
|
||||
loanPurpose: [
|
||||
{required: true, message: "请选择贷款用途", trigger: "change"}
|
||||
],
|
||||
loanTerm: [
|
||||
{required: true, message: "请选择借款期限", trigger: "change"}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dialogVisible: {
|
||||
get() {
|
||||
return this.visible
|
||||
},
|
||||
set(val) {
|
||||
this.$emit('update:visible', val)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
visible(val) {
|
||||
if (val) {
|
||||
this.reset()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 表单重置 */
|
||||
reset() {
|
||||
this.form = {
|
||||
orgCode: '892000',
|
||||
runType: '1',
|
||||
custIsn: undefined,
|
||||
custName: undefined,
|
||||
idType: undefined,
|
||||
idNum: undefined,
|
||||
guarType: undefined,
|
||||
applyAmt: undefined,
|
||||
loanPurpose: undefined,
|
||||
loanTerm: undefined,
|
||||
bizProof: false,
|
||||
loanLoop: false,
|
||||
collType: undefined,
|
||||
collThirdParty: false
|
||||
}
|
||||
this.submitting = false
|
||||
this.resetForm("form")
|
||||
},
|
||||
/** 对话框关闭处理 */
|
||||
handleClose() {
|
||||
this.cancel()
|
||||
},
|
||||
/** 取消按钮 */
|
||||
cancel() {
|
||||
this.dialogVisible = false
|
||||
this.reset()
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.submitting = true
|
||||
// 转换开关值为字符串
|
||||
const data = {
|
||||
...this.form,
|
||||
bizProof: this.form.bizProof ? '1' : '0',
|
||||
loanLoop: this.form.loanLoop ? '1' : '0',
|
||||
collThirdParty: this.form.collThirdParty ? '1' : '0'
|
||||
}
|
||||
|
||||
createPersonalWorkflow(data).then(response => {
|
||||
this.$modal.msgSuccess("新增成功")
|
||||
this.dialogVisible = false
|
||||
this.$emit('success')
|
||||
}).catch(error => {
|
||||
// 保留表单,显示错误信息
|
||||
console.error('创建失败:', error)
|
||||
}).finally(() => {
|
||||
this.submitting = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.workflow-create-form .el-divider {
|
||||
margin: 8px 0 16px 0;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.workflow-create-form .el-col {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
flex: 0 0 100% !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,330 @@
|
||||
<template>
|
||||
<div class="personal-workflow-detail" v-loading="loading">
|
||||
<!-- 两栏布局:左侧关键信息 + 右侧(流程详情+模型输出) -->
|
||||
<div v-if="!loading && detailData" class="detail-layout">
|
||||
<!-- 左侧关键信息卡片 -->
|
||||
<div class="left-panel">
|
||||
<el-card class="summary-card">
|
||||
<div slot="header" class="card-header">
|
||||
<span class="card-title">关键信息</span>
|
||||
</div>
|
||||
<el-descriptions :column="1" direction="vertical" border>
|
||||
<el-descriptions-item label="业务方流水号">{{ detailData.serialNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户名称">{{ detailData.custName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户类型">{{ detailData.custType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请金额">{{ detailData.applyAmt }} 元</el-descriptions-item>
|
||||
<el-descriptions-item label="基准利率">
|
||||
<span class="rate-value">{{ getBaseLoanRate() }}</span> %
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="浮动BP">
|
||||
<span class="total-bp-value">{{ getTotalBp() }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="最终测算利率">
|
||||
<span class="calculate-rate">{{ getCalculateRate() }}</span> %
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="执行利率">
|
||||
<div class="execute-rate-input-wrapper">
|
||||
<el-input
|
||||
v-model="executeRateInput"
|
||||
class="execute-rate-input"
|
||||
placeholder="请输入执行利率"
|
||||
>
|
||||
<template slot="append">%</template>
|
||||
</el-input>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="handleSetExecuteRate"
|
||||
>
|
||||
确定
|
||||
</el-button>
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 右侧面板 -->
|
||||
<div class="right-panel">
|
||||
<!-- 模型输出卡片 -->
|
||||
<ModelOutputDisplay
|
||||
:cust-type="detailData.custType"
|
||||
:retail-output="retailOutput"
|
||||
:corp-output="null"
|
||||
/>
|
||||
|
||||
<!-- 流程详情卡片 -->
|
||||
<el-card class="detail-card">
|
||||
<div slot="header" class="card-header">
|
||||
<span class="card-title">流程详情</span>
|
||||
</div>
|
||||
|
||||
<!-- 基本信息组 -->
|
||||
<div class="info-section">
|
||||
<h4 class="section-title">基本信息</h4>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="机构编码">{{ detailData.orgCode }}</el-descriptions-item>
|
||||
<el-descriptions-item label="运行模式">{{ detailData.runType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户内码">{{ detailData.custIsn }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件类型">{{ detailData.idType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="证件号码">{{ detailData.idNum }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建时间">{{ detailData.createTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="创建者">{{ detailData.createBy }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
|
||||
<!-- 业务信息组 -->
|
||||
<div class="info-section">
|
||||
<h4 class="section-title">业务信息</h4>
|
||||
<el-descriptions :column="2" border>
|
||||
<el-descriptions-item label="担保方式">{{ detailData.guarType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请金额">{{ detailData.applyAmt }} 元</el-descriptions-item>
|
||||
<el-descriptions-item label="贷款用途">{{ formatLoanPurpose(detailData.loanPurpose) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="借款期限">{{ detailData.loanTerm || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="是否有经营佐证">{{
|
||||
formatBoolean(detailData.bizProof)
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="循环功能">{{ formatBoolean(detailData.loanLoop) }}</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押类型">{{ detailData.collType || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="抵质押物是否三方所有">{{
|
||||
formatBoolean(detailData.collThirdParty)
|
||||
}}
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 议价池卡片 -->
|
||||
<BargainingPoolDisplay
|
||||
v-if="bargainingPool"
|
||||
:branch-pool="bargainingPool.branchPool"
|
||||
:sub-branch-pool="bargainingPool.subBranchPool"
|
||||
:private-domain-pool="bargainingPool.privateDomainPool"
|
||||
:excess-profit-share="bargainingPool.excessProfitShare"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {setExecuteRate} from "@/api/loanPricing/workflow"
|
||||
import ModelOutputDisplay from "./ModelOutputDisplay.vue"
|
||||
import BargainingPoolDisplay from "./BargainingPoolDisplay.vue"
|
||||
|
||||
export default {
|
||||
name: "PersonalWorkflowDetail",
|
||||
components: {
|
||||
ModelOutputDisplay,
|
||||
BargainingPoolDisplay
|
||||
},
|
||||
props: {
|
||||
detailData: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
retailOutput: {
|
||||
type: Object,
|
||||
default: null
|
||||
},
|
||||
bargainingPool: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
executeRateInput: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'detailData.executeRate': {
|
||||
handler(newVal) {
|
||||
this.executeRateInput = newVal || ''
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 格式化布尔值为中文 */
|
||||
formatBoolean(value) {
|
||||
if (value === 'true' || value === true || value === '1' || value === 1) return '是'
|
||||
if (value === 'false' || value === false || value === '0' || value === 0) return '否'
|
||||
return value || '-'
|
||||
},
|
||||
/** 格式化贷款用途 */
|
||||
formatLoanPurpose(value) {
|
||||
if (value === 'consumer') return '消费'
|
||||
if (value === 'business') return '经营'
|
||||
return value || '-'
|
||||
},
|
||||
/** 获取基准利率 */
|
||||
getBaseLoanRate() {
|
||||
return this.retailOutput?.baseLoanRate || '-'
|
||||
},
|
||||
/** 获取浮动BP */
|
||||
getTotalBp() {
|
||||
return this.retailOutput?.totalBp || '-'
|
||||
},
|
||||
/** 获取最终测算利率 */
|
||||
getCalculateRate() {
|
||||
return this.retailOutput?.finalCalculateRate || '-'
|
||||
},
|
||||
/** 设定执行利率 */
|
||||
handleSetExecuteRate() {
|
||||
const value = this.executeRateInput
|
||||
if (value === null || value === undefined || value === '') {
|
||||
this.$modal.msgError("请输入执行利率")
|
||||
return
|
||||
}
|
||||
|
||||
const numValue = parseFloat(value)
|
||||
if (isNaN(numValue)) {
|
||||
this.$modal.msgError("请输入有效的数字")
|
||||
return
|
||||
}
|
||||
if (numValue < 0 || numValue > 100) {
|
||||
this.$modal.msgError("执行利率必须在 0 到 100 之间")
|
||||
return
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
setExecuteRate(this.detailData.serialNum, value.toString()).then(() => {
|
||||
this.$modal.msgSuccess("执行利率设定成功")
|
||||
this.$emit('refresh')
|
||||
this.loading = false
|
||||
}).catch(error => {
|
||||
this.$modal.msgError("设定失败:" + (error.msg || error.message || "未知错误"))
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.personal-workflow-detail {
|
||||
.detail-layout {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
align-items: flex-start;
|
||||
|
||||
.left-panel {
|
||||
flex: 0 0 280px;
|
||||
max-width: 280px;
|
||||
|
||||
.summary-card {
|
||||
::v-deep .el-card__header {
|
||||
padding: 16px 20px;
|
||||
background-color: #fafafa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-card__body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.execute-rate-input-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
width: 100%;
|
||||
|
||||
.execute-rate-input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.rate-value {
|
||||
color: #67c23a;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.total-bp-value {
|
||||
color: #e6a23c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.calculate-rate {
|
||||
color: #f56c6c;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right-panel {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
|
||||
.detail-card {
|
||||
::v-deep .el-card__header {
|
||||
padding: 16px 20px;
|
||||
background-color: #fafafa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.card-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-card__body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.info-section {
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
margin: 0 0 16px 0;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 992px) {
|
||||
.personal-workflow-detail {
|
||||
.detail-layout {
|
||||
flex-direction: column;
|
||||
|
||||
.left-panel,
|
||||
.right-panel {
|
||||
flex: 1 1 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
97
ruoyi-ui/src/views/loanPricing/workflow/detail.vue
Normal file
97
ruoyi-ui/src/views/loanPricing/workflow/detail.vue
Normal file
@@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div class="app-container workflow-detail-container" v-loading="loading">
|
||||
<!-- 页面头部:标题和返回按钮 -->
|
||||
<div class="page-header">
|
||||
<h2 class="page-title">流程详情</h2>
|
||||
<el-button icon="el-icon-back" size="small" @click="goBack">返回</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 根据客户类型渲染对应的详情组件 -->
|
||||
<personal-workflow-detail
|
||||
v-if="!loading && workflowDetail && workflowDetail.custType === '个人'"
|
||||
:detail-data="workflowDetail"
|
||||
:retail-output="retailOutput"
|
||||
:bargaining-pool="bargainingPool"
|
||||
@refresh="getDetail"
|
||||
/>
|
||||
|
||||
<corporate-workflow-detail
|
||||
v-if="!loading && workflowDetail && workflowDetail.custType === '企业'"
|
||||
:detail-data="workflowDetail"
|
||||
:corp-output="corpOutput"
|
||||
:bargaining-pool="bargainingPool"
|
||||
@refresh="getDetail"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {getWorkflow} from "@/api/loanPricing/workflow"
|
||||
import PersonalWorkflowDetail from "./components/PersonalWorkflowDetail.vue"
|
||||
import CorporateWorkflowDetail from "./components/CorporateWorkflowDetail.vue"
|
||||
|
||||
export default {
|
||||
name: "LoanPricingWorkflowDetail",
|
||||
components: {
|
||||
PersonalWorkflowDetail,
|
||||
CorporateWorkflowDetail
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
workflowDetail: null,
|
||||
retailOutput: null,
|
||||
corpOutput: null,
|
||||
bargainingPool: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getDetail()
|
||||
},
|
||||
methods: {
|
||||
/** 获取流程详情 */
|
||||
getDetail() {
|
||||
const serialNum = this.$route.params.serialNum
|
||||
if (!serialNum) {
|
||||
this.$modal.msgError("缺少业务方流水号参数")
|
||||
this.goBack()
|
||||
return
|
||||
}
|
||||
|
||||
getWorkflow(serialNum).then(response => {
|
||||
this.workflowDetail = response.data.loanPricingWorkflow
|
||||
this.retailOutput = response.data.modelRetailOutputFields
|
||||
this.corpOutput = response.data.modelCorpOutputFields
|
||||
this.bargainingPool = response.data.bargainingPool
|
||||
this.loading = false
|
||||
}).catch(error => {
|
||||
this.$modal.msgError("获取流程详情失败:" + (error.message || "未知错误"))
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
/** 返回上一页 */
|
||||
goBack() {
|
||||
this.$router.go(-1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.workflow-detail-container {
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
padding: 0 4px;
|
||||
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
182
ruoyi-ui/src/views/loanPricing/workflow/index.vue
Normal file
182
ruoyi-ui/src/views/loanPricing/workflow/index.vue
Normal file
@@ -0,0 +1,182 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
|
||||
<el-form-item label="客户内码" prop="custIsn">
|
||||
<el-input
|
||||
v-model="queryParams.custIsn"
|
||||
placeholder="请输入客户内码"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="创建者" prop="createBy">
|
||||
<el-input
|
||||
v-model="queryParams.createBy"
|
||||
placeholder="请输入创建者"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="机构号" prop="orgCode">
|
||||
<el-input
|
||||
v-model="queryParams.orgCode"
|
||||
placeholder="请输入机构号"
|
||||
clearable
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-row :gutter="10" class="mb8">
|
||||
<el-col :span="1.5">
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
icon="el-icon-plus"
|
||||
size="mini"
|
||||
@click="handleAdd"
|
||||
>新增</el-button>
|
||||
</el-col>
|
||||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||||
</el-row>
|
||||
|
||||
<el-table v-loading="loading" :data="workflowList">
|
||||
<el-table-column label="业务方流水号" align="center" prop="serialNum" width="180" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="客户名称" align="center" prop="custName" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="客户类型" align="center" prop="custType" width="100" />
|
||||
<el-table-column label="担保方式" align="center" prop="guarType" width="100" />
|
||||
<el-table-column label="申请金额(元)" align="center" prop="applyAmt" width="120" />
|
||||
<el-table-column label="测算利率(%)" align="center" prop="calculateRate" width="100" />
|
||||
<el-table-column label="执行利率(%)" align="center" prop="executeRate" width="100" />
|
||||
<el-table-column label="创建时间" align="center" prop="createTime" width="160">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建者" align="center" prop="createBy" width="120" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handleView(scope.row)"
|
||||
>查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total>0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 客户类型选择对话框 -->
|
||||
<customer-type-selector :visible.sync="showTypeSelector" @select="handleSelectType"/>
|
||||
|
||||
<!-- 个人客户创建对话框 -->
|
||||
<personal-create-dialog :visible.sync="showPersonalDialog" @success="handleCreateSuccess"/>
|
||||
|
||||
<!-- 企业客户创建对话框 -->
|
||||
<corporate-create-dialog :visible.sync="showCorporateDialog" @success="handleCreateSuccess"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {listWorkflow} from "@/api/loanPricing/workflow"
|
||||
import CustomerTypeSelector from "./components/CustomerTypeSelector"
|
||||
import PersonalCreateDialog from "./components/PersonalCreateDialog"
|
||||
import CorporateCreateDialog from "./components/CorporateCreateDialog"
|
||||
|
||||
export default {
|
||||
name: "LoanPricingWorkflow",
|
||||
components: {
|
||||
CustomerTypeSelector,
|
||||
PersonalCreateDialog,
|
||||
CorporateCreateDialog
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 显示搜索条件
|
||||
showSearch: true,
|
||||
// 总条数
|
||||
total: 0,
|
||||
// 利率定价流程表格数据
|
||||
workflowList: [],
|
||||
// 是否显示客户类型选择弹出层
|
||||
showTypeSelector: false,
|
||||
// 是否显示个人客户创建弹出层
|
||||
showPersonalDialog: false,
|
||||
// 是否显示企业客户创建弹出层
|
||||
showCorporateDialog: false,
|
||||
// 查询参数
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
custIsn: undefined,
|
||||
createBy: undefined,
|
||||
orgCode: undefined
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList()
|
||||
},
|
||||
activated() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
/** 查询利率定价流程列表 */
|
||||
getList() {
|
||||
this.loading = true
|
||||
listWorkflow(this.queryParams).then(response => {
|
||||
this.workflowList = response.rows
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
/** 搜索按钮操作 */
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
/** 重置按钮操作 */
|
||||
resetQuery() {
|
||||
this.resetForm("queryForm")
|
||||
this.handleQuery()
|
||||
},
|
||||
/** 查看详情操作 */
|
||||
handleView(row) {
|
||||
this.$router.push({
|
||||
name: 'LoanPricingWorkflowDetail',
|
||||
params: { serialNum: row.serialNum }
|
||||
})
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.showTypeSelector = true
|
||||
},
|
||||
/** 选择客户类型回调 */
|
||||
handleSelectType(type) {
|
||||
if (type === 'personal') {
|
||||
this.showPersonalDialog = true
|
||||
} else if (type === 'corporate') {
|
||||
this.showCorporateDialog = true
|
||||
}
|
||||
},
|
||||
/** 创建成功回调 */
|
||||
handleCreateSuccess() {
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -73,13 +73,13 @@ export default {
|
||||
return {
|
||||
title: process.env.VUE_APP_TITLE,
|
||||
footerContent: defaultSettings.footerContent,
|
||||
codeUrl: "",
|
||||
loginForm: {
|
||||
username: "admin",
|
||||
password: "admin123",
|
||||
rememberMe: false,
|
||||
code: "",
|
||||
uuid: ""
|
||||
codeUrl: "",
|
||||
loginForm: {
|
||||
username: "",
|
||||
password: "",
|
||||
rememberMe: false,
|
||||
code: "",
|
||||
uuid: ""
|
||||
},
|
||||
loginRules: {
|
||||
username: [
|
||||
|
||||
34
ruoyi-ui/tests/id-number-validation-removal.test.js
Normal file
34
ruoyi-ui/tests/id-number-validation-removal.test.js
Normal file
@@ -0,0 +1,34 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const assert = require('assert')
|
||||
|
||||
function read(relativePath) {
|
||||
return fs.readFileSync(path.join(__dirname, '..', relativePath), 'utf8')
|
||||
}
|
||||
|
||||
const personalCreateDialog = read('src/views/loanPricing/workflow/components/PersonalCreateDialog.vue')
|
||||
const corporateCreateDialog = read('src/views/loanPricing/workflow/components/CorporateCreateDialog.vue')
|
||||
|
||||
assert(
|
||||
!personalCreateDialog.includes('const validateIdNum ='),
|
||||
'个人新增弹窗仍包含证件号码格式校验函数'
|
||||
)
|
||||
|
||||
assert(
|
||||
!corporateCreateDialog.includes('const validateIdNum ='),
|
||||
'企业新增弹窗仍包含证件号码格式校验函数'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalCreateDialog.includes("idNum: [") &&
|
||||
personalCreateDialog.includes('{required: true, message: "证件号码不能为空", trigger: "blur"}'),
|
||||
'个人新增弹窗证件号码规则应仅保留必填'
|
||||
)
|
||||
|
||||
assert(
|
||||
corporateCreateDialog.includes("idNum: [") &&
|
||||
corporateCreateDialog.includes('{required: true, message: "证件号码不能为空", trigger: "blur"}'),
|
||||
'企业新增弹窗证件号码规则应仅保留必填'
|
||||
)
|
||||
|
||||
console.log('id number validation removal assertions passed')
|
||||
30
ruoyi-ui/tests/login-default-credentials.test.js
Normal file
30
ruoyi-ui/tests/login-default-credentials.test.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const assert = require('assert')
|
||||
|
||||
const loginViewSource = fs.readFileSync(
|
||||
path.join(__dirname, '../src/views/login.vue'),
|
||||
'utf8'
|
||||
)
|
||||
|
||||
assert(
|
||||
/loginForm:\s*\{[\s\S]*username:\s*""/.test(loginViewSource),
|
||||
'登录页默认用户名应为空字符串'
|
||||
)
|
||||
|
||||
assert(
|
||||
/loginForm:\s*\{[\s\S]*password:\s*""/.test(loginViewSource),
|
||||
'登录页默认密码应为空字符串'
|
||||
)
|
||||
|
||||
assert(
|
||||
/username:\s*username === undefined \? this\.loginForm\.username : username/.test(loginViewSource),
|
||||
'登录页应继续支持从 cookie 回填用户名'
|
||||
)
|
||||
|
||||
assert(
|
||||
/password:\s*password === undefined \? this\.loginForm\.password : decrypt\(password\)/.test(loginViewSource),
|
||||
'登录页应继续支持从 cookie 回填密码'
|
||||
)
|
||||
|
||||
console.log('login default credentials assertions passed')
|
||||
88
ruoyi-ui/tests/password-transfer-api.test.js
Normal file
88
ruoyi-ui/tests/password-transfer-api.test.js
Normal file
@@ -0,0 +1,88 @@
|
||||
const assert = require('assert')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const vm = require('vm')
|
||||
|
||||
function loadModule(filePath, stubs = {}) {
|
||||
const source = fs.readFileSync(filePath, 'utf8')
|
||||
const exportedNames = []
|
||||
const transformed = source
|
||||
.replace(/^import .*$/gm, '')
|
||||
.replace(/export function\s+([A-Za-z0-9_]+)\s*\(/g, (_, name) => {
|
||||
exportedNames.push(name)
|
||||
return `function ${name}(`
|
||||
})
|
||||
.replace(/export default\s+/g, 'module.exports = ')
|
||||
|
||||
const sandbox = {
|
||||
module: { exports: {} },
|
||||
exports: {},
|
||||
require,
|
||||
console,
|
||||
process: {
|
||||
env: {
|
||||
VUE_APP_PASSWORD_TRANSFER_KEY: '1234567890abcdef'
|
||||
}
|
||||
},
|
||||
...stubs
|
||||
}
|
||||
|
||||
vm.runInNewContext(
|
||||
`${transformed}\nmodule.exports = { ${exportedNames.join(', ')} };`,
|
||||
sandbox,
|
||||
{ filename: filePath }
|
||||
)
|
||||
|
||||
return sandbox.module.exports
|
||||
}
|
||||
|
||||
const passwordTransferModule = loadModule(
|
||||
path.resolve(__dirname, '../src/utils/passwordTransfer.js'),
|
||||
{ CryptoJS: require('crypto-js') }
|
||||
)
|
||||
|
||||
const { encryptPasswordFields } = passwordTransferModule
|
||||
|
||||
const encrypted = encryptPasswordFields(
|
||||
{ password: 'admin123', code: '8888' },
|
||||
['password'],
|
||||
'1234567890abcdef'
|
||||
)
|
||||
|
||||
assert.notStrictEqual(encrypted.password, 'admin123')
|
||||
assert.strictEqual(encrypted.code, '8888')
|
||||
|
||||
const request = config => config
|
||||
const loginModule = loadModule(
|
||||
path.resolve(__dirname, '../src/api/login.js'),
|
||||
{ request, encryptPasswordFields }
|
||||
)
|
||||
|
||||
const loginConfig = loginModule.login('admin', 'admin123', '8888', 'uuid-1')
|
||||
assert.notStrictEqual(loginConfig.data.password, 'admin123')
|
||||
assert.strictEqual(loginConfig.data.username, 'admin')
|
||||
|
||||
const registerConfig = loginModule.register({ username: 'u1', password: 'p1', confirmPassword: 'p1', code: '8888' })
|
||||
assert.notStrictEqual(registerConfig.data.password, 'p1')
|
||||
assert.strictEqual(registerConfig.data.confirmPassword, 'p1')
|
||||
|
||||
const userModule = loadModule(
|
||||
path.resolve(__dirname, '../src/api/system/user.js'),
|
||||
{
|
||||
request,
|
||||
encryptPasswordFields,
|
||||
parseStrEmpty: value => value
|
||||
}
|
||||
)
|
||||
|
||||
const updatePwdConfig = userModule.updateUserPwd('oldPwd', 'newPwd')
|
||||
assert.notStrictEqual(updatePwdConfig.data.oldPassword, 'oldPwd')
|
||||
assert.notStrictEqual(updatePwdConfig.data.newPassword, 'newPwd')
|
||||
|
||||
const addUserConfig = userModule.addUser({ userName: 'u1', password: 'initPwd', nickName: 'n1' })
|
||||
assert.notStrictEqual(addUserConfig.data.password, 'initPwd')
|
||||
|
||||
const resetUserPwdConfig = userModule.resetUserPwd(2, 'resetPwd')
|
||||
assert.notStrictEqual(resetUserPwdConfig.data.password, 'resetPwd')
|
||||
|
||||
console.log('password-transfer-api test passed')
|
||||
65
ruoyi-ui/tests/personal-create-input-params.test.js
Normal file
65
ruoyi-ui/tests/personal-create-input-params.test.js
Normal file
@@ -0,0 +1,65 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const assert = require('assert')
|
||||
|
||||
function read(relativePath) {
|
||||
return fs.readFileSync(path.join(__dirname, '..', relativePath), 'utf8')
|
||||
}
|
||||
|
||||
const personalCreateDialog = read('src/views/loanPricing/workflow/components/PersonalCreateDialog.vue')
|
||||
const personalDetail = read('src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue')
|
||||
|
||||
assert(
|
||||
personalCreateDialog.includes('label="贷款用途"') && personalCreateDialog.includes('prop="loanPurpose"'),
|
||||
'个人新增弹窗缺少贷款用途字段'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalCreateDialog.includes('label="借款期限(年)"') && personalCreateDialog.includes('prop="loanTerm"'),
|
||||
'个人新增弹窗缺少借款期限字段'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalCreateDialog.includes("value=\"consumer\"") && personalCreateDialog.includes("value=\"business\""),
|
||||
'个人新增弹窗缺少贷款用途选项'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalCreateDialog.includes('loanTermOptions') &&
|
||||
personalCreateDialog.includes("'1'") &&
|
||||
personalCreateDialog.includes("'6'") &&
|
||||
!personalCreateDialog.includes("'7'"),
|
||||
'个人新增弹窗借款期限选项应限制为 1-6 年'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalCreateDialog.includes('label="一类"') &&
|
||||
personalCreateDialog.includes('label="二类"') &&
|
||||
personalCreateDialog.includes('label="三类"') &&
|
||||
!personalCreateDialog.includes('label="一线"'),
|
||||
'个人新增弹窗抵质押类型选项未按 Excel 对齐'
|
||||
)
|
||||
|
||||
assert(
|
||||
!personalCreateDialog.includes('{required: true, message: "请选择抵质押类型", trigger: "change"}'),
|
||||
'个人新增弹窗仍将抵质押类型设为必填'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalCreateDialog.includes("bizProof: this.form.bizProof ? '1' : '0'") &&
|
||||
personalCreateDialog.includes("loanLoop: this.form.loanLoop ? '1' : '0'") &&
|
||||
personalCreateDialog.includes("collThirdParty: this.form.collThirdParty ? '1' : '0'"),
|
||||
'个人新增弹窗开关字段未按 1/0 提交'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalDetail.includes('label="贷款用途"') && personalDetail.includes('detailData.loanPurpose'),
|
||||
'个人详情页缺少贷款用途展示'
|
||||
)
|
||||
|
||||
assert(
|
||||
personalDetail.includes("value === '1'") && personalDetail.includes("value === '0'"),
|
||||
'个人详情页布尔格式化未兼容 1/0'
|
||||
)
|
||||
|
||||
console.log('personal create input params assertions passed')
|
||||
21
ruoyi-ui/tests/personal-final-calculate-rate-display.test.js
Normal file
21
ruoyi-ui/tests/personal-final-calculate-rate-display.test.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const assert = require('assert')
|
||||
|
||||
function read(relativePath) {
|
||||
return fs.readFileSync(path.join(__dirname, '..', relativePath), 'utf8')
|
||||
}
|
||||
|
||||
const personalDetail = read('src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue')
|
||||
|
||||
assert(
|
||||
/label="最终测算利率"/.test(personalDetail),
|
||||
'个人流程详情左侧缺少“最终测算利率”标签'
|
||||
)
|
||||
|
||||
assert(
|
||||
/return this\.retailOutput\?\.finalCalculateRate \|\| '-'/.test(personalDetail),
|
||||
'个人流程详情没有使用 finalCalculateRate 展示最终测算利率'
|
||||
)
|
||||
|
||||
console.log('personal final calculate rate display assertions passed')
|
||||
29
ruoyi-ui/tests/retail-display-fields.test.js
Normal file
29
ruoyi-ui/tests/retail-display-fields.test.js
Normal file
@@ -0,0 +1,29 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const assert = require('assert')
|
||||
|
||||
function read(relativePath) {
|
||||
return fs.readFileSync(path.join(__dirname, '..', relativePath), 'utf8')
|
||||
}
|
||||
|
||||
const personalDetail = read('src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue')
|
||||
const modelOutput = read('src/views/loanPricing/workflow/components/ModelOutputDisplay.vue')
|
||||
|
||||
assert(
|
||||
personalDetail.includes('label="借款期限"') && personalDetail.includes('detailData.loanTerm'),
|
||||
'个人详情页缺少借款期限展示'
|
||||
)
|
||||
|
||||
const requiredRetailFields = [
|
||||
'retailOutput.loanRateHistory',
|
||||
'retailOutput.minRateProduct',
|
||||
'retailOutput.smoothRange',
|
||||
'retailOutput.finalCalculateRate',
|
||||
'retailOutput.referenceRate'
|
||||
]
|
||||
|
||||
requiredRetailFields.forEach((field) => {
|
||||
assert(modelOutput.includes(field), `模型输出缺少字段展示: ${field}`)
|
||||
})
|
||||
|
||||
console.log('retail display fields assertions passed')
|
||||
27
ruoyi-ui/tests/workflow-detail-card-order.test.js
Normal file
27
ruoyi-ui/tests/workflow-detail-card-order.test.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const assert = require('assert')
|
||||
|
||||
function read(relativePath) {
|
||||
return fs.readFileSync(path.join(__dirname, '..', relativePath), 'utf8')
|
||||
}
|
||||
|
||||
function assertModelOutputBeforeDetailCard(source, label) {
|
||||
const modelOutputIndex = source.indexOf('<ModelOutputDisplay')
|
||||
const detailCardIndex = source.indexOf('<el-card class="detail-card">')
|
||||
|
||||
assert(modelOutputIndex !== -1, `${label} 缺少模型输出卡片`)
|
||||
assert(detailCardIndex !== -1, `${label} 缺少流程详情卡片`)
|
||||
assert(
|
||||
modelOutputIndex < detailCardIndex,
|
||||
`${label} 的模型输出卡片应位于流程详情卡片上方`
|
||||
)
|
||||
}
|
||||
|
||||
const personalDetail = read('src/views/loanPricing/workflow/components/PersonalWorkflowDetail.vue')
|
||||
const corporateDetail = read('src/views/loanPricing/workflow/components/CorporateWorkflowDetail.vue')
|
||||
|
||||
assertModelOutputBeforeDetailCard(personalDetail, '个人流程详情')
|
||||
assertModelOutputBeforeDetailCard(corporateDetail, '企业流程详情')
|
||||
|
||||
console.log('workflow detail card order assertions passed')
|
||||
52
ruoyi-ui/tests/workflow-index-refresh.test.js
Normal file
52
ruoyi-ui/tests/workflow-index-refresh.test.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const assert = require('assert')
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const vm = require('vm')
|
||||
|
||||
function loadComponentOptions(filePath) {
|
||||
const source = fs.readFileSync(filePath, 'utf8')
|
||||
const scriptMatch = source.match(/<script>([\s\S]*?)<\/script>/)
|
||||
|
||||
if (!scriptMatch) {
|
||||
throw new Error('未找到组件脚本内容')
|
||||
}
|
||||
|
||||
const importNames = []
|
||||
const importPattern = /^import\s+([A-Za-z0-9_]+)\s+from\s+.*$/gm
|
||||
let importMatch = importPattern.exec(scriptMatch[1])
|
||||
while (importMatch) {
|
||||
importNames.push(importMatch[1])
|
||||
importMatch = importPattern.exec(scriptMatch[1])
|
||||
}
|
||||
|
||||
const stubImports = importNames.map(name => `const ${name} = {};`).join('\n')
|
||||
const transformed = `${stubImports}\n${scriptMatch[1]}`
|
||||
.replace(/^import .*$/gm, '')
|
||||
.replace(/export default/, 'module.exports =')
|
||||
|
||||
const sandbox = {
|
||||
module: { exports: {} },
|
||||
exports: {},
|
||||
require,
|
||||
console
|
||||
}
|
||||
|
||||
vm.runInNewContext(transformed, sandbox, { filename: filePath })
|
||||
return sandbox.module.exports
|
||||
}
|
||||
|
||||
const filePath = path.resolve(__dirname, '../src/views/loanPricing/workflow/index.vue')
|
||||
const component = loadComponentOptions(filePath)
|
||||
|
||||
assert.strictEqual(typeof component.activated, 'function', '流程列表页应在激活时刷新数据')
|
||||
|
||||
let refreshCount = 0
|
||||
component.activated.call({
|
||||
getList() {
|
||||
refreshCount += 1
|
||||
}
|
||||
})
|
||||
|
||||
assert.strictEqual(refreshCount, 1, '流程列表页激活时应调用一次 getList')
|
||||
|
||||
console.log('workflow-index-refresh test passed')
|
||||
24
sql/loan_pricing_menu.sql
Normal file
24
sql/loan_pricing_menu.sql
Normal file
@@ -0,0 +1,24 @@
|
||||
-- 利率定价流程菜单配置
|
||||
-- 注意:Windows 环境下执行后可能需要使用 CONVERT 修复编码问题
|
||||
|
||||
-- 删除旧数据
|
||||
DELETE FROM sys_role_menu WHERE menu_id IN (2000, 2001, 2002);
|
||||
DELETE FROM sys_menu WHERE menu_id IN (2000, 2001, 2002);
|
||||
|
||||
-- 一级菜单:利率定价管理
|
||||
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
VALUES(2000, '利率定价管理', 0, 5, 'loanPricing', NULL, 1, 0, 'M', '0', '0', '', 'money', 'admin', NOW(), '');
|
||||
|
||||
-- 二级菜单:流程列表
|
||||
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
VALUES(2001, '流程列表', 2000, 1, 'workflow', 'loanPricing/workflow/index', 1, 0, 'C', '0', '0', 'loanPricing:workflow:list', 'list', 'admin', NOW(), '');
|
||||
|
||||
-- 流程列表查询按钮
|
||||
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
VALUES(2002, '流程查询', 2001, 1, '', '', 1, 0, 'F', '0', '0', 'loanPricing:workflow:query', '#', 'admin', NOW(), '');
|
||||
|
||||
-- 关联管理员角色
|
||||
INSERT INTO sys_role_menu VALUES(1, 2000), (1, 2001), (1, 2002);
|
||||
|
||||
-- 如果 Windows 环境导致中文乱码,执行以下语句修复:
|
||||
-- UPDATE sys_menu SET menu_name = CONVERT(CAST(CONVERT(menu_name USING latin1) AS BINARY) USING utf8mb4) WHERE menu_id IN (2000, 2001, 2002);
|
||||
923
sql/loan_pricing_prod_init_20260331.sql
Normal file
923
sql/loan_pricing_prod_init_20260331.sql
Normal file
@@ -0,0 +1,923 @@
|
||||
-- 说明:
|
||||
-- 1. 本文件用于生产环境数据库初始化
|
||||
-- 2. 基于 sql/ry_20250522.sql 追加贷款定价业务表结构生成
|
||||
-- 3. 包含若依基础初始化数据,不包含任何贷款定价业务数据
|
||||
-- 4. 建议在空库中执行;执行前请确认数据库账号具备建库建表权限
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
CREATE DATABASE IF NOT EXISTS `loan-pricing` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||
USE `loan-pricing`;
|
||||
|
||||
-- ----------------------------
|
||||
-- 1、部门表
|
||||
-- ----------------------------
|
||||
drop table if exists sys_dept;
|
||||
create table sys_dept (
|
||||
dept_id bigint(20) not null auto_increment comment '部门id',
|
||||
parent_id bigint(20) default 0 comment '父部门id',
|
||||
ancestors varchar(50) default '' comment '祖级列表',
|
||||
dept_name varchar(30) default '' comment '部门名称',
|
||||
order_num int(4) default 0 comment '显示顺序',
|
||||
leader varchar(20) default null comment '负责人',
|
||||
phone varchar(11) default null comment '联系电话',
|
||||
email varchar(50) default null comment '邮箱',
|
||||
status char(1) default '0' comment '部门状态(0正常 1停用)',
|
||||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
primary key (dept_id)
|
||||
) engine=innodb auto_increment=200 comment = '部门表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化-部门表数据
|
||||
-- ----------------------------
|
||||
insert into sys_dept values(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||||
insert into sys_dept values(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||||
insert into sys_dept values(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||||
insert into sys_dept values(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||||
insert into sys_dept values(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||||
insert into sys_dept values(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||||
insert into sys_dept values(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||||
insert into sys_dept values(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||||
insert into sys_dept values(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||||
insert into sys_dept values(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 2、用户信息表
|
||||
-- ----------------------------
|
||||
drop table if exists sys_user;
|
||||
create table sys_user (
|
||||
user_id bigint(20) not null auto_increment comment '用户ID',
|
||||
dept_id bigint(20) default null comment '部门ID',
|
||||
user_name varchar(30) not null comment '用户账号',
|
||||
nick_name varchar(30) not null comment '用户昵称',
|
||||
user_type varchar(2) default '00' comment '用户类型(00系统用户)',
|
||||
email varchar(50) default '' comment '用户邮箱',
|
||||
phonenumber varchar(11) default '' comment '手机号码',
|
||||
sex char(1) default '0' comment '用户性别(0男 1女 2未知)',
|
||||
avatar varchar(100) default '' comment '头像地址',
|
||||
password varchar(100) default '' comment '密码',
|
||||
status char(1) default '0' comment '账号状态(0正常 1停用)',
|
||||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
||||
login_ip varchar(128) default '' comment '最后登录IP',
|
||||
login_date datetime comment '最后登录时间',
|
||||
pwd_update_date datetime comment '密码最后更新时间',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
remark varchar(500) default null comment '备注',
|
||||
primary key (user_id)
|
||||
) engine=innodb auto_increment=100 comment = '用户信息表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化-用户信息表数据
|
||||
-- ----------------------------
|
||||
insert into sys_user values(1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), sysdate(), 'admin', sysdate(), '', null, '管理员');
|
||||
insert into sys_user values(2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), sysdate(), 'admin', sysdate(), '', null, '测试员');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 3、岗位信息表
|
||||
-- ----------------------------
|
||||
drop table if exists sys_post;
|
||||
create table sys_post
|
||||
(
|
||||
post_id bigint(20) not null auto_increment comment '岗位ID',
|
||||
post_code varchar(64) not null comment '岗位编码',
|
||||
post_name varchar(50) not null comment '岗位名称',
|
||||
post_sort int(4) not null comment '显示顺序',
|
||||
status char(1) not null comment '状态(0正常 1停用)',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
remark varchar(500) default null comment '备注',
|
||||
primary key (post_id)
|
||||
) engine=innodb comment = '岗位信息表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化-岗位信息表数据
|
||||
-- ----------------------------
|
||||
insert into sys_post values(1, 'ceo', '董事长', 1, '0', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_post values(2, 'se', '项目经理', 2, '0', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_post values(3, 'hr', '人力资源', 3, '0', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_post values(4, 'user', '普通员工', 4, '0', 'admin', sysdate(), '', null, '');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 4、角色信息表
|
||||
-- ----------------------------
|
||||
drop table if exists sys_role;
|
||||
create table sys_role (
|
||||
role_id bigint(20) not null auto_increment comment '角色ID',
|
||||
role_name varchar(30) not null comment '角色名称',
|
||||
role_key varchar(100) not null comment '角色权限字符串',
|
||||
role_sort int(4) not null comment '显示顺序',
|
||||
data_scope char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)',
|
||||
menu_check_strictly tinyint(1) default 1 comment '菜单树选择项是否关联显示',
|
||||
dept_check_strictly tinyint(1) default 1 comment '部门树选择项是否关联显示',
|
||||
status char(1) not null comment '角色状态(0正常 1停用)',
|
||||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
remark varchar(500) default null comment '备注',
|
||||
primary key (role_id)
|
||||
) engine=innodb auto_increment=100 comment = '角色信息表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化-角色信息表数据
|
||||
-- ----------------------------
|
||||
insert into sys_role values('1', '超级管理员', 'admin', 1, 1, 1, 1, '0', '0', 'admin', sysdate(), '', null, '超级管理员');
|
||||
insert into sys_role values('2', '普通角色', 'common', 2, 2, 1, 1, '0', '0', 'admin', sysdate(), '', null, '普通角色');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 5、菜单权限表
|
||||
-- ----------------------------
|
||||
drop table if exists sys_menu;
|
||||
create table sys_menu (
|
||||
menu_id bigint(20) not null auto_increment comment '菜单ID',
|
||||
menu_name varchar(50) not null comment '菜单名称',
|
||||
parent_id bigint(20) default 0 comment '父菜单ID',
|
||||
order_num int(4) default 0 comment '显示顺序',
|
||||
path varchar(200) default '' comment '路由地址',
|
||||
component varchar(255) default null comment '组件路径',
|
||||
query varchar(255) default null comment '路由参数',
|
||||
route_name varchar(50) default '' comment '路由名称',
|
||||
is_frame int(1) default 1 comment '是否为外链(0是 1否)',
|
||||
is_cache int(1) default 0 comment '是否缓存(0缓存 1不缓存)',
|
||||
menu_type char(1) default '' comment '菜单类型(M目录 C菜单 F按钮)',
|
||||
visible char(1) default 0 comment '菜单状态(0显示 1隐藏)',
|
||||
status char(1) default 0 comment '菜单状态(0正常 1停用)',
|
||||
perms varchar(100) default null comment '权限标识',
|
||||
icon varchar(100) default '#' comment '菜单图标',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
remark varchar(500) default '' comment '备注',
|
||||
primary key (menu_id)
|
||||
) engine=innodb auto_increment=2000 comment = '菜单权限表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化-菜单信息表数据
|
||||
-- ----------------------------
|
||||
-- 一级菜单
|
||||
insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, '', '', 1, 0, 'M', '0', '0', '', 'system', 'admin', sysdate(), '', null, '系统管理目录');
|
||||
insert into sys_menu values('2', '系统监控', '0', '2', 'monitor', null, '', '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', sysdate(), '', null, '系统监控目录');
|
||||
insert into sys_menu values('3', '系统工具', '0', '3', 'tool', null, '', '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', sysdate(), '', null, '系统工具目录');
|
||||
-- 二级菜单
|
||||
insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', '', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', sysdate(), '', null, '用户管理菜单');
|
||||
insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', '', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', sysdate(), '', null, '角色管理菜单');
|
||||
insert into sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', '', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 'admin', sysdate(), '', null, '菜单管理菜单');
|
||||
insert into sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', '', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 'admin', sysdate(), '', null, '部门管理菜单');
|
||||
insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', '', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 'admin', sysdate(), '', null, '岗位管理菜单');
|
||||
insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', '', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 'admin', sysdate(), '', null, '字典管理菜单');
|
||||
insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', '', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 'admin', sysdate(), '', null, '参数设置菜单');
|
||||
insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', '', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 'admin', sysdate(), '', null, '通知公告菜单');
|
||||
insert into sys_menu values('108', '日志管理', '1', '9', 'log', '', '', '', 1, 0, 'M', '0', '0', '', 'log', 'admin', sysdate(), '', null, '日志管理菜单');
|
||||
insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', '', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 'admin', sysdate(), '', null, '在线用户菜单');
|
||||
insert into sys_menu values('110', '定时任务', '2', '2', 'job', 'monitor/job/index', '', '', 1, 0, 'C', '0', '0', 'monitor:job:list', 'job', 'admin', sysdate(), '', null, '定时任务菜单');
|
||||
insert into sys_menu values('111', '数据监控', '2', '3', 'druid', 'monitor/druid/index', '', '', 1, 0, 'C', '0', '0', 'monitor:druid:list', 'druid', 'admin', sysdate(), '', null, '数据监控菜单');
|
||||
insert into sys_menu values('112', '服务监控', '2', '4', 'server', 'monitor/server/index', '', '', 1, 0, 'C', '0', '0', 'monitor:server:list', 'server', 'admin', sysdate(), '', null, '服务监控菜单');
|
||||
insert into sys_menu values('113', '缓存监控', '2', '5', 'cache', 'monitor/cache/index', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 'admin', sysdate(), '', null, '缓存监控菜单');
|
||||
insert into sys_menu values('114', '缓存列表', '2', '6', 'cacheList', 'monitor/cache/list', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis-list', 'admin', sysdate(), '', null, '缓存列表菜单');
|
||||
insert into sys_menu values('115', '表单构建', '3', '1', 'build', 'tool/build/index', '', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', sysdate(), '', null, '表单构建菜单');
|
||||
insert into sys_menu values('116', '代码生成', '3', '2', 'gen', 'tool/gen/index', '', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', sysdate(), '', null, '代码生成菜单');
|
||||
insert into sys_menu values('117', '系统接口', '3', '3', 'swagger', 'tool/swagger/index', '', '', 1, 0, 'C', '0', '0', 'tool:swagger:list', 'swagger', 'admin', sysdate(), '', null, '系统接口菜单');
|
||||
-- 三级菜单
|
||||
insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', '', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 'admin', sysdate(), '', null, '操作日志菜单');
|
||||
insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', '', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', sysdate(), '', null, '登录日志菜单');
|
||||
-- 用户管理按钮
|
||||
insert into sys_menu values('1000', '用户查询', '100', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1001', '用户新增', '100', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1002', '用户修改', '100', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1003', '用户删除', '100', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1004', '用户导出', '100', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1005', '用户导入', '100', '6', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1006', '重置密码', '100', '7', '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 角色管理按钮
|
||||
insert into sys_menu values('1007', '角色查询', '101', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1008', '角色新增', '101', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1009', '角色修改', '101', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1010', '角色删除', '101', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1011', '角色导出', '101', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 菜单管理按钮
|
||||
insert into sys_menu values('1012', '菜单查询', '102', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1013', '菜单新增', '102', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1014', '菜单修改', '102', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1015', '菜单删除', '102', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 部门管理按钮
|
||||
insert into sys_menu values('1016', '部门查询', '103', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1017', '部门新增', '103', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1018', '部门修改', '103', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1019', '部门删除', '103', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 岗位管理按钮
|
||||
insert into sys_menu values('1020', '岗位查询', '104', '1', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1021', '岗位新增', '104', '2', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1022', '岗位修改', '104', '3', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1023', '岗位删除', '104', '4', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1024', '岗位导出', '104', '5', '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 字典管理按钮
|
||||
insert into sys_menu values('1025', '字典查询', '105', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1026', '字典新增', '105', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1027', '字典修改', '105', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1028', '字典删除', '105', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1029', '字典导出', '105', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 参数设置按钮
|
||||
insert into sys_menu values('1030', '参数查询', '106', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1031', '参数新增', '106', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1032', '参数修改', '106', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1033', '参数删除', '106', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1034', '参数导出', '106', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 通知公告按钮
|
||||
insert into sys_menu values('1035', '公告查询', '107', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1036', '公告新增', '107', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1037', '公告修改', '107', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1038', '公告删除', '107', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 操作日志按钮
|
||||
insert into sys_menu values('1039', '操作查询', '500', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1040', '操作删除', '500', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1041', '日志导出', '500', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 登录日志按钮
|
||||
insert into sys_menu values('1042', '登录查询', '501', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1043', '登录删除', '501', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1044', '日志导出', '501', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1045', '账户解锁', '501', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 在线用户按钮
|
||||
insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 定时任务按钮
|
||||
insert into sys_menu values('1049', '任务查询', '110', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1050', '任务新增', '110', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:add', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1051', '任务修改', '110', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1052', '任务删除', '110', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1053', '状态修改', '110', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:changeStatus', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1054', '任务导出', '110', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:export', '#', 'admin', sysdate(), '', null, '');
|
||||
-- 代码生成按钮
|
||||
insert into sys_menu values('1055', '生成查询', '116', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1056', '生成修改', '116', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1057', '生成删除', '116', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1058', '导入代码', '116', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1059', '预览代码', '116', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_menu values('1060', '生成代码', '116', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', sysdate(), '', null, '');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 6、用户和角色关联表 用户N-1角色
|
||||
-- ----------------------------
|
||||
drop table if exists sys_user_role;
|
||||
create table sys_user_role (
|
||||
user_id bigint(20) not null comment '用户ID',
|
||||
role_id bigint(20) not null comment '角色ID',
|
||||
primary key(user_id, role_id)
|
||||
) engine=innodb comment = '用户和角色关联表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化-用户和角色关联表数据
|
||||
-- ----------------------------
|
||||
insert into sys_user_role values ('1', '1');
|
||||
insert into sys_user_role values ('2', '2');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 7、角色和菜单关联表 角色1-N菜单
|
||||
-- ----------------------------
|
||||
drop table if exists sys_role_menu;
|
||||
create table sys_role_menu (
|
||||
role_id bigint(20) not null comment '角色ID',
|
||||
menu_id bigint(20) not null comment '菜单ID',
|
||||
primary key(role_id, menu_id)
|
||||
) engine=innodb comment = '角色和菜单关联表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化-角色和菜单关联表数据
|
||||
-- ----------------------------
|
||||
insert into sys_role_menu values ('2', '1');
|
||||
insert into sys_role_menu values ('2', '2');
|
||||
insert into sys_role_menu values ('2', '3');
|
||||
insert into sys_role_menu values ('2', '4');
|
||||
insert into sys_role_menu values ('2', '100');
|
||||
insert into sys_role_menu values ('2', '101');
|
||||
insert into sys_role_menu values ('2', '102');
|
||||
insert into sys_role_menu values ('2', '103');
|
||||
insert into sys_role_menu values ('2', '104');
|
||||
insert into sys_role_menu values ('2', '105');
|
||||
insert into sys_role_menu values ('2', '106');
|
||||
insert into sys_role_menu values ('2', '107');
|
||||
insert into sys_role_menu values ('2', '108');
|
||||
insert into sys_role_menu values ('2', '109');
|
||||
insert into sys_role_menu values ('2', '110');
|
||||
insert into sys_role_menu values ('2', '111');
|
||||
insert into sys_role_menu values ('2', '112');
|
||||
insert into sys_role_menu values ('2', '113');
|
||||
insert into sys_role_menu values ('2', '114');
|
||||
insert into sys_role_menu values ('2', '115');
|
||||
insert into sys_role_menu values ('2', '116');
|
||||
insert into sys_role_menu values ('2', '117');
|
||||
insert into sys_role_menu values ('2', '500');
|
||||
insert into sys_role_menu values ('2', '501');
|
||||
insert into sys_role_menu values ('2', '1000');
|
||||
insert into sys_role_menu values ('2', '1001');
|
||||
insert into sys_role_menu values ('2', '1002');
|
||||
insert into sys_role_menu values ('2', '1003');
|
||||
insert into sys_role_menu values ('2', '1004');
|
||||
insert into sys_role_menu values ('2', '1005');
|
||||
insert into sys_role_menu values ('2', '1006');
|
||||
insert into sys_role_menu values ('2', '1007');
|
||||
insert into sys_role_menu values ('2', '1008');
|
||||
insert into sys_role_menu values ('2', '1009');
|
||||
insert into sys_role_menu values ('2', '1010');
|
||||
insert into sys_role_menu values ('2', '1011');
|
||||
insert into sys_role_menu values ('2', '1012');
|
||||
insert into sys_role_menu values ('2', '1013');
|
||||
insert into sys_role_menu values ('2', '1014');
|
||||
insert into sys_role_menu values ('2', '1015');
|
||||
insert into sys_role_menu values ('2', '1016');
|
||||
insert into sys_role_menu values ('2', '1017');
|
||||
insert into sys_role_menu values ('2', '1018');
|
||||
insert into sys_role_menu values ('2', '1019');
|
||||
insert into sys_role_menu values ('2', '1020');
|
||||
insert into sys_role_menu values ('2', '1021');
|
||||
insert into sys_role_menu values ('2', '1022');
|
||||
insert into sys_role_menu values ('2', '1023');
|
||||
insert into sys_role_menu values ('2', '1024');
|
||||
insert into sys_role_menu values ('2', '1025');
|
||||
insert into sys_role_menu values ('2', '1026');
|
||||
insert into sys_role_menu values ('2', '1027');
|
||||
insert into sys_role_menu values ('2', '1028');
|
||||
insert into sys_role_menu values ('2', '1029');
|
||||
insert into sys_role_menu values ('2', '1030');
|
||||
insert into sys_role_menu values ('2', '1031');
|
||||
insert into sys_role_menu values ('2', '1032');
|
||||
insert into sys_role_menu values ('2', '1033');
|
||||
insert into sys_role_menu values ('2', '1034');
|
||||
insert into sys_role_menu values ('2', '1035');
|
||||
insert into sys_role_menu values ('2', '1036');
|
||||
insert into sys_role_menu values ('2', '1037');
|
||||
insert into sys_role_menu values ('2', '1038');
|
||||
insert into sys_role_menu values ('2', '1039');
|
||||
insert into sys_role_menu values ('2', '1040');
|
||||
insert into sys_role_menu values ('2', '1041');
|
||||
insert into sys_role_menu values ('2', '1042');
|
||||
insert into sys_role_menu values ('2', '1043');
|
||||
insert into sys_role_menu values ('2', '1044');
|
||||
insert into sys_role_menu values ('2', '1045');
|
||||
insert into sys_role_menu values ('2', '1046');
|
||||
insert into sys_role_menu values ('2', '1047');
|
||||
insert into sys_role_menu values ('2', '1048');
|
||||
insert into sys_role_menu values ('2', '1049');
|
||||
insert into sys_role_menu values ('2', '1050');
|
||||
insert into sys_role_menu values ('2', '1051');
|
||||
insert into sys_role_menu values ('2', '1052');
|
||||
insert into sys_role_menu values ('2', '1053');
|
||||
insert into sys_role_menu values ('2', '1054');
|
||||
insert into sys_role_menu values ('2', '1055');
|
||||
insert into sys_role_menu values ('2', '1056');
|
||||
insert into sys_role_menu values ('2', '1057');
|
||||
insert into sys_role_menu values ('2', '1058');
|
||||
insert into sys_role_menu values ('2', '1059');
|
||||
insert into sys_role_menu values ('2', '1060');
|
||||
|
||||
-- ----------------------------
|
||||
-- 8、角色和部门关联表 角色1-N部门
|
||||
-- ----------------------------
|
||||
drop table if exists sys_role_dept;
|
||||
create table sys_role_dept (
|
||||
role_id bigint(20) not null comment '角色ID',
|
||||
dept_id bigint(20) not null comment '部门ID',
|
||||
primary key(role_id, dept_id)
|
||||
) engine=innodb comment = '角色和部门关联表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化-角色和部门关联表数据
|
||||
-- ----------------------------
|
||||
insert into sys_role_dept values ('2', '100');
|
||||
insert into sys_role_dept values ('2', '101');
|
||||
insert into sys_role_dept values ('2', '105');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 9、用户与岗位关联表 用户1-N岗位
|
||||
-- ----------------------------
|
||||
drop table if exists sys_user_post;
|
||||
create table sys_user_post
|
||||
(
|
||||
user_id bigint(20) not null comment '用户ID',
|
||||
post_id bigint(20) not null comment '岗位ID',
|
||||
primary key (user_id, post_id)
|
||||
) engine=innodb comment = '用户与岗位关联表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化-用户与岗位关联表数据
|
||||
-- ----------------------------
|
||||
insert into sys_user_post values ('1', '1');
|
||||
insert into sys_user_post values ('2', '2');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 10、操作日志记录
|
||||
-- ----------------------------
|
||||
drop table if exists sys_oper_log;
|
||||
create table sys_oper_log (
|
||||
oper_id bigint(20) not null auto_increment comment '日志主键',
|
||||
title varchar(50) default '' comment '模块标题',
|
||||
business_type int(2) default 0 comment '业务类型(0其它 1新增 2修改 3删除)',
|
||||
method varchar(200) default '' comment '方法名称',
|
||||
request_method varchar(10) default '' comment '请求方式',
|
||||
operator_type int(1) default 0 comment '操作类别(0其它 1后台用户 2手机端用户)',
|
||||
oper_name varchar(50) default '' comment '操作人员',
|
||||
dept_name varchar(50) default '' comment '部门名称',
|
||||
oper_url varchar(255) default '' comment '请求URL',
|
||||
oper_ip varchar(128) default '' comment '主机地址',
|
||||
oper_location varchar(255) default '' comment '操作地点',
|
||||
oper_param varchar(2000) default '' comment '请求参数',
|
||||
json_result varchar(2000) default '' comment '返回参数',
|
||||
status int(1) default 0 comment '操作状态(0正常 1异常)',
|
||||
error_msg varchar(2000) default '' comment '错误消息',
|
||||
oper_time datetime comment '操作时间',
|
||||
cost_time bigint(20) default 0 comment '消耗时间',
|
||||
primary key (oper_id),
|
||||
key idx_sys_oper_log_bt (business_type),
|
||||
key idx_sys_oper_log_s (status),
|
||||
key idx_sys_oper_log_ot (oper_time)
|
||||
) engine=innodb auto_increment=100 comment = '操作日志记录';
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 11、字典类型表
|
||||
-- ----------------------------
|
||||
drop table if exists sys_dict_type;
|
||||
create table sys_dict_type
|
||||
(
|
||||
dict_id bigint(20) not null auto_increment comment '字典主键',
|
||||
dict_name varchar(100) default '' comment '字典名称',
|
||||
dict_type varchar(100) default '' comment '字典类型',
|
||||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
remark varchar(500) default null comment '备注',
|
||||
primary key (dict_id),
|
||||
unique (dict_type)
|
||||
) engine=innodb auto_increment=100 comment = '字典类型表';
|
||||
|
||||
insert into sys_dict_type values(1, '用户性别', 'sys_user_sex', '0', 'admin', sysdate(), '', null, '用户性别列表');
|
||||
insert into sys_dict_type values(2, '菜单状态', 'sys_show_hide', '0', 'admin', sysdate(), '', null, '菜单状态列表');
|
||||
insert into sys_dict_type values(3, '系统开关', 'sys_normal_disable', '0', 'admin', sysdate(), '', null, '系统开关列表');
|
||||
insert into sys_dict_type values(4, '任务状态', 'sys_job_status', '0', 'admin', sysdate(), '', null, '任务状态列表');
|
||||
insert into sys_dict_type values(5, '任务分组', 'sys_job_group', '0', 'admin', sysdate(), '', null, '任务分组列表');
|
||||
insert into sys_dict_type values(6, '系统是否', 'sys_yes_no', '0', 'admin', sysdate(), '', null, '系统是否列表');
|
||||
insert into sys_dict_type values(7, '通知类型', 'sys_notice_type', '0', 'admin', sysdate(), '', null, '通知类型列表');
|
||||
insert into sys_dict_type values(8, '通知状态', 'sys_notice_status', '0', 'admin', sysdate(), '', null, '通知状态列表');
|
||||
insert into sys_dict_type values(9, '操作类型', 'sys_oper_type', '0', 'admin', sysdate(), '', null, '操作类型列表');
|
||||
insert into sys_dict_type values(10, '系统状态', 'sys_common_status', '0', 'admin', sysdate(), '', null, '登录状态列表');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 12、字典数据表
|
||||
-- ----------------------------
|
||||
drop table if exists sys_dict_data;
|
||||
create table sys_dict_data
|
||||
(
|
||||
dict_code bigint(20) not null auto_increment comment '字典编码',
|
||||
dict_sort int(4) default 0 comment '字典排序',
|
||||
dict_label varchar(100) default '' comment '字典标签',
|
||||
dict_value varchar(100) default '' comment '字典键值',
|
||||
dict_type varchar(100) default '' comment '字典类型',
|
||||
css_class varchar(100) default null comment '样式属性(其他样式扩展)',
|
||||
list_class varchar(100) default null comment '表格回显样式',
|
||||
is_default char(1) default 'N' comment '是否默认(Y是 N否)',
|
||||
status char(1) default '0' comment '状态(0正常 1停用)',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
remark varchar(500) default null comment '备注',
|
||||
primary key (dict_code)
|
||||
) engine=innodb auto_increment=100 comment = '字典数据表';
|
||||
|
||||
insert into sys_dict_data values(1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', sysdate(), '', null, '性别男');
|
||||
insert into sys_dict_data values(2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别女');
|
||||
insert into sys_dict_data values(3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', sysdate(), '', null, '性别未知');
|
||||
insert into sys_dict_data values(4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '显示菜单');
|
||||
insert into sys_dict_data values(5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '隐藏菜单');
|
||||
insert into sys_dict_data values(6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');
|
||||
insert into sys_dict_data values(7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态');
|
||||
insert into sys_dict_data values(8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');
|
||||
insert into sys_dict_data values(9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态');
|
||||
insert into sys_dict_data values(10, 1, '默认', 'DEFAULT', 'sys_job_group', '', '', 'Y', '0', 'admin', sysdate(), '', null, '默认分组');
|
||||
insert into sys_dict_data values(11, 2, '系统', 'SYSTEM', 'sys_job_group', '', '', 'N', '0', 'admin', sysdate(), '', null, '系统分组');
|
||||
insert into sys_dict_data values(12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '系统默认是');
|
||||
insert into sys_dict_data values(13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '系统默认否');
|
||||
insert into sys_dict_data values(14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', sysdate(), '', null, '通知');
|
||||
insert into sys_dict_data values(15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', sysdate(), '', null, '公告');
|
||||
insert into sys_dict_data values(16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', sysdate(), '', null, '正常状态');
|
||||
insert into sys_dict_data values(17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '关闭状态');
|
||||
insert into sys_dict_data values(18, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '其他操作');
|
||||
insert into sys_dict_data values(19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '新增操作');
|
||||
insert into sys_dict_data values(20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', sysdate(), '', null, '修改操作');
|
||||
insert into sys_dict_data values(21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '删除操作');
|
||||
insert into sys_dict_data values(22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '授权操作');
|
||||
insert into sys_dict_data values(23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导出操作');
|
||||
insert into sys_dict_data values(24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '导入操作');
|
||||
insert into sys_dict_data values(25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '强退操作');
|
||||
insert into sys_dict_data values(26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', sysdate(), '', null, '生成操作');
|
||||
insert into sys_dict_data values(27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '清空操作');
|
||||
insert into sys_dict_data values(28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', sysdate(), '', null, '正常状态');
|
||||
insert into sys_dict_data values(29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', sysdate(), '', null, '停用状态');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 13、参数配置表
|
||||
-- ----------------------------
|
||||
drop table if exists sys_config;
|
||||
create table sys_config (
|
||||
config_id int(5) not null auto_increment comment '参数主键',
|
||||
config_name varchar(100) default '' comment '参数名称',
|
||||
config_key varchar(100) default '' comment '参数键名',
|
||||
config_value varchar(500) default '' comment '参数键值',
|
||||
config_type char(1) default 'N' comment '系统内置(Y是 N否)',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
remark varchar(500) default null comment '备注',
|
||||
primary key (config_id)
|
||||
) engine=innodb auto_increment=100 comment = '参数配置表';
|
||||
|
||||
insert into sys_config values(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', sysdate(), '', null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' );
|
||||
insert into sys_config values(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', sysdate(), '', null, '初始化密码 123456' );
|
||||
insert into sys_config values(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', sysdate(), '', null, '深色主题theme-dark,浅色主题theme-light' );
|
||||
insert into sys_config values(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', sysdate(), '', null, '是否开启验证码功能(true开启,false关闭)');
|
||||
insert into sys_config values(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能(true开启,false关闭)');
|
||||
insert into sys_config values(6, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)');
|
||||
insert into sys_config values(7, '用户管理-初始密码修改策略', 'sys.account.initPasswordModify', '1', 'Y', 'admin', sysdate(), '', null, '0:初始密码修改策略关闭,没有任何提示,1:提醒用户,如果未修改初始密码,则在登录时就会提醒修改密码对话框');
|
||||
insert into sys_config values(8, '用户管理-账号密码更新周期', 'sys.account.passwordValidateDays', '0', 'Y', 'admin', sysdate(), '', null, '密码更新周期(填写数字,数据初始化值为0不限制,若修改必须为大于0小于365的正整数),如果超过这个周期登录系统时,则在登录时就会提醒修改密码对话框');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 14、系统访问记录
|
||||
-- ----------------------------
|
||||
drop table if exists sys_logininfor;
|
||||
create table sys_logininfor (
|
||||
info_id bigint(20) not null auto_increment comment '访问ID',
|
||||
user_name varchar(50) default '' comment '用户账号',
|
||||
ipaddr varchar(128) default '' comment '登录IP地址',
|
||||
login_location varchar(255) default '' comment '登录地点',
|
||||
browser varchar(50) default '' comment '浏览器类型',
|
||||
os varchar(50) default '' comment '操作系统',
|
||||
status char(1) default '0' comment '登录状态(0成功 1失败)',
|
||||
msg varchar(255) default '' comment '提示消息',
|
||||
login_time datetime comment '访问时间',
|
||||
primary key (info_id),
|
||||
key idx_sys_logininfor_s (status),
|
||||
key idx_sys_logininfor_lt (login_time)
|
||||
) engine=innodb auto_increment=100 comment = '系统访问记录';
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 15、定时任务调度表
|
||||
-- ----------------------------
|
||||
drop table if exists sys_job;
|
||||
create table sys_job (
|
||||
job_id bigint(20) not null auto_increment comment '任务ID',
|
||||
job_name varchar(64) default '' comment '任务名称',
|
||||
job_group varchar(64) default 'DEFAULT' comment '任务组名',
|
||||
invoke_target varchar(500) not null comment '调用目标字符串',
|
||||
cron_expression varchar(255) default '' comment 'cron执行表达式',
|
||||
misfire_policy varchar(20) default '3' comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
|
||||
concurrent char(1) default '1' comment '是否并发执行(0允许 1禁止)',
|
||||
status char(1) default '0' comment '状态(0正常 1暂停)',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
remark varchar(500) default '' comment '备注信息',
|
||||
primary key (job_id, job_name, job_group)
|
||||
) engine=innodb auto_increment=100 comment = '定时任务调度表';
|
||||
|
||||
insert into sys_job values(1, '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_job values(2, '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(\'ry\')', '0/15 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
|
||||
insert into sys_job values(3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 16、定时任务调度日志表
|
||||
-- ----------------------------
|
||||
drop table if exists sys_job_log;
|
||||
create table sys_job_log (
|
||||
job_log_id bigint(20) not null auto_increment comment '任务日志ID',
|
||||
job_name varchar(64) not null comment '任务名称',
|
||||
job_group varchar(64) not null comment '任务组名',
|
||||
invoke_target varchar(500) not null comment '调用目标字符串',
|
||||
job_message varchar(500) comment '日志信息',
|
||||
status char(1) default '0' comment '执行状态(0正常 1失败)',
|
||||
exception_info varchar(2000) default '' comment '异常信息',
|
||||
create_time datetime comment '创建时间',
|
||||
primary key (job_log_id)
|
||||
) engine=innodb comment = '定时任务调度日志表';
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 17、通知公告表
|
||||
-- ----------------------------
|
||||
drop table if exists sys_notice;
|
||||
create table sys_notice (
|
||||
notice_id int(4) not null auto_increment comment '公告ID',
|
||||
notice_title varchar(50) not null comment '公告标题',
|
||||
notice_type char(1) not null comment '公告类型(1通知 2公告)',
|
||||
notice_content longblob default null comment '公告内容',
|
||||
status char(1) default '0' comment '公告状态(0正常 1关闭)',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
remark varchar(255) default null comment '备注',
|
||||
primary key (notice_id)
|
||||
) engine=innodb auto_increment=10 comment = '通知公告表';
|
||||
|
||||
-- ----------------------------
|
||||
-- 初始化-公告信息表数据
|
||||
-- ----------------------------
|
||||
insert into sys_notice values('1', '温馨提醒:2018-07-01 若依新版本发布啦', '2', '新版本内容', '0', 'admin', sysdate(), '', null, '管理员');
|
||||
insert into sys_notice values('2', '维护通知:2018-07-01 若依系统凌晨维护', '1', '维护内容', '0', 'admin', sysdate(), '', null, '管理员');
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 18、代码生成业务表
|
||||
-- ----------------------------
|
||||
drop table if exists gen_table;
|
||||
create table gen_table (
|
||||
table_id bigint(20) not null auto_increment comment '编号',
|
||||
table_name varchar(200) default '' comment '表名称',
|
||||
table_comment varchar(500) default '' comment '表描述',
|
||||
sub_table_name varchar(64) default null comment '关联子表的表名',
|
||||
sub_table_fk_name varchar(64) default null comment '子表关联的外键名',
|
||||
class_name varchar(100) default '' comment '实体类名称',
|
||||
tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)',
|
||||
tpl_web_type varchar(30) default '' comment '前端模板类型(element-ui模版 element-plus模版)',
|
||||
package_name varchar(100) comment '生成包路径',
|
||||
module_name varchar(30) comment '生成模块名',
|
||||
business_name varchar(30) comment '生成业务名',
|
||||
function_name varchar(50) comment '生成功能名',
|
||||
function_author varchar(50) comment '生成功能作者',
|
||||
gen_type char(1) default '0' comment '生成代码方式(0zip压缩包 1自定义路径)',
|
||||
gen_path varchar(200) default '/' comment '生成路径(不填默认项目路径)',
|
||||
options varchar(1000) comment '其它生成选项',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
remark varchar(500) default null comment '备注',
|
||||
primary key (table_id)
|
||||
) engine=innodb auto_increment=1 comment = '代码生成业务表';
|
||||
|
||||
|
||||
-- ----------------------------
|
||||
-- 19、代码生成业务表字段
|
||||
-- ----------------------------
|
||||
drop table if exists gen_table_column;
|
||||
create table gen_table_column (
|
||||
column_id bigint(20) not null auto_increment comment '编号',
|
||||
table_id bigint(20) comment '归属表编号',
|
||||
column_name varchar(200) comment '列名称',
|
||||
column_comment varchar(500) comment '列描述',
|
||||
column_type varchar(100) comment '列类型',
|
||||
java_type varchar(500) comment 'JAVA类型',
|
||||
java_field varchar(200) comment 'JAVA字段名',
|
||||
is_pk char(1) comment '是否主键(1是)',
|
||||
is_increment char(1) comment '是否自增(1是)',
|
||||
is_required char(1) comment '是否必填(1是)',
|
||||
is_insert char(1) comment '是否为插入字段(1是)',
|
||||
is_edit char(1) comment '是否编辑字段(1是)',
|
||||
is_list char(1) comment '是否列表字段(1是)',
|
||||
is_query char(1) comment '是否查询字段(1是)',
|
||||
query_type varchar(200) default 'EQ' comment '查询方式(等于、不等于、大于、小于、范围)',
|
||||
html_type varchar(200) comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)',
|
||||
dict_type varchar(200) default '' comment '字典类型',
|
||||
sort int comment '排序',
|
||||
create_by varchar(64) default '' comment '创建者',
|
||||
create_time datetime comment '创建时间',
|
||||
update_by varchar(64) default '' comment '更新者',
|
||||
update_time datetime comment '更新时间',
|
||||
primary key (column_id)
|
||||
) engine=innodb auto_increment=1 comment = '代码生成业务表字段';
|
||||
|
||||
-- ----------------------------
|
||||
-- 贷款定价菜单初始化
|
||||
-- ----------------------------
|
||||
DELETE FROM sys_role_menu WHERE menu_id IN (2000, 2001, 2002);
|
||||
DELETE FROM sys_menu WHERE menu_id IN (2000, 2001, 2002);
|
||||
|
||||
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
VALUES(2000, '利率定价管理', 0, 5, 'loanPricing', NULL, 1, 0, 'M', '0', '0', '', 'money', 'admin', NOW(), '');
|
||||
|
||||
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
VALUES(2001, '流程列表', 2000, 1, 'workflow', 'loanPricing/workflow/index', 1, 0, 'C', '0', '0', 'loanPricing:workflow:list', 'list', 'admin', NOW(), '');
|
||||
|
||||
INSERT INTO sys_menu(menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark)
|
||||
VALUES(2002, '流程查询', 2001, 1, '', '', 1, 0, 'F', '0', '0', 'loanPricing:workflow:query', '#', 'admin', NOW(), '');
|
||||
|
||||
INSERT INTO sys_role_menu VALUES(1, 2000), (1, 2001), (1, 2002);
|
||||
|
||||
-- Table structure for table `loan_pricing_workflow`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `loan_pricing_workflow`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `loan_pricing_workflow` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`serial_num` varchar(50) NOT NULL COMMENT '业务方流水号',
|
||||
`model_output_id` bigint(20) DEFAULT NULL COMMENT '模型输出ID',
|
||||
`org_code` varchar(20) NOT NULL DEFAULT '892000' COMMENT '机构编码(统一值892000)',
|
||||
`run_type` varchar(10) NOT NULL DEFAULT '1' COMMENT '运行模式: 1-同步',
|
||||
`cust_isn` varchar(50) NOT NULL COMMENT '客户内码',
|
||||
`cust_type` varchar(20) NOT NULL COMMENT '客户类型: 个人/企业',
|
||||
`guar_type` varchar(20) NOT NULL COMMENT '担保方式: 信用/保证/抵押/质押',
|
||||
`mid_per_quick_pay` varchar(10) DEFAULT NULL COMMENT '中间业务_个人_快捷支付: true/false',
|
||||
`mid_per_ele_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_个人_电费代扣: true/false',
|
||||
`mid_ent_ele_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_企业_电费代扣: true/false',
|
||||
`mid_ent_water_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_企业_水费代扣: true/false',
|
||||
`apply_amt` varchar(50) NOT NULL COMMENT '申请金额(元)',
|
||||
`loan_term` varchar(50) DEFAULT NULL COMMENT '贷款期限',
|
||||
`is_clean_ent` varchar(10) DEFAULT NULL COMMENT '净身企业: true/false',
|
||||
`has_settle_acct` varchar(10) DEFAULT NULL COMMENT '开立基本结算账户: true/false',
|
||||
`is_manufacturing` varchar(10) DEFAULT NULL COMMENT '制造业企业: true/false',
|
||||
`is_agri_guar` varchar(10) DEFAULT NULL COMMENT '省农担担保贷款: true/false',
|
||||
`is_tech_ent` varchar(10) DEFAULT NULL COMMENT '科技型企业: true/false(科技型企业最多下降5BP)',
|
||||
`is_green_loan` varchar(10) DEFAULT NULL COMMENT '绿色贷款: true/false(绿色贷款最多下降5BP)',
|
||||
`is_trade_construction` varchar(10) DEFAULT NULL COMMENT '贸易和建筑业企业标识: true/false(抵质押类上调20BP)',
|
||||
`is_tax_a` varchar(10) DEFAULT NULL COMMENT '是否纳税信用等级A级: true/false',
|
||||
`is_agri_leading` varchar(10) DEFAULT NULL COMMENT '是否县级及以上农业龙头企业: true/false',
|
||||
`loan_purpose` varchar(20) DEFAULT NULL COMMENT '贷款用途: consumer-消费/business-经营',
|
||||
`biz_proof` varchar(10) DEFAULT NULL COMMENT '是否有经营佐证: true/false',
|
||||
`loan_loop` varchar(10) DEFAULT NULL COMMENT '循环功能: true/false(贷款合同是否开通循环功能)',
|
||||
`coll_type` varchar(20) DEFAULT NULL COMMENT '抵质押类型: 一线/一类/二类',
|
||||
`coll_third_party` varchar(10) DEFAULT NULL COMMENT '抵质押物是否三方所有: true/false',
|
||||
`loan_rate` varchar(20) DEFAULT NULL COMMENT '贷款利率',
|
||||
`execute_rate` varchar(20) DEFAULT NULL COMMENT '执行利率(%)',
|
||||
`cust_name` varchar(100) DEFAULT NULL COMMENT '客户名称',
|
||||
`id_type` varchar(50) DEFAULT NULL COMMENT '证件类型',
|
||||
`id_num` varchar(100) DEFAULT NULL COMMENT '证件号码',
|
||||
`is_inclusive_finance` varchar(10) DEFAULT NULL COMMENT '是否普惠小微借款人: true/false',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_serial_num` (`serial_num`),
|
||||
KEY `idx_org_code` (`org_code`),
|
||||
KEY `idx_create_by` (`create_by`),
|
||||
KEY `idx_cust_name` (`cust_name`),
|
||||
KEY `idx_update_time` (`update_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='利率定价流程表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `model_corp_output_fields`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `model_corp_output_fields`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `model_corp_output_fields` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键ID',
|
||||
`cust_isn` varchar(100) DEFAULT NULL COMMENT '客户内码',
|
||||
`cust_type` varchar(100) DEFAULT NULL COMMENT '客户类型',
|
||||
`guar_type` varchar(100) DEFAULT NULL COMMENT '担保方式',
|
||||
`cust_name` varchar(100) DEFAULT NULL COMMENT '客户名称',
|
||||
`id_type` varchar(100) DEFAULT NULL COMMENT '证件类型',
|
||||
`id_num` varchar(100) DEFAULT NULL COMMENT '证件号码',
|
||||
`base_loan_rate` varchar(100) DEFAULT NULL COMMENT '基准利率',
|
||||
`is_first_loan` varchar(100) DEFAULT NULL COMMENT '我行首贷客户',
|
||||
`faith_day` varchar(100) DEFAULT NULL COMMENT '用信天数',
|
||||
`bp_first_loan` varchar(100) DEFAULT NULL COMMENT 'BP_首贷',
|
||||
`bp_age_loan` varchar(100) DEFAULT NULL COMMENT 'BP_贷龄',
|
||||
`total_bp_loyalty` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_忠诚度',
|
||||
`balance_avg` varchar(100) DEFAULT NULL COMMENT '存款年日均',
|
||||
`loan_avg` varchar(100) DEFAULT NULL COMMENT '贷款年日均',
|
||||
`derivation_rate` varchar(100) DEFAULT NULL COMMENT '派生率',
|
||||
`total_bp_contribution` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_贡献度',
|
||||
`mid_ent_connect` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_企业互联',
|
||||
`mid_ent_effect` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_有效价值客户',
|
||||
`mid_ent_inter` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_国际业务',
|
||||
`mid_ent_accept` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_承兑',
|
||||
`mid_ent_discount` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_贴现',
|
||||
`mid_ent_ele_ddc` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_电费代扣',
|
||||
`mid_ent_water_ddc` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_水费代扣',
|
||||
`mid_ent_tax` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_税务代扣',
|
||||
`bp_mid` varchar(100) DEFAULT NULL COMMENT 'BP_中间业务',
|
||||
`payroll` varchar(100) DEFAULT NULL COMMENT '代发工资户数',
|
||||
`inv_loan_amount` varchar(100) DEFAULT NULL COMMENT '存量贷款余额',
|
||||
`bp_payroll` varchar(100) DEFAULT NULL COMMENT 'BP_代发工资',
|
||||
`is_clean_ent` varchar(100) DEFAULT NULL COMMENT '净身企业',
|
||||
`has_settle_acct` varchar(100) DEFAULT NULL COMMENT '开立基本结算账户',
|
||||
`is_agri_guar` varchar(100) DEFAULT NULL COMMENT '省农担担保贷款',
|
||||
`is_green_loan` varchar(100) DEFAULT NULL COMMENT '绿色贷款',
|
||||
`is_tech_ent` varchar(100) DEFAULT NULL COMMENT '科技型企业',
|
||||
`bp_ent_type` varchar(100) DEFAULT NULL COMMENT 'BP_企业客户类别',
|
||||
`totoal_bp_relevance` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_关联度',
|
||||
`loan_term` varchar(100) DEFAULT NULL COMMENT '贷款期限',
|
||||
`bp_loan_term` varchar(100) DEFAULT NULL COMMENT 'BP_贷款期限',
|
||||
`apply_amt` varchar(100) DEFAULT NULL COMMENT '申请金额',
|
||||
`bp_loan_amount` varchar(100) DEFAULT NULL COMMENT 'BP_贷款额度',
|
||||
`coll_type` varchar(100) DEFAULT NULL COMMENT '抵质押类型',
|
||||
`coll_third_party` varchar(100) DEFAULT NULL COMMENT '抵质押物是否三方所有',
|
||||
`bp_collateral` varchar(100) DEFAULT NULL COMMENT 'BP_抵押物',
|
||||
`grey_cust` varchar(100) DEFAULT NULL COMMENT '灰名单客户',
|
||||
`prin_overdue` varchar(100) DEFAULT NULL COMMENT '本金逾期',
|
||||
`interest_overdue` varchar(100) DEFAULT NULL COMMENT '利息逾期',
|
||||
`card_overdue` varchar(100) DEFAULT NULL COMMENT '信用卡逾期',
|
||||
`bp_grey_overdue` varchar(100) DEFAULT NULL COMMENT 'BP_灰名单与逾期',
|
||||
`totoal_bp_risk` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_风险度',
|
||||
`total_bp` varchar(100) DEFAULT NULL COMMENT '浮动BP',
|
||||
`calculate_rate` varchar(100) DEFAULT NULL COMMENT '测算利率',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='客户贷款利率测算表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `model_retail_output_fields`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `model_retail_output_fields`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `model_retail_output_fields` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`cust_isn` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '客户内码',
|
||||
`cust_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '客户类型',
|
||||
`guar_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '担保方式',
|
||||
`cust_name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '客户名称',
|
||||
`id_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '证件类型',
|
||||
`id_num` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '证件号码',
|
||||
`base_loan_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '基准利率',
|
||||
`is_first_loan` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '我行首贷客户',
|
||||
`faith_day` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用信天数',
|
||||
`cust_age` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '客户年龄',
|
||||
`bp_first_loan` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_首贷',
|
||||
`bp_age_loan` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_贷龄',
|
||||
`bp_age` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_年龄',
|
||||
`total_bp_loyalty` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_忠诚度',
|
||||
`balance_avg` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '存款年日均',
|
||||
`loan_avg` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '贷款年日均',
|
||||
`derivation_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '派生率',
|
||||
`total_bp_contribution` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_贡献度',
|
||||
`mid_per_card` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_信用卡',
|
||||
`mid_per_pass` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_一码通',
|
||||
`mid_per_harvest` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_丰收互联',
|
||||
`mid_per_effect` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_有效客户',
|
||||
`mid_per_quick_pay` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_快捷支付',
|
||||
`mid_per_ele_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_电费代扣',
|
||||
`mid_per_water_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_水费代扣',
|
||||
`mid_per_huashu_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_华数费代扣',
|
||||
`mid_per_gas_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_煤气费代扣',
|
||||
`mid_per_citizencard` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_市民卡',
|
||||
`mid_per_fin_man` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_理财业务',
|
||||
`mid_per_etc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_etc',
|
||||
`bp_mid` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_中间业务',
|
||||
`totoal_bp_relevance` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_关联度',
|
||||
`apply_amt` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '申请金额',
|
||||
`bp_loan_amount` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_贷款额度',
|
||||
`loan_purpose` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '贷款用途',
|
||||
`biz_proof` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '是否有经营佐证',
|
||||
`bp_loan_use` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_贷款用途',
|
||||
`loan_loop` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '循环功能',
|
||||
`bp_loan_loop` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_循环功能',
|
||||
`coll_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '抵质押类型',
|
||||
`coll_third_party` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '抵质押物是否三方所有',
|
||||
`bp_collateral` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_抵押物',
|
||||
`grey_cust` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '灰名单客户',
|
||||
`prin_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '本金逾期',
|
||||
`interest_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '利息逾期',
|
||||
`card_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '信用卡逾期',
|
||||
`bp_grey_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_灰名单与逾期',
|
||||
`totoal_bp_risk` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_风险度',
|
||||
`total_bp` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '浮动BP',
|
||||
`calculate_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '测算利率',
|
||||
`loan_rate_history` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '历史利率',
|
||||
`min_rate_product` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '产品最低利率下限',
|
||||
`smooth_range` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '平滑幅度',
|
||||
`final_calculate_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '最终测算利率',
|
||||
`reference_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '参考利率',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='零售模型输出字段表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
373
sql/loan_pricing_required_data_20260328.sql
Normal file
373
sql/loan_pricing_required_data_20260328.sql
Normal file
@@ -0,0 +1,373 @@
|
||||
-- 说明:
|
||||
-- 1. 本文件从源库 116.62.17.81:3306/loan-pricing 以 utf8mb4 正确导出
|
||||
-- 2. 本文件仅包含迁移后系统可运行所需的基础配置数据和当前业务关键数据
|
||||
-- 3. 已包含的表: loan_pricing_workflow, model_corp_output_fields, model_retail_output_fields,
|
||||
-- sys_config, sys_dept, sys_dict_data, sys_dict_type, sys_job, sys_menu, sys_notice,
|
||||
-- sys_post, sys_role, sys_role_dept, sys_role_menu, sys_user, sys_user_post, sys_user_role
|
||||
-- 4. 未包含日志和运行态数据: sys_job_log, sys_logininfor, sys_oper_log, QRTZ_* 运行态表
|
||||
-- 5. 建议先执行表结构 SQL, 再执行本文件
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
USE `loan-pricing`;
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
DELETE FROM `loan_pricing_workflow`;
|
||||
INSERT INTO `loan_pricing_workflow` (`id`, `serial_num`, `model_output_id`, `org_code`, `run_type`, `cust_isn`, `cust_type`, `guar_type`, `mid_per_quick_pay`, `mid_per_ele_ddc`, `mid_ent_ele_ddc`, `mid_ent_water_ddc`, `apply_amt`, `loan_term`, `is_clean_ent`, `has_settle_acct`, `is_manufacturing`, `is_agri_guar`, `is_tech_ent`, `is_green_loan`, `is_trade_construction`, `is_tax_a`, `is_agri_leading`, `loan_purpose`, `biz_proof`, `loan_loop`, `coll_type`, `coll_third_party`, `loan_rate`, `execute_rate`, `cust_name`, `id_type`, `id_num`, `is_inclusive_finance`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES
|
||||
(1, '20260130160640382', 1, '892000', '1', '1234', '个人', '信用', 'false', 'false', 'false', 'false', '10000000', NULL, 'false', 'false', 'false', 'false', NULL, NULL, NULL, 'false', 'false', NULL, 'false', NULL, NULL, 'false', '11', NULL, NULL, '身份证', NULL, 'false', '若依-admin', '2026-01-30 16:06:40', '若依-admin', '2026-01-30 16:06:41'),
|
||||
(2, '20260130163824202', 1, '892000', '1', '82821892198', '企业', '保证', 'false', 'false', 'false', 'false', '100000', NULL, 'false', 'false', 'false', 'false', NULL, NULL, NULL, 'false', 'false', 'consumer', 'false', NULL, NULL, 'false', '10', '4.5', '吴总', '统一社会信用代码', NULL, 'false', '若依-admin', '2026-01-30 16:38:24', '若依-admin', '2026-01-30 16:39:10'),
|
||||
(3, '20260202140048990', 2, '892000', '1', 'TEST001', '个人', '信用', NULL, NULL, NULL, NULL, '500000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'true', 'false', NULL, NULL, NULL, NULL, '张三', '身份证', '110101199001011234', NULL, '若依-admin', '2026-02-02 14:00:49', '若依-admin', '2026-02-02 14:00:50'),
|
||||
(4, '20260202140101592', 3, '892000', '1', 'TEST002', '个人', '质押', NULL, NULL, NULL, NULL, '100000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '若依-admin', '2026-02-02 14:01:02', '若依-admin', '2026-02-02 14:01:02'),
|
||||
(5, '20260202140102337', 4, '892000', '1', 'TEST003', '个人', '抵押', NULL, NULL, NULL, NULL, '800000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'true', 'true', '一类', 'false', NULL, NULL, '孙七', '身份证', '110101199001011239', NULL, '若依-admin', '2026-02-02 14:01:02', '若依-admin', '2026-02-02 14:01:03'),
|
||||
(6, '20260202140119035', 2, '892000', '1', 'CORP001', '企业', '抵押', NULL, NULL, NULL, NULL, '1000000', '36', NULL, NULL, NULL, 'false', 'true', 'true', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '测试科技有限公司', '统一社会信用代码', '91110000100000000X', NULL, '若依-admin', '2026-02-02 14:01:19', '若依-admin', '2026-02-02 14:01:19'),
|
||||
(7, '20260202140128799', 3, '892000', '1', 'CORP007', '企业', '信用', NULL, NULL, NULL, NULL, '3000000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '若依-admin', '2026-02-02 14:01:29', '若依-admin', '2026-02-02 14:01:29'),
|
||||
(8, '20260202140129480', 4, '892000', '1', 'CORP005', '企业', '保证', NULL, NULL, NULL, NULL, '2000000', '60', NULL, NULL, NULL, 'true', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '农业科技有限公司', '统一社会信用代码', '91110000100000005X', NULL, '若依-admin', '2026-02-02 14:01:29', '若依-admin', '2026-02-02 14:01:30'),
|
||||
(9, '20260202140138984', 5, '892000', '1', 'OLD001', '个人', '信用', NULL, NULL, NULL, NULL, '500000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'true', 'false', NULL, NULL, '4.5', NULL, '测试用户1', '身份证', NULL, NULL, '若依-admin', '2026-02-02 14:01:39', '若依-admin', '2026-02-02 14:01:39'),
|
||||
(10, '20260202140145591', 5, '892000', '1', 'OLD002', '企业', '抵押', NULL, NULL, NULL, NULL, '1000000', '36', NULL, NULL, NULL, 'false', 'true', 'true', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, '4.0', NULL, '测试企业1', '统一社会信用代码', NULL, NULL, '若依-admin', '2026-02-02 14:01:46', '若依-admin', '2026-02-02 14:01:46'),
|
||||
(11, '20260202144250835', 6, '892000', '1', '1234567', '个人', '信用', NULL, NULL, NULL, NULL, '100000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'true', 'true', '一线', 'true', NULL, NULL, '个人测试', '身份证', '330103199912311231', NULL, '若依-admin', '2026-02-02 14:42:51', '若依-admin', '2026-02-02 14:42:51'),
|
||||
(12, '20260202151445788', 6, '892000', '1', 'test1234', '企业', '信用', NULL, NULL, NULL, NULL, '200000', '23', NULL, NULL, NULL, 'true', 'true', 'true', 'true', NULL, NULL, NULL, NULL, NULL, '一线', 'true', NULL, NULL, 'test1234', '统一社会信用代码', '91110000100000000X', NULL, '若依-admin', '2026-02-02 15:14:46', '若依-admin', '2026-02-02 15:14:46');
|
||||
|
||||
DELETE FROM `model_corp_output_fields`;
|
||||
INSERT INTO `model_corp_output_fields` (`id`, `cust_isn`, `cust_type`, `guar_type`, `cust_name`, `id_type`, `id_num`, `base_loan_rate`, `is_first_loan`, `faith_day`, `bp_first_loan`, `bp_age_loan`, `total_bp_loyalty`, `balance_avg`, `loan_avg`, `derivation_rate`, `total_bp_contribution`, `mid_ent_connect`, `mid_ent_effect`, `mid_ent_inter`, `mid_ent_accept`, `mid_ent_discount`, `mid_ent_ele_ddc`, `mid_ent_water_ddc`, `mid_ent_tax`, `bp_mid`, `payroll`, `inv_loan_amount`, `bp_payroll`, `is_clean_ent`, `has_settle_acct`, `is_agri_guar`, `is_green_loan`, `is_tech_ent`, `bp_ent_type`, `totoal_bp_relevance`, `loan_term`, `bp_loan_term`, `apply_amt`, `bp_loan_amount`, `coll_type`, `coll_third_party`, `bp_collateral`, `grey_cust`, `prin_overdue`, `interest_overdue`, `card_overdue`, `bp_grey_overdue`, `totoal_bp_risk`, `total_bp`, `calculate_rate`, `create_time`) VALUES
|
||||
(1, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-01-30 16:38:24'),
|
||||
(2, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-02-02 14:01:19'),
|
||||
(3, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-02-02 14:01:29'),
|
||||
(4, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-02-02 14:01:30'),
|
||||
(5, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-02-02 14:01:46'),
|
||||
(6, 'CUST20260121001', '企业客户', '抵押担保', '北京智联科技有限公司', '营业执照', '91110108MA00XXXXXX', '3.45', 'N', '730', '0', '5.2', '8.5', '5000000.00', '3000000.00', '1.8', '12.3', '100000.00', '50000.00', '80000.00', '200000.00', '150000.00', '30000.00', '10000.00', '40000.00', '6.8', '200', '2500000.00', '4.1', 'Y', 'Y', 'N', 'Y', 'Y', '7.5', '9.2', '36', '3.3', '5000000.00', '5.8', '房产抵押', 'N', '4.5', 'N', 'N', 'N', 'N', '0', '1.2', '48.2', '3.932', '2026-02-02 15:14:46');
|
||||
|
||||
DELETE FROM `model_retail_output_fields`;
|
||||
INSERT INTO `model_retail_output_fields` (`id`, `cust_isn`, `cust_type`, `guar_type`, `cust_name`, `id_type`, `id_num`, `base_loan_rate`, `is_first_loan`, `faith_day`, `cust_age`, `bp_first_loan`, `bp_age_loan`, `bp_age`, `total_bp_loyalty`, `balance_avg`, `loan_avg`, `derivation_rate`, `total_bp_contribution`, `mid_per_card`, `mid_per_pass`, `mid_per_harvest`, `mid_per_effect`, `mid_per_quick_pay`, `mid_per_ele_ddc`, `mid_per_water_ddc`, `mid_per_huashu_ddc`, `mid_per_gas_ddc`, `mid_per_citizencard`, `mid_per_fin_man`, `mid_per_etc`, `bp_mid`, `totoal_bp_relevance`, `apply_amt`, `bp_loan_amount`, `loan_purpose`, `biz_proof`, `bp_loan_use`, `loan_loop`, `bp_loan_loop`, `coll_type`, `coll_third_party`, `bp_collateral`, `grey_cust`, `prin_overdue`, `interest_overdue`, `card_overdue`, `bp_grey_overdue`, `totoal_bp_risk`, `total_bp`, `calculate_rate`, `create_time`) VALUES
|
||||
(1, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '是', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '是', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '有', '55', '支持', '40', '无抵质押', '否', '0', '否', '否', '否', '否', '98', '95', '350', '6.15', '2026-01-30 16:06:41'),
|
||||
(2, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '是', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '是', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '有', '55', '支持', '40', '无抵质押', '否', '0', '否', '否', '否', '否', '98', '95', '350', '6.15', '2026-02-02 14:00:49'),
|
||||
(3, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '是', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '是', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '有', '55', '支持', '40', '无抵质押', '否', '0', '否', '否', '否', '否', '98', '95', '350', '6.15', '2026-02-02 14:01:02'),
|
||||
(4, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '是', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '是', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '有', '55', '支持', '40', '无抵质押', '否', '0', '否', '否', '否', '否', '98', '95', '350', '6.15', '2026-02-02 14:01:03'),
|
||||
(5, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '是', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '是', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '有', '55', '支持', '40', '无抵质押', '否', '0', '否', '否', '否', '否', '98', '95', '350', '6.15', '2026-02-02 14:01:39'),
|
||||
(6, 'CUST20260121001', '个人', '信用担保', '张三', '身份证', '330106199001011234', '4.35', '是', '365', '36', '50', '30', '20', '95', '50000.00', '100000.00', '1.2', '88', '1000.50', '500.00', '800.20', '是', '300.00', '150.00', '80.00', '120.00', '90.00', '200.00', '5000.00', '180.00', '45', '90', '200000.00', '60', '个人消费', '有', '55', '支持', '40', '无抵质押', '否', '0', '否', '否', '否', '否', '98', '95', '350', '6.15', '2026-02-02 14:42:51');
|
||||
|
||||
DELETE FROM `sys_config`;
|
||||
INSERT INTO `sys_config` (`config_id`, `config_name`, `config_key`, `config_value`, `config_type`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
|
||||
(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', '2026-01-30 07:57:17', '', NULL, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow'),
|
||||
(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', '2026-01-30 07:57:18', '', NULL, '初始化密码 123456'),
|
||||
(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', '2026-01-30 07:57:18', '', NULL, '深色主题theme-dark,浅色主题theme-light'),
|
||||
(4, '账号自助-验证码开关', 'sys.account.captchaEnabled', 'true', 'Y', 'admin', '2026-01-30 07:57:18', '', NULL, '是否开启验证码功能(true开启,false关闭)'),
|
||||
(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser', 'false', 'Y', 'admin', '2026-01-30 07:57:19', '', NULL, '是否开启注册用户功能(true开启,false关闭)'),
|
||||
(6, '用户登录-黑名单列表', 'sys.login.blackIPList', '', 'Y', 'admin', '2026-01-30 07:57:19', '', NULL, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)'),
|
||||
(7, '用户管理-初始密码修改策略', 'sys.account.initPasswordModify', '1', 'Y', 'admin', '2026-01-30 07:57:19', '', NULL, '0:初始密码修改策略关闭,没有任何提示,1:提醒用户,如果未修改初始密码,则在登录时就会提醒修改密码对话框'),
|
||||
(8, '用户管理-账号密码更新周期', 'sys.account.passwordValidateDays', '0', 'Y', 'admin', '2026-01-30 07:57:20', '', NULL, '密码更新周期(填写数字,数据初始化值为0不限制,若修改必须为大于0小于365的正整数),如果超过这个周期登录系统时,则在登录时就会提醒修改密码对话框');
|
||||
|
||||
DELETE FROM `sys_dept`;
|
||||
INSERT INTO `sys_dept` (`dept_id`, `parent_id`, `ancestors`, `dept_name`, `order_num`, `leader`, `phone`, `email`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`) VALUES
|
||||
(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:45', '', NULL),
|
||||
(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:45', '', NULL),
|
||||
(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:46', '', NULL),
|
||||
(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:46', '', NULL),
|
||||
(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:46', '', NULL),
|
||||
(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:47', '', NULL),
|
||||
(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:47', '', NULL),
|
||||
(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:47', '', NULL),
|
||||
(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:48', '', NULL),
|
||||
(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2026-01-30 07:55:48', '', NULL);
|
||||
|
||||
DELETE FROM `sys_dict_data`;
|
||||
INSERT INTO `sys_dict_data` (`dict_code`, `dict_sort`, `dict_label`, `dict_value`, `dict_type`, `css_class`, `list_class`, `is_default`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
|
||||
(1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', '2026-01-30 07:57:06', '', NULL, '性别男'),
|
||||
(2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', '2026-01-30 07:57:07', '', NULL, '性别女'),
|
||||
(3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', '2026-01-30 07:57:07', '', NULL, '性别未知'),
|
||||
(4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', '2026-01-30 07:57:07', '', NULL, '显示菜单'),
|
||||
(5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:08', '', NULL, '隐藏菜单'),
|
||||
(6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', '2026-01-30 07:57:08', '', NULL, '正常状态'),
|
||||
(7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:08', '', NULL, '停用状态'),
|
||||
(8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', '2026-01-30 07:57:09', '', NULL, '正常状态'),
|
||||
(9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:09', '', NULL, '停用状态'),
|
||||
(10, 1, '默认', 'DEFAULT', 'sys_job_group', '', '', 'Y', '0', 'admin', '2026-01-30 07:57:10', '', NULL, '默认分组'),
|
||||
(11, 2, '系统', 'SYSTEM', 'sys_job_group', '', '', 'N', '0', 'admin', '2026-01-30 07:57:10', '', NULL, '系统分组'),
|
||||
(12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', '2026-01-30 07:57:10', '', NULL, '系统默认是'),
|
||||
(13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:11', '', NULL, '系统默认否'),
|
||||
(14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', '2026-01-30 07:57:11', '', NULL, '通知'),
|
||||
(15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', '2026-01-30 07:57:11', '', NULL, '公告'),
|
||||
(16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', '2026-01-30 07:57:12', '', NULL, '正常状态'),
|
||||
(17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:12', '', NULL, '关闭状态'),
|
||||
(18, 99, '其他', '0', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2026-01-30 07:57:12', '', NULL, '其他操作'),
|
||||
(19, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2026-01-30 07:57:13', '', NULL, '新增操作'),
|
||||
(20, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2026-01-30 07:57:13', '', NULL, '修改操作'),
|
||||
(21, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:13', '', NULL, '删除操作'),
|
||||
(22, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', '2026-01-30 07:57:14', '', NULL, '授权操作'),
|
||||
(23, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2026-01-30 07:57:14', '', NULL, '导出操作'),
|
||||
(24, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2026-01-30 07:57:14', '', NULL, '导入操作'),
|
||||
(25, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:15', '', NULL, '强退操作'),
|
||||
(26, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2026-01-30 07:57:15', '', NULL, '生成操作'),
|
||||
(27, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:16', '', NULL, '清空操作'),
|
||||
(28, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', '2026-01-30 07:57:16', '', NULL, '正常状态'),
|
||||
(29, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', '2026-01-30 07:57:16', '', NULL, '停用状态');
|
||||
|
||||
DELETE FROM `sys_dict_type`;
|
||||
INSERT INTO `sys_dict_type` (`dict_id`, `dict_name`, `dict_type`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
|
||||
(1, '用户性别', 'sys_user_sex', '0', 'admin', '2026-01-30 07:57:02', '', NULL, '用户性别列表'),
|
||||
(2, '菜单状态', 'sys_show_hide', '0', 'admin', '2026-01-30 07:57:02', '', NULL, '菜单状态列表'),
|
||||
(3, '系统开关', 'sys_normal_disable', '0', 'admin', '2026-01-30 07:57:03', '', NULL, '系统开关列表'),
|
||||
(4, '任务状态', 'sys_job_status', '0', 'admin', '2026-01-30 07:57:03', '', NULL, '任务状态列表'),
|
||||
(5, '任务分组', 'sys_job_group', '0', 'admin', '2026-01-30 07:57:03', '', NULL, '任务分组列表'),
|
||||
(6, '系统是否', 'sys_yes_no', '0', 'admin', '2026-01-30 07:57:04', '', NULL, '系统是否列表'),
|
||||
(7, '通知类型', 'sys_notice_type', '0', 'admin', '2026-01-30 07:57:04', '', NULL, '通知类型列表'),
|
||||
(8, '通知状态', 'sys_notice_status', '0', 'admin', '2026-01-30 07:57:04', '', NULL, '通知状态列表'),
|
||||
(9, '操作类型', 'sys_oper_type', '0', 'admin', '2026-01-30 07:57:05', '', NULL, '操作类型列表'),
|
||||
(10, '系统状态', 'sys_common_status', '0', 'admin', '2026-01-30 07:57:05', '', NULL, '登录状态列表');
|
||||
|
||||
DELETE FROM `sys_job`;
|
||||
INSERT INTO `sys_job` (`job_id`, `job_name`, `job_group`, `invoke_target`, `cron_expression`, `misfire_policy`, `concurrent`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
|
||||
(1, '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', '2026-01-30 07:57:21', '', NULL, ''),
|
||||
(2, '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(\'ry\')', '0/15 * * * * ?', '3', '1', '1', 'admin', '2026-01-30 07:57:22', '', NULL, ''),
|
||||
(3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', '2026-01-30 07:57:22', '', NULL, '');
|
||||
|
||||
DELETE FROM `sys_menu`;
|
||||
INSERT INTO `sys_menu` (`menu_id`, `menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `route_name`, `is_frame`, `is_cache`, `menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
|
||||
(1, '系统管理', 0, 1, 'system', NULL, '', '', 1, 0, 'M', '0', '0', '', 'system', 'admin', '2026-01-30 07:55:54', '', NULL, '系统管理目录'),
|
||||
(2, '系统监控', 0, 2, 'monitor', NULL, '', '', 1, 0, 'M', '0', '0', '', 'monitor', 'admin', '2026-01-30 07:55:55', '', NULL, '系统监控目录'),
|
||||
(3, '系统工具', 0, 3, 'tool', NULL, '', '', 1, 0, 'M', '0', '0', '', 'tool', 'admin', '2026-01-30 07:55:55', '', NULL, '系统工具目录'),
|
||||
(4, '若依官网', 0, 4, 'http://ruoyi.vip', NULL, '', '', 0, 0, 'M', '0', '0', '', 'guide', 'admin', '2026-01-30 07:55:55', '', NULL, '若依官网地址'),
|
||||
(100, '用户管理', 1, 1, 'user', 'system/user/index', '', '', 1, 0, 'C', '0', '0', 'system:user:list', 'user', 'admin', '2026-01-30 07:55:56', '', NULL, '用户管理菜单'),
|
||||
(101, '角色管理', 1, 2, 'role', 'system/role/index', '', '', 1, 0, 'C', '0', '0', 'system:role:list', 'peoples', 'admin', '2026-01-30 07:55:56', '', NULL, '角色管理菜单'),
|
||||
(102, '菜单管理', 1, 3, 'menu', 'system/menu/index', '', '', 1, 0, 'C', '0', '0', 'system:menu:list', 'tree-table', 'admin', '2026-01-30 07:55:56', '', NULL, '菜单管理菜单'),
|
||||
(103, '部门管理', 1, 4, 'dept', 'system/dept/index', '', '', 1, 0, 'C', '0', '0', 'system:dept:list', 'tree', 'admin', '2026-01-30 07:55:57', '', NULL, '部门管理菜单'),
|
||||
(104, '岗位管理', 1, 5, 'post', 'system/post/index', '', '', 1, 0, 'C', '0', '0', 'system:post:list', 'post', 'admin', '2026-01-30 07:55:57', '', NULL, '岗位管理菜单'),
|
||||
(105, '字典管理', 1, 6, 'dict', 'system/dict/index', '', '', 1, 0, 'C', '0', '0', 'system:dict:list', 'dict', 'admin', '2026-01-30 07:55:57', '', NULL, '字典管理菜单'),
|
||||
(106, '参数设置', 1, 7, 'config', 'system/config/index', '', '', 1, 0, 'C', '0', '0', 'system:config:list', 'edit', 'admin', '2026-01-30 07:55:58', '', NULL, '参数设置菜单'),
|
||||
(107, '通知公告', 1, 8, 'notice', 'system/notice/index', '', '', 1, 0, 'C', '0', '0', 'system:notice:list', 'message', 'admin', '2026-01-30 07:55:58', '', NULL, '通知公告菜单'),
|
||||
(108, '日志管理', 1, 9, 'log', '', '', '', 1, 0, 'M', '0', '0', '', 'log', 'admin', '2026-01-30 07:55:58', '', NULL, '日志管理菜单'),
|
||||
(109, '在线用户', 2, 1, 'online', 'monitor/online/index', '', '', 1, 0, 'C', '0', '0', 'monitor:online:list', 'online', 'admin', '2026-01-30 07:55:59', '', NULL, '在线用户菜单'),
|
||||
(110, '定时任务', 2, 2, 'job', 'monitor/job/index', '', '', 1, 0, 'C', '0', '0', 'monitor:job:list', 'job', 'admin', '2026-01-30 07:55:59', '', NULL, '定时任务菜单'),
|
||||
(111, '数据监控', 2, 3, 'druid', 'monitor/druid/index', '', '', 1, 0, 'C', '0', '0', 'monitor:druid:list', 'druid', 'admin', '2026-01-30 07:55:59', '', NULL, '数据监控菜单'),
|
||||
(112, '服务监控', 2, 4, 'server', 'monitor/server/index', '', '', 1, 0, 'C', '0', '0', 'monitor:server:list', 'server', 'admin', '2026-01-30 07:56:00', '', NULL, '服务监控菜单'),
|
||||
(113, '缓存监控', 2, 5, 'cache', 'monitor/cache/index', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis', 'admin', '2026-01-30 07:56:00', '', NULL, '缓存监控菜单'),
|
||||
(114, '缓存列表', 2, 6, 'cacheList', 'monitor/cache/list', '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list', 'redis-list', 'admin', '2026-01-30 07:56:01', '', NULL, '缓存列表菜单'),
|
||||
(115, '表单构建', 3, 1, 'build', 'tool/build/index', '', '', 1, 0, 'C', '0', '0', 'tool:build:list', 'build', 'admin', '2026-01-30 07:56:01', '', NULL, '表单构建菜单'),
|
||||
(116, '代码生成', 3, 2, 'gen', 'tool/gen/index', '', '', 1, 0, 'C', '0', '0', 'tool:gen:list', 'code', 'admin', '2026-01-30 07:56:01', '', NULL, '代码生成菜单'),
|
||||
(117, '系统接口', 3, 3, 'swagger', 'tool/swagger/index', '', '', 1, 0, 'C', '0', '0', 'tool:swagger:list', 'swagger', 'admin', '2026-01-30 07:56:02', '', NULL, '系统接口菜单'),
|
||||
(500, '操作日志', 108, 1, 'operlog', 'monitor/operlog/index', '', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list', 'form', 'admin', '2026-01-30 07:56:02', '', NULL, '操作日志菜单'),
|
||||
(501, '登录日志', 108, 2, 'logininfor', 'monitor/logininfor/index', '', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor', 'admin', '2026-01-30 07:56:02', '', NULL, '登录日志菜单'),
|
||||
(1000, '用户查询', 100, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query', '#', 'admin', '2026-01-30 07:56:03', '', NULL, ''),
|
||||
(1001, '用户新增', 100, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add', '#', 'admin', '2026-01-30 07:56:03', '', NULL, ''),
|
||||
(1002, '用户修改', 100, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit', '#', 'admin', '2026-01-30 07:56:03', '', NULL, ''),
|
||||
(1003, '用户删除', 100, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove', '#', 'admin', '2026-01-30 07:56:04', '', NULL, ''),
|
||||
(1004, '用户导出', 100, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export', '#', 'admin', '2026-01-30 07:56:04', '', NULL, ''),
|
||||
(1005, '用户导入', 100, 6, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import', '#', 'admin', '2026-01-30 07:56:05', '', NULL, ''),
|
||||
(1006, '重置密码', 100, 7, '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd', '#', 'admin', '2026-01-30 07:56:05', '', NULL, ''),
|
||||
(1007, '角色查询', 101, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query', '#', 'admin', '2026-01-30 07:56:05', '', NULL, ''),
|
||||
(1008, '角色新增', 101, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add', '#', 'admin', '2026-01-30 07:56:06', '', NULL, ''),
|
||||
(1009, '角色修改', 101, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit', '#', 'admin', '2026-01-30 07:56:06', '', NULL, ''),
|
||||
(1010, '角色删除', 101, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove', '#', 'admin', '2026-01-30 07:56:06', '', NULL, ''),
|
||||
(1011, '角色导出', 101, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export', '#', 'admin', '2026-01-30 07:56:07', '', NULL, ''),
|
||||
(1012, '菜单查询', 102, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query', '#', 'admin', '2026-01-30 07:56:07', '', NULL, ''),
|
||||
(1013, '菜单新增', 102, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add', '#', 'admin', '2026-01-30 07:56:07', '', NULL, ''),
|
||||
(1014, '菜单修改', 102, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit', '#', 'admin', '2026-01-30 07:56:08', '', NULL, ''),
|
||||
(1015, '菜单删除', 102, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove', '#', 'admin', '2026-01-30 07:56:08', '', NULL, ''),
|
||||
(1016, '部门查询', 103, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query', '#', 'admin', '2026-01-30 07:56:09', '', NULL, ''),
|
||||
(1017, '部门新增', 103, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add', '#', 'admin', '2026-01-30 07:56:09', '', NULL, ''),
|
||||
(1018, '部门修改', 103, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit', '#', 'admin', '2026-01-30 07:56:09', '', NULL, ''),
|
||||
(1019, '部门删除', 103, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove', '#', 'admin', '2026-01-30 07:56:10', '', NULL, ''),
|
||||
(1020, '岗位查询', 104, 1, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query', '#', 'admin', '2026-01-30 07:56:10', '', NULL, ''),
|
||||
(1021, '岗位新增', 104, 2, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add', '#', 'admin', '2026-01-30 07:56:10', '', NULL, ''),
|
||||
(1022, '岗位修改', 104, 3, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit', '#', 'admin', '2026-01-30 07:56:11', '', NULL, ''),
|
||||
(1023, '岗位删除', 104, 4, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove', '#', 'admin', '2026-01-30 07:56:11', '', NULL, ''),
|
||||
(1024, '岗位导出', 104, 5, '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export', '#', 'admin', '2026-01-30 07:56:12', '', NULL, ''),
|
||||
(1025, '字典查询', 105, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:query', '#', 'admin', '2026-01-30 07:56:12', '', NULL, ''),
|
||||
(1026, '字典新增', 105, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:add', '#', 'admin', '2026-01-30 07:56:12', '', NULL, ''),
|
||||
(1027, '字典修改', 105, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit', '#', 'admin', '2026-01-30 07:56:13', '', NULL, ''),
|
||||
(1028, '字典删除', 105, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove', '#', 'admin', '2026-01-30 07:56:13', '', NULL, ''),
|
||||
(1029, '字典导出', 105, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:export', '#', 'admin', '2026-01-30 07:56:13', '', NULL, ''),
|
||||
(1030, '参数查询', 106, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:query', '#', 'admin', '2026-01-30 07:56:14', '', NULL, ''),
|
||||
(1031, '参数新增', 106, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:add', '#', 'admin', '2026-01-30 07:56:14', '', NULL, ''),
|
||||
(1032, '参数修改', 106, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:edit', '#', 'admin', '2026-01-30 07:56:15', '', NULL, ''),
|
||||
(1033, '参数删除', 106, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:remove', '#', 'admin', '2026-01-30 07:56:15', '', NULL, ''),
|
||||
(1034, '参数导出', 106, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:export', '#', 'admin', '2026-01-30 07:56:15', '', NULL, ''),
|
||||
(1035, '公告查询', 107, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:query', '#', 'admin', '2026-01-30 07:56:16', '', NULL, ''),
|
||||
(1036, '公告新增', 107, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:add', '#', 'admin', '2026-01-30 07:56:16', '', NULL, ''),
|
||||
(1037, '公告修改', 107, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit', '#', 'admin', '2026-01-30 07:56:16', '', NULL, ''),
|
||||
(1038, '公告删除', 107, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove', '#', 'admin', '2026-01-30 07:56:17', '', NULL, ''),
|
||||
(1039, '操作查询', 500, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query', '#', 'admin', '2026-01-30 07:56:17', '', NULL, ''),
|
||||
(1040, '操作删除', 500, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove', '#', 'admin', '2026-01-30 07:56:18', '', NULL, ''),
|
||||
(1041, '日志导出', 500, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export', '#', 'admin', '2026-01-30 07:56:18', '', NULL, ''),
|
||||
(1042, '登录查询', 501, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query', '#', 'admin', '2026-01-30 07:56:18', '', NULL, ''),
|
||||
(1043, '登录删除', 501, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove', '#', 'admin', '2026-01-30 07:56:19', '', NULL, ''),
|
||||
(1044, '日志导出', 501, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export', '#', 'admin', '2026-01-30 07:56:19', '', NULL, ''),
|
||||
(1045, '账户解锁', 501, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock', '#', 'admin', '2026-01-30 07:56:19', '', NULL, ''),
|
||||
(1046, '在线查询', 109, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query', '#', 'admin', '2026-01-30 07:56:20', '', NULL, ''),
|
||||
(1047, '批量强退', 109, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', '2026-01-30 07:56:20', '', NULL, ''),
|
||||
(1048, '单条强退', 109, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', '2026-01-30 07:56:20', '', NULL, ''),
|
||||
(1049, '任务查询', 110, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:query', '#', 'admin', '2026-01-30 07:56:21', '', NULL, ''),
|
||||
(1050, '任务新增', 110, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:add', '#', 'admin', '2026-01-30 07:56:21', '', NULL, ''),
|
||||
(1051, '任务修改', 110, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:edit', '#', 'admin', '2026-01-30 07:56:22', '', NULL, ''),
|
||||
(1052, '任务删除', 110, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:remove', '#', 'admin', '2026-01-30 07:56:22', '', NULL, ''),
|
||||
(1053, '状态修改', 110, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:changeStatus', '#', 'admin', '2026-01-30 07:56:22', '', NULL, ''),
|
||||
(1054, '任务导出', 110, 6, '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:export', '#', 'admin', '2026-01-30 07:56:23', '', NULL, ''),
|
||||
(1055, '生成查询', 116, 1, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query', '#', 'admin', '2026-01-30 07:56:23', '', NULL, ''),
|
||||
(1056, '生成修改', 116, 2, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit', '#', 'admin', '2026-01-30 07:56:23', '', NULL, ''),
|
||||
(1057, '生成删除', 116, 3, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove', '#', 'admin', '2026-01-30 07:56:24', '', NULL, ''),
|
||||
(1058, '导入代码', 116, 4, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import', '#', 'admin', '2026-01-30 07:56:24', '', NULL, ''),
|
||||
(1059, '预览代码', 116, 5, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview', '#', 'admin', '2026-01-30 07:56:24', '', NULL, ''),
|
||||
(1060, '生成代码', 116, 6, '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code', '#', 'admin', '2026-01-30 07:56:25', '', NULL, ''),
|
||||
(2000, '利率定价管理', 0, 5, 'loanPricing', NULL, NULL, '', 1, 0, 'M', '1', '0', '', 'money', 'admin', '2026-01-30 07:59:15', 'admin', '2026-01-30 08:05:37', ''),
|
||||
(2001, '流程列表', 2000, 1, 'workflow', 'loanPricing/workflow/index', NULL, '', 1, 0, 'C', '0', '0', 'loanPricing:workflow:list', 'list', 'admin', '2026-01-30 07:59:15', '', NULL, ''),
|
||||
(2002, '流程查询', 2001, 1, '', '', NULL, '', 1, 0, 'F', '0', '0', 'loanPricing:workflow:query', '#', 'admin', '2026-01-30 07:59:16', '', NULL, '');
|
||||
|
||||
DELETE FROM `sys_notice`;
|
||||
INSERT INTO `sys_notice` (`notice_id`, `notice_title`, `notice_type`, `notice_content`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
|
||||
(1, '温馨提醒:2018-07-01 若依新版本发布啦', '2', 0xe696b0e78988e69cace58685e5aeb9, '0', 'admin', '2026-01-30 07:57:24', '', NULL, '管理员'),
|
||||
(2, '维护通知:2018-07-01 若依系统凌晨维护', '1', 0xe7bbb4e68aa4e58685e5aeb9, '0', 'admin', '2026-01-30 07:57:24', '', NULL, '管理员');
|
||||
|
||||
DELETE FROM `sys_post`;
|
||||
INSERT INTO `sys_post` (`post_id`, `post_code`, `post_name`, `post_sort`, `status`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
|
||||
(1, 'ceo', '董事长', 1, '0', 'admin', '2026-01-30 07:55:51', '', NULL, ''),
|
||||
(2, 'se', '项目经理', 2, '0', 'admin', '2026-01-30 07:55:51', '', NULL, ''),
|
||||
(3, 'hr', '人力资源', 3, '0', 'admin', '2026-01-30 07:55:51', '', NULL, ''),
|
||||
(4, 'user', '普通员工', 4, '0', 'admin', '2026-01-30 07:55:52', '', NULL, '');
|
||||
|
||||
DELETE FROM `sys_role`;
|
||||
INSERT INTO `sys_role` (`role_id`, `role_name`, `role_key`, `role_sort`, `data_scope`, `menu_check_strictly`, `dept_check_strictly`, `status`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
|
||||
(1, '超级管理员', 'admin', 1, '1', 1, 1, '0', '0', 'admin', '2026-01-30 07:55:53', '', NULL, '超级管理员'),
|
||||
(2, '普通角色', 'common', 2, '2', 1, 1, '0', '0', 'admin', '2026-01-30 07:55:53', '', NULL, '普通角色'),
|
||||
(100, '管理员', 'headAdmin', 0, '1', 1, 1, '0', '0', 'admin', '2026-01-30 08:43:12', '', NULL, NULL);
|
||||
|
||||
DELETE FROM `sys_role_dept`;
|
||||
INSERT INTO `sys_role_dept` (`role_id`, `dept_id`) VALUES
|
||||
(2, 100),
|
||||
(2, 101),
|
||||
(2, 105);
|
||||
|
||||
DELETE FROM `sys_role_menu`;
|
||||
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`) VALUES
|
||||
(1, 2000),
|
||||
(1, 2001),
|
||||
(1, 2002),
|
||||
(2, 1),
|
||||
(2, 2),
|
||||
(2, 3),
|
||||
(2, 4),
|
||||
(2, 100),
|
||||
(2, 101),
|
||||
(2, 102),
|
||||
(2, 103),
|
||||
(2, 104),
|
||||
(2, 105),
|
||||
(2, 106),
|
||||
(2, 107),
|
||||
(2, 108),
|
||||
(2, 109),
|
||||
(2, 110),
|
||||
(2, 111),
|
||||
(2, 112),
|
||||
(2, 113),
|
||||
(2, 114),
|
||||
(2, 115),
|
||||
(2, 116),
|
||||
(2, 117),
|
||||
(2, 500),
|
||||
(2, 501),
|
||||
(2, 1000),
|
||||
(2, 1001),
|
||||
(2, 1002),
|
||||
(2, 1003),
|
||||
(2, 1004),
|
||||
(2, 1005),
|
||||
(2, 1006),
|
||||
(2, 1007),
|
||||
(2, 1008),
|
||||
(2, 1009),
|
||||
(2, 1010),
|
||||
(2, 1011),
|
||||
(2, 1012),
|
||||
(2, 1013),
|
||||
(2, 1014),
|
||||
(2, 1015),
|
||||
(2, 1016),
|
||||
(2, 1017),
|
||||
(2, 1018),
|
||||
(2, 1019),
|
||||
(2, 1020),
|
||||
(2, 1021),
|
||||
(2, 1022),
|
||||
(2, 1023),
|
||||
(2, 1024),
|
||||
(2, 1025),
|
||||
(2, 1026),
|
||||
(2, 1027),
|
||||
(2, 1028),
|
||||
(2, 1029),
|
||||
(2, 1030),
|
||||
(2, 1031),
|
||||
(2, 1032),
|
||||
(2, 1033),
|
||||
(2, 1034),
|
||||
(2, 1035),
|
||||
(2, 1036),
|
||||
(2, 1037),
|
||||
(2, 1038),
|
||||
(2, 1039),
|
||||
(2, 1040),
|
||||
(2, 1041),
|
||||
(2, 1042),
|
||||
(2, 1043),
|
||||
(2, 1044),
|
||||
(2, 1045),
|
||||
(2, 1046),
|
||||
(2, 1047),
|
||||
(2, 1048),
|
||||
(2, 1049),
|
||||
(2, 1050),
|
||||
(2, 1051),
|
||||
(2, 1052),
|
||||
(2, 1053),
|
||||
(2, 1054),
|
||||
(2, 1055),
|
||||
(2, 1056),
|
||||
(2, 1057),
|
||||
(2, 1058),
|
||||
(2, 1059),
|
||||
(2, 1060),
|
||||
(100, 1),
|
||||
(100, 100),
|
||||
(100, 101),
|
||||
(100, 102),
|
||||
(100, 103),
|
||||
(100, 1000),
|
||||
(100, 1001),
|
||||
(100, 1002),
|
||||
(100, 1003),
|
||||
(100, 1004),
|
||||
(100, 1005),
|
||||
(100, 1006),
|
||||
(100, 1007),
|
||||
(100, 1008),
|
||||
(100, 1009),
|
||||
(100, 1010),
|
||||
(100, 1011),
|
||||
(100, 1012),
|
||||
(100, 1013),
|
||||
(100, 1014),
|
||||
(100, 1015),
|
||||
(100, 1016),
|
||||
(100, 1017),
|
||||
(100, 1018),
|
||||
(100, 1019),
|
||||
(100, 2000),
|
||||
(100, 2001),
|
||||
(100, 2002);
|
||||
|
||||
DELETE FROM `sys_user`;
|
||||
INSERT INTO `sys_user` (`user_id`, `dept_id`, `user_name`, `nick_name`, `user_type`, `email`, `phonenumber`, `sex`, `avatar`, `password`, `status`, `del_flag`, `login_ip`, `login_date`, `pwd_update_date`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES
|
||||
(1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2026-03-28 09:16:04', '2026-01-30 07:55:49', 'admin', '2026-01-30 07:55:49', '', NULL, '管理员'),
|
||||
(2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2026-01-30 07:55:50', '2026-01-30 07:55:50', 'admin', '2026-01-30 07:55:50', '', NULL, '测试员'),
|
||||
(100, 100, '8929999', '测试管理员', '00', '', '', '0', '', '$2a$10$i1YqCkEgZK4YhJC09y3qAOovK13Sc5oOENYtFGZRU6R/z8jJB/C/W', '0', '0', '127.0.0.1', '2026-01-30 16:44:03', NULL, 'admin', '2026-01-30 08:43:45', '', NULL, NULL);
|
||||
|
||||
DELETE FROM `sys_user_post`;
|
||||
INSERT INTO `sys_user_post` (`user_id`, `post_id`) VALUES
|
||||
(1, 1),
|
||||
(2, 2);
|
||||
|
||||
DELETE FROM `sys_user_role`;
|
||||
INSERT INTO `sys_user_role` (`user_id`, `role_id`) VALUES
|
||||
(1, 1),
|
||||
(2, 2),
|
||||
(100, 100);
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=1;
|
||||
898
sql/loan_pricing_schema_20260328.sql
Normal file
898
sql/loan_pricing_schema_20260328.sql
Normal file
@@ -0,0 +1,898 @@
|
||||
-- 说明:
|
||||
-- 1. 本文件由源库 116.62.17.81:3306/loan-pricing 导出
|
||||
-- 2. 用途是初始化目标库 116.62.17.81:3307 的全部表结构
|
||||
-- 3. 导入前请先创建目标数据库账号并确认拥有建库建表权限
|
||||
|
||||
-- MySQL dump 10.13 Distrib 9.6.0, for macos15 (arm64)
|
||||
--
|
||||
-- Host: 116.62.17.81 Database: loan-pricing
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 5.7.44
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!50503 SET NAMES utf8mb4 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Current Database: `loan-pricing`
|
||||
--
|
||||
|
||||
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `loan-pricing` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci */;
|
||||
|
||||
USE `loan-pricing`;
|
||||
|
||||
--
|
||||
-- Table structure for table `QRTZ_BLOB_TRIGGERS`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `QRTZ_BLOB_TRIGGERS`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `QRTZ_BLOB_TRIGGERS` (
|
||||
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
|
||||
`trigger_name` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
|
||||
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
|
||||
`blob_data` blob COMMENT '存放持久化Trigger对象',
|
||||
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
|
||||
CONSTRAINT `QRTZ_BLOB_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `QRTZ_TRIGGERS` (`sched_name`, `trigger_name`, `trigger_group`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Blob类型的触发器表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `QRTZ_CALENDARS`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `QRTZ_CALENDARS`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `QRTZ_CALENDARS` (
|
||||
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
|
||||
`calendar_name` varchar(200) NOT NULL COMMENT '日历名称',
|
||||
`calendar` blob NOT NULL COMMENT '存放持久化calendar对象',
|
||||
PRIMARY KEY (`sched_name`,`calendar_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='日历信息表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `QRTZ_CRON_TRIGGERS`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `QRTZ_CRON_TRIGGERS`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `QRTZ_CRON_TRIGGERS` (
|
||||
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
|
||||
`trigger_name` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
|
||||
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
|
||||
`cron_expression` varchar(200) NOT NULL COMMENT 'cron表达式',
|
||||
`time_zone_id` varchar(80) DEFAULT NULL COMMENT '时区',
|
||||
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
|
||||
CONSTRAINT `QRTZ_CRON_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `QRTZ_TRIGGERS` (`sched_name`, `trigger_name`, `trigger_group`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='Cron类型的触发器表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `QRTZ_FIRED_TRIGGERS`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `QRTZ_FIRED_TRIGGERS`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `QRTZ_FIRED_TRIGGERS` (
|
||||
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
|
||||
`entry_id` varchar(95) NOT NULL COMMENT '调度器实例id',
|
||||
`trigger_name` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
|
||||
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
|
||||
`instance_name` varchar(200) NOT NULL COMMENT '调度器实例名',
|
||||
`fired_time` bigint(13) NOT NULL COMMENT '触发的时间',
|
||||
`sched_time` bigint(13) NOT NULL COMMENT '定时器制定的时间',
|
||||
`priority` int(11) NOT NULL COMMENT '优先级',
|
||||
`state` varchar(16) NOT NULL COMMENT '状态',
|
||||
`job_name` varchar(200) DEFAULT NULL COMMENT '任务名称',
|
||||
`job_group` varchar(200) DEFAULT NULL COMMENT '任务组名',
|
||||
`is_nonconcurrent` varchar(1) DEFAULT NULL COMMENT '是否并发',
|
||||
`requests_recovery` varchar(1) DEFAULT NULL COMMENT '是否接受恢复执行',
|
||||
PRIMARY KEY (`sched_name`,`entry_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='已触发的触发器表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `QRTZ_JOB_DETAILS`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `QRTZ_JOB_DETAILS`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `QRTZ_JOB_DETAILS` (
|
||||
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
|
||||
`job_name` varchar(200) NOT NULL COMMENT '任务名称',
|
||||
`job_group` varchar(200) NOT NULL COMMENT '任务组名',
|
||||
`description` varchar(250) DEFAULT NULL COMMENT '相关介绍',
|
||||
`job_class_name` varchar(250) NOT NULL COMMENT '执行任务类名称',
|
||||
`is_durable` varchar(1) NOT NULL COMMENT '是否持久化',
|
||||
`is_nonconcurrent` varchar(1) NOT NULL COMMENT '是否并发',
|
||||
`is_update_data` varchar(1) NOT NULL COMMENT '是否更新数据',
|
||||
`requests_recovery` varchar(1) NOT NULL COMMENT '是否接受恢复执行',
|
||||
`job_data` blob COMMENT '存放持久化job对象',
|
||||
PRIMARY KEY (`sched_name`,`job_name`,`job_group`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='任务详细信息表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `QRTZ_LOCKS`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `QRTZ_LOCKS`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `QRTZ_LOCKS` (
|
||||
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
|
||||
`lock_name` varchar(40) NOT NULL COMMENT '悲观锁名称',
|
||||
PRIMARY KEY (`sched_name`,`lock_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='存储的悲观锁信息表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `QRTZ_PAUSED_TRIGGER_GRPS`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `QRTZ_PAUSED_TRIGGER_GRPS`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `QRTZ_PAUSED_TRIGGER_GRPS` (
|
||||
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
|
||||
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
|
||||
PRIMARY KEY (`sched_name`,`trigger_group`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='暂停的触发器表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `QRTZ_SCHEDULER_STATE`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `QRTZ_SCHEDULER_STATE`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `QRTZ_SCHEDULER_STATE` (
|
||||
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
|
||||
`instance_name` varchar(200) NOT NULL COMMENT '实例名称',
|
||||
`last_checkin_time` bigint(13) NOT NULL COMMENT '上次检查时间',
|
||||
`checkin_interval` bigint(13) NOT NULL COMMENT '检查间隔时间',
|
||||
PRIMARY KEY (`sched_name`,`instance_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='调度器状态表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `QRTZ_SIMPLE_TRIGGERS`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `QRTZ_SIMPLE_TRIGGERS`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `QRTZ_SIMPLE_TRIGGERS` (
|
||||
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
|
||||
`trigger_name` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
|
||||
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
|
||||
`repeat_count` bigint(7) NOT NULL COMMENT '重复的次数统计',
|
||||
`repeat_interval` bigint(12) NOT NULL COMMENT '重复的间隔时间',
|
||||
`times_triggered` bigint(10) NOT NULL COMMENT '已经触发的次数',
|
||||
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
|
||||
CONSTRAINT `QRTZ_SIMPLE_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `QRTZ_TRIGGERS` (`sched_name`, `trigger_name`, `trigger_group`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='简单触发器的信息表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `QRTZ_SIMPROP_TRIGGERS`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `QRTZ_SIMPROP_TRIGGERS`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `QRTZ_SIMPROP_TRIGGERS` (
|
||||
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
|
||||
`trigger_name` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_name的外键',
|
||||
`trigger_group` varchar(200) NOT NULL COMMENT 'qrtz_triggers表trigger_group的外键',
|
||||
`str_prop_1` varchar(512) DEFAULT NULL COMMENT 'String类型的trigger的第一个参数',
|
||||
`str_prop_2` varchar(512) DEFAULT NULL COMMENT 'String类型的trigger的第二个参数',
|
||||
`str_prop_3` varchar(512) DEFAULT NULL COMMENT 'String类型的trigger的第三个参数',
|
||||
`int_prop_1` int(11) DEFAULT NULL COMMENT 'int类型的trigger的第一个参数',
|
||||
`int_prop_2` int(11) DEFAULT NULL COMMENT 'int类型的trigger的第二个参数',
|
||||
`long_prop_1` bigint(20) DEFAULT NULL COMMENT 'long类型的trigger的第一个参数',
|
||||
`long_prop_2` bigint(20) DEFAULT NULL COMMENT 'long类型的trigger的第二个参数',
|
||||
`dec_prop_1` decimal(13,4) DEFAULT NULL COMMENT 'decimal类型的trigger的第一个参数',
|
||||
`dec_prop_2` decimal(13,4) DEFAULT NULL COMMENT 'decimal类型的trigger的第二个参数',
|
||||
`bool_prop_1` varchar(1) DEFAULT NULL COMMENT 'Boolean类型的trigger的第一个参数',
|
||||
`bool_prop_2` varchar(1) DEFAULT NULL COMMENT 'Boolean类型的trigger的第二个参数',
|
||||
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
|
||||
CONSTRAINT `QRTZ_SIMPROP_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `trigger_name`, `trigger_group`) REFERENCES `QRTZ_TRIGGERS` (`sched_name`, `trigger_name`, `trigger_group`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='同步机制的行锁表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `QRTZ_TRIGGERS`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `QRTZ_TRIGGERS`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `QRTZ_TRIGGERS` (
|
||||
`sched_name` varchar(120) NOT NULL COMMENT '调度名称',
|
||||
`trigger_name` varchar(200) NOT NULL COMMENT '触发器的名字',
|
||||
`trigger_group` varchar(200) NOT NULL COMMENT '触发器所属组的名字',
|
||||
`job_name` varchar(200) NOT NULL COMMENT 'qrtz_job_details表job_name的外键',
|
||||
`job_group` varchar(200) NOT NULL COMMENT 'qrtz_job_details表job_group的外键',
|
||||
`description` varchar(250) DEFAULT NULL COMMENT '相关介绍',
|
||||
`next_fire_time` bigint(13) DEFAULT NULL COMMENT '上一次触发时间(毫秒)',
|
||||
`prev_fire_time` bigint(13) DEFAULT NULL COMMENT '下一次触发时间(默认为-1表示不触发)',
|
||||
`priority` int(11) DEFAULT NULL COMMENT '优先级',
|
||||
`trigger_state` varchar(16) NOT NULL COMMENT '触发器状态',
|
||||
`trigger_type` varchar(8) NOT NULL COMMENT '触发器的类型',
|
||||
`start_time` bigint(13) NOT NULL COMMENT '开始时间',
|
||||
`end_time` bigint(13) DEFAULT NULL COMMENT '结束时间',
|
||||
`calendar_name` varchar(200) DEFAULT NULL COMMENT '日程表名称',
|
||||
`misfire_instr` smallint(2) DEFAULT NULL COMMENT '补偿执行的策略',
|
||||
`job_data` blob COMMENT '存放持久化job对象',
|
||||
PRIMARY KEY (`sched_name`,`trigger_name`,`trigger_group`),
|
||||
KEY `sched_name` (`sched_name`,`job_name`,`job_group`),
|
||||
CONSTRAINT `QRTZ_TRIGGERS_ibfk_1` FOREIGN KEY (`sched_name`, `job_name`, `job_group`) REFERENCES `QRTZ_JOB_DETAILS` (`sched_name`, `job_name`, `job_group`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='触发器详细信息表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `gen_table`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `gen_table`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `gen_table` (
|
||||
`table_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
|
||||
`table_name` varchar(200) DEFAULT '' COMMENT '表名称',
|
||||
`table_comment` varchar(500) DEFAULT '' COMMENT '表描述',
|
||||
`sub_table_name` varchar(64) DEFAULT NULL COMMENT '关联子表的表名',
|
||||
`sub_table_fk_name` varchar(64) DEFAULT NULL COMMENT '子表关联的外键名',
|
||||
`class_name` varchar(100) DEFAULT '' COMMENT '实体类名称',
|
||||
`tpl_category` varchar(200) DEFAULT 'crud' COMMENT '使用的模板(crud单表操作 tree树表操作)',
|
||||
`tpl_web_type` varchar(30) DEFAULT '' COMMENT '前端模板类型(element-ui模版 element-plus模版)',
|
||||
`package_name` varchar(100) DEFAULT NULL COMMENT '生成包路径',
|
||||
`module_name` varchar(30) DEFAULT NULL COMMENT '生成模块名',
|
||||
`business_name` varchar(30) DEFAULT NULL COMMENT '生成业务名',
|
||||
`function_name` varchar(50) DEFAULT NULL COMMENT '生成功能名',
|
||||
`function_author` varchar(50) DEFAULT NULL COMMENT '生成功能作者',
|
||||
`gen_type` char(1) DEFAULT '0' COMMENT '生成代码方式(0zip压缩包 1自定义路径)',
|
||||
`gen_path` varchar(200) DEFAULT '/' COMMENT '生成路径(不填默认项目路径)',
|
||||
`options` varchar(1000) DEFAULT NULL COMMENT '其它生成选项',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`table_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代码生成业务表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `gen_table_column`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `gen_table_column`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `gen_table_column` (
|
||||
`column_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '编号',
|
||||
`table_id` bigint(20) DEFAULT NULL COMMENT '归属表编号',
|
||||
`column_name` varchar(200) DEFAULT NULL COMMENT '列名称',
|
||||
`column_comment` varchar(500) DEFAULT NULL COMMENT '列描述',
|
||||
`column_type` varchar(100) DEFAULT NULL COMMENT '列类型',
|
||||
`java_type` varchar(500) DEFAULT NULL COMMENT 'JAVA类型',
|
||||
`java_field` varchar(200) DEFAULT NULL COMMENT 'JAVA字段名',
|
||||
`is_pk` char(1) DEFAULT NULL COMMENT '是否主键(1是)',
|
||||
`is_increment` char(1) DEFAULT NULL COMMENT '是否自增(1是)',
|
||||
`is_required` char(1) DEFAULT NULL COMMENT '是否必填(1是)',
|
||||
`is_insert` char(1) DEFAULT NULL COMMENT '是否为插入字段(1是)',
|
||||
`is_edit` char(1) DEFAULT NULL COMMENT '是否编辑字段(1是)',
|
||||
`is_list` char(1) DEFAULT NULL COMMENT '是否列表字段(1是)',
|
||||
`is_query` char(1) DEFAULT NULL COMMENT '是否查询字段(1是)',
|
||||
`query_type` varchar(200) DEFAULT 'EQ' COMMENT '查询方式(等于、不等于、大于、小于、范围)',
|
||||
`html_type` varchar(200) DEFAULT NULL COMMENT '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)',
|
||||
`dict_type` varchar(200) DEFAULT '' COMMENT '字典类型',
|
||||
`sort` int(11) DEFAULT NULL COMMENT '排序',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`column_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='代码生成业务表字段';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `loan_pricing_workflow`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `loan_pricing_workflow`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `loan_pricing_workflow` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`serial_num` varchar(50) NOT NULL COMMENT '业务方流水号',
|
||||
`model_output_id` bigint(20) DEFAULT NULL COMMENT '模型输出ID',
|
||||
`org_code` varchar(20) NOT NULL DEFAULT '892000' COMMENT '机构编码(统一值892000)',
|
||||
`run_type` varchar(10) NOT NULL DEFAULT '1' COMMENT '运行模式: 1-同步',
|
||||
`cust_isn` varchar(50) NOT NULL COMMENT '客户内码',
|
||||
`cust_type` varchar(20) NOT NULL COMMENT '客户类型: 个人/企业',
|
||||
`guar_type` varchar(20) NOT NULL COMMENT '担保方式: 信用/保证/抵押/质押',
|
||||
`mid_per_quick_pay` varchar(10) DEFAULT NULL COMMENT '中间业务_个人_快捷支付: true/false',
|
||||
`mid_per_ele_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_个人_电费代扣: true/false',
|
||||
`mid_ent_ele_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_企业_电费代扣: true/false',
|
||||
`mid_ent_water_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_企业_水费代扣: true/false',
|
||||
`apply_amt` varchar(50) NOT NULL COMMENT '申请金额(元)',
|
||||
`loan_term` varchar(50) DEFAULT NULL COMMENT '贷款期限',
|
||||
`is_clean_ent` varchar(10) DEFAULT NULL COMMENT '净身企业: true/false',
|
||||
`has_settle_acct` varchar(10) DEFAULT NULL COMMENT '开立基本结算账户: true/false',
|
||||
`is_manufacturing` varchar(10) DEFAULT NULL COMMENT '制造业企业: true/false',
|
||||
`is_agri_guar` varchar(10) DEFAULT NULL COMMENT '省农担担保贷款: true/false',
|
||||
`is_tech_ent` varchar(10) DEFAULT NULL COMMENT '科技型企业: true/false(科技型企业最多下降5BP)',
|
||||
`is_green_loan` varchar(10) DEFAULT NULL COMMENT '绿色贷款: true/false(绿色贷款最多下降5BP)',
|
||||
`is_trade_construction` varchar(10) DEFAULT NULL COMMENT '贸易和建筑业企业标识: true/false(抵质押类上调20BP)',
|
||||
`is_tax_a` varchar(10) DEFAULT NULL COMMENT '是否纳税信用等级A级: true/false',
|
||||
`is_agri_leading` varchar(10) DEFAULT NULL COMMENT '是否县级及以上农业龙头企业: true/false',
|
||||
`loan_purpose` varchar(20) DEFAULT NULL COMMENT '贷款用途: consumer-消费/business-经营',
|
||||
`biz_proof` varchar(10) DEFAULT NULL COMMENT '是否有经营佐证: true/false',
|
||||
`loan_loop` varchar(10) DEFAULT NULL COMMENT '循环功能: true/false(贷款合同是否开通循环功能)',
|
||||
`coll_type` varchar(20) DEFAULT NULL COMMENT '抵质押类型: 一线/一类/二类',
|
||||
`coll_third_party` varchar(10) DEFAULT NULL COMMENT '抵质押物是否三方所有: true/false',
|
||||
`loan_rate` varchar(20) DEFAULT NULL COMMENT '贷款利率',
|
||||
`execute_rate` varchar(20) DEFAULT NULL COMMENT '执行利率(%)',
|
||||
`cust_name` varchar(100) DEFAULT NULL COMMENT '客户名称',
|
||||
`id_type` varchar(50) DEFAULT NULL COMMENT '证件类型',
|
||||
`id_num` varchar(100) DEFAULT NULL COMMENT '证件号码',
|
||||
`is_inclusive_finance` varchar(10) DEFAULT NULL COMMENT '是否普惠小微借款人: true/false',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_serial_num` (`serial_num`),
|
||||
KEY `idx_org_code` (`org_code`),
|
||||
KEY `idx_create_by` (`create_by`),
|
||||
KEY `idx_cust_name` (`cust_name`),
|
||||
KEY `idx_update_time` (`update_time`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='利率定价流程表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `model_corp_output_fields`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `model_corp_output_fields`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `model_corp_output_fields` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键ID',
|
||||
`cust_isn` varchar(100) DEFAULT NULL COMMENT '客户内码',
|
||||
`cust_type` varchar(100) DEFAULT NULL COMMENT '客户类型',
|
||||
`guar_type` varchar(100) DEFAULT NULL COMMENT '担保方式',
|
||||
`cust_name` varchar(100) DEFAULT NULL COMMENT '客户名称',
|
||||
`id_type` varchar(100) DEFAULT NULL COMMENT '证件类型',
|
||||
`id_num` varchar(100) DEFAULT NULL COMMENT '证件号码',
|
||||
`base_loan_rate` varchar(100) DEFAULT NULL COMMENT '基准利率',
|
||||
`is_first_loan` varchar(100) DEFAULT NULL COMMENT '我行首贷客户',
|
||||
`faith_day` varchar(100) DEFAULT NULL COMMENT '用信天数',
|
||||
`bp_first_loan` varchar(100) DEFAULT NULL COMMENT 'BP_首贷',
|
||||
`bp_age_loan` varchar(100) DEFAULT NULL COMMENT 'BP_贷龄',
|
||||
`total_bp_loyalty` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_忠诚度',
|
||||
`balance_avg` varchar(100) DEFAULT NULL COMMENT '存款年日均',
|
||||
`loan_avg` varchar(100) DEFAULT NULL COMMENT '贷款年日均',
|
||||
`derivation_rate` varchar(100) DEFAULT NULL COMMENT '派生率',
|
||||
`total_bp_contribution` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_贡献度',
|
||||
`mid_ent_connect` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_企业互联',
|
||||
`mid_ent_effect` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_有效价值客户',
|
||||
`mid_ent_inter` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_国际业务',
|
||||
`mid_ent_accept` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_承兑',
|
||||
`mid_ent_discount` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_贴现',
|
||||
`mid_ent_ele_ddc` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_电费代扣',
|
||||
`mid_ent_water_ddc` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_水费代扣',
|
||||
`mid_ent_tax` varchar(100) DEFAULT NULL COMMENT '中间业务_企业_税务代扣',
|
||||
`bp_mid` varchar(100) DEFAULT NULL COMMENT 'BP_中间业务',
|
||||
`payroll` varchar(100) DEFAULT NULL COMMENT '代发工资户数',
|
||||
`inv_loan_amount` varchar(100) DEFAULT NULL COMMENT '存量贷款余额',
|
||||
`bp_payroll` varchar(100) DEFAULT NULL COMMENT 'BP_代发工资',
|
||||
`is_clean_ent` varchar(100) DEFAULT NULL COMMENT '净身企业',
|
||||
`has_settle_acct` varchar(100) DEFAULT NULL COMMENT '开立基本结算账户',
|
||||
`is_agri_guar` varchar(100) DEFAULT NULL COMMENT '省农担担保贷款',
|
||||
`is_green_loan` varchar(100) DEFAULT NULL COMMENT '绿色贷款',
|
||||
`is_tech_ent` varchar(100) DEFAULT NULL COMMENT '科技型企业',
|
||||
`bp_ent_type` varchar(100) DEFAULT NULL COMMENT 'BP_企业客户类别',
|
||||
`totoal_bp_relevance` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_关联度',
|
||||
`loan_term` varchar(100) DEFAULT NULL COMMENT '贷款期限',
|
||||
`bp_loan_term` varchar(100) DEFAULT NULL COMMENT 'BP_贷款期限',
|
||||
`apply_amt` varchar(100) DEFAULT NULL COMMENT '申请金额',
|
||||
`bp_loan_amount` varchar(100) DEFAULT NULL COMMENT 'BP_贷款额度',
|
||||
`coll_type` varchar(100) DEFAULT NULL COMMENT '抵质押类型',
|
||||
`coll_third_party` varchar(100) DEFAULT NULL COMMENT '抵质押物是否三方所有',
|
||||
`bp_collateral` varchar(100) DEFAULT NULL COMMENT 'BP_抵押物',
|
||||
`grey_cust` varchar(100) DEFAULT NULL COMMENT '灰名单客户',
|
||||
`prin_overdue` varchar(100) DEFAULT NULL COMMENT '本金逾期',
|
||||
`interest_overdue` varchar(100) DEFAULT NULL COMMENT '利息逾期',
|
||||
`card_overdue` varchar(100) DEFAULT NULL COMMENT '信用卡逾期',
|
||||
`bp_grey_overdue` varchar(100) DEFAULT NULL COMMENT 'BP_灰名单与逾期',
|
||||
`totoal_bp_risk` varchar(100) DEFAULT NULL COMMENT 'TOTAL_BP_风险度',
|
||||
`total_bp` varchar(100) DEFAULT NULL COMMENT '浮动BP',
|
||||
`calculate_rate` varchar(100) DEFAULT NULL COMMENT '测算利率',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='客户贷款利率测算表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `model_retail_output_fields`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `model_retail_output_fields`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `model_retail_output_fields` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`cust_isn` varchar(100) COLLATE utf8mb4_general_ci NOT NULL COMMENT '客户内码',
|
||||
`cust_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '客户类型',
|
||||
`guar_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '担保方式',
|
||||
`cust_name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '客户名称',
|
||||
`id_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '证件类型',
|
||||
`id_num` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '证件号码',
|
||||
`base_loan_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '基准利率',
|
||||
`is_first_loan` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '我行首贷客户',
|
||||
`faith_day` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '用信天数',
|
||||
`cust_age` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '客户年龄',
|
||||
`bp_first_loan` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_首贷',
|
||||
`bp_age_loan` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_贷龄',
|
||||
`bp_age` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_年龄',
|
||||
`total_bp_loyalty` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_忠诚度',
|
||||
`balance_avg` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '存款年日均',
|
||||
`loan_avg` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '贷款年日均',
|
||||
`derivation_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '派生率',
|
||||
`total_bp_contribution` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_贡献度',
|
||||
`mid_per_card` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_信用卡',
|
||||
`mid_per_pass` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_一码通',
|
||||
`mid_per_harvest` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_丰收互联',
|
||||
`mid_per_effect` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_有效客户',
|
||||
`mid_per_quick_pay` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_快捷支付',
|
||||
`mid_per_ele_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_电费代扣',
|
||||
`mid_per_water_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_水费代扣',
|
||||
`mid_per_huashu_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_华数费代扣',
|
||||
`mid_per_gas_ddc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_煤气费代扣',
|
||||
`mid_per_citizencard` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_市民卡',
|
||||
`mid_per_fin_man` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_理财业务',
|
||||
`mid_per_etc` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '中间业务_个人_etc',
|
||||
`bp_mid` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_中间业务',
|
||||
`totoal_bp_relevance` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_关联度',
|
||||
`apply_amt` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '申请金额',
|
||||
`bp_loan_amount` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_贷款额度',
|
||||
`loan_purpose` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '贷款用途',
|
||||
`biz_proof` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '是否有经营佐证',
|
||||
`bp_loan_use` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_贷款用途',
|
||||
`loan_loop` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '循环功能',
|
||||
`bp_loan_loop` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_循环功能',
|
||||
`coll_type` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '抵质押类型',
|
||||
`coll_third_party` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '抵质押物是否三方所有',
|
||||
`bp_collateral` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_抵押物',
|
||||
`grey_cust` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '灰名单客户',
|
||||
`prin_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '本金逾期',
|
||||
`interest_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '利息逾期',
|
||||
`card_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '信用卡逾期',
|
||||
`bp_grey_overdue` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'BP_灰名单与逾期',
|
||||
`totoal_bp_risk` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'TOTAL_BP_风险度',
|
||||
`total_bp` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '浮动BP',
|
||||
`calculate_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '测算利率',
|
||||
`loan_rate_history` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '历史利率',
|
||||
`min_rate_product` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '产品最低利率下限',
|
||||
`smooth_range` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '平滑幅度',
|
||||
`final_calculate_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '最终测算利率',
|
||||
`reference_rate` varchar(100) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '参考利率',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='零售模型输出字段表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_config`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_config`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_config` (
|
||||
`config_id` int(5) NOT NULL AUTO_INCREMENT COMMENT '参数主键',
|
||||
`config_name` varchar(100) DEFAULT '' COMMENT '参数名称',
|
||||
`config_key` varchar(100) DEFAULT '' COMMENT '参数键名',
|
||||
`config_value` varchar(500) DEFAULT '' COMMENT '参数键值',
|
||||
`config_type` char(1) DEFAULT 'N' COMMENT '系统内置(Y是 N否)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`config_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='参数配置表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_dept`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_dept`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_dept` (
|
||||
`dept_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '部门id',
|
||||
`parent_id` bigint(20) DEFAULT '0' COMMENT '父部门id',
|
||||
`ancestors` varchar(50) DEFAULT '' COMMENT '祖级列表',
|
||||
`dept_name` varchar(30) DEFAULT '' COMMENT '部门名称',
|
||||
`order_num` int(4) DEFAULT '0' COMMENT '显示顺序',
|
||||
`leader` varchar(20) DEFAULT NULL COMMENT '负责人',
|
||||
`phone` varchar(11) DEFAULT NULL COMMENT '联系电话',
|
||||
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
|
||||
`status` char(1) DEFAULT '0' COMMENT '部门状态(0正常 1停用)',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`dept_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=110 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='部门表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_dict_data`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_dict_data`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_dict_data` (
|
||||
`dict_code` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典编码',
|
||||
`dict_sort` int(4) DEFAULT '0' COMMENT '字典排序',
|
||||
`dict_label` varchar(100) DEFAULT '' COMMENT '字典标签',
|
||||
`dict_value` varchar(100) DEFAULT '' COMMENT '字典键值',
|
||||
`dict_type` varchar(100) DEFAULT '' COMMENT '字典类型',
|
||||
`css_class` varchar(100) DEFAULT NULL COMMENT '样式属性(其他样式扩展)',
|
||||
`list_class` varchar(100) DEFAULT NULL COMMENT '表格回显样式',
|
||||
`is_default` char(1) DEFAULT 'N' COMMENT '是否默认(Y是 N否)',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`dict_code`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='字典数据表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_dict_type`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_dict_type`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_dict_type` (
|
||||
`dict_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '字典主键',
|
||||
`dict_name` varchar(100) DEFAULT '' COMMENT '字典名称',
|
||||
`dict_type` varchar(100) DEFAULT '' COMMENT '字典类型',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`dict_id`),
|
||||
UNIQUE KEY `dict_type` (`dict_type`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='字典类型表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_job`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_job`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_job` (
|
||||
`job_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任务ID',
|
||||
`job_name` varchar(64) NOT NULL DEFAULT '' COMMENT '任务名称',
|
||||
`job_group` varchar(64) NOT NULL DEFAULT 'DEFAULT' COMMENT '任务组名',
|
||||
`invoke_target` varchar(500) NOT NULL COMMENT '调用目标字符串',
|
||||
`cron_expression` varchar(255) DEFAULT '' COMMENT 'cron执行表达式',
|
||||
`misfire_policy` varchar(20) DEFAULT '3' COMMENT '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
|
||||
`concurrent` char(1) DEFAULT '1' COMMENT '是否并发执行(0允许 1禁止)',
|
||||
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1暂停)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT '' COMMENT '备注信息',
|
||||
PRIMARY KEY (`job_id`,`job_name`,`job_group`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='定时任务调度表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_job_log`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_job_log`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_job_log` (
|
||||
`job_log_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '任务日志ID',
|
||||
`job_name` varchar(64) NOT NULL COMMENT '任务名称',
|
||||
`job_group` varchar(64) NOT NULL COMMENT '任务组名',
|
||||
`invoke_target` varchar(500) NOT NULL COMMENT '调用目标字符串',
|
||||
`job_message` varchar(500) DEFAULT NULL COMMENT '日志信息',
|
||||
`status` char(1) DEFAULT '0' COMMENT '执行状态(0正常 1失败)',
|
||||
`exception_info` varchar(2000) DEFAULT '' COMMENT '异常信息',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
PRIMARY KEY (`job_log_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='定时任务调度日志表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_logininfor`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_logininfor`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_logininfor` (
|
||||
`info_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '访问ID',
|
||||
`user_name` varchar(50) DEFAULT '' COMMENT '用户账号',
|
||||
`ipaddr` varchar(128) DEFAULT '' COMMENT '登录IP地址',
|
||||
`login_location` varchar(255) DEFAULT '' COMMENT '登录地点',
|
||||
`browser` varchar(50) DEFAULT '' COMMENT '浏览器类型',
|
||||
`os` varchar(50) DEFAULT '' COMMENT '操作系统',
|
||||
`status` char(1) DEFAULT '0' COMMENT '登录状态(0成功 1失败)',
|
||||
`msg` varchar(255) DEFAULT '' COMMENT '提示消息',
|
||||
`login_time` datetime DEFAULT NULL COMMENT '访问时间',
|
||||
PRIMARY KEY (`info_id`),
|
||||
KEY `idx_sys_logininfor_s` (`status`),
|
||||
KEY `idx_sys_logininfor_lt` (`login_time`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='系统访问记录';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_menu`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_menu`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_menu` (
|
||||
`menu_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '菜单ID',
|
||||
`menu_name` varchar(50) NOT NULL COMMENT '菜单名称',
|
||||
`parent_id` bigint(20) DEFAULT '0' COMMENT '父菜单ID',
|
||||
`order_num` int(4) DEFAULT '0' COMMENT '显示顺序',
|
||||
`path` varchar(200) DEFAULT '' COMMENT '路由地址',
|
||||
`component` varchar(255) DEFAULT NULL COMMENT '组件路径',
|
||||
`query` varchar(255) DEFAULT NULL COMMENT '路由参数',
|
||||
`route_name` varchar(50) DEFAULT '' COMMENT '路由名称',
|
||||
`is_frame` int(1) DEFAULT '1' COMMENT '是否为外链(0是 1否)',
|
||||
`is_cache` int(1) DEFAULT '0' COMMENT '是否缓存(0缓存 1不缓存)',
|
||||
`menu_type` char(1) DEFAULT '' COMMENT '菜单类型(M目录 C菜单 F按钮)',
|
||||
`visible` char(1) DEFAULT '0' COMMENT '菜单状态(0显示 1隐藏)',
|
||||
`status` char(1) DEFAULT '0' COMMENT '菜单状态(0正常 1停用)',
|
||||
`perms` varchar(100) DEFAULT NULL COMMENT '权限标识',
|
||||
`icon` varchar(100) DEFAULT '#' COMMENT '菜单图标',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT '' COMMENT '备注',
|
||||
PRIMARY KEY (`menu_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=2003 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='菜单权限表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_notice`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_notice`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_notice` (
|
||||
`notice_id` int(4) NOT NULL AUTO_INCREMENT COMMENT '公告ID',
|
||||
`notice_title` varchar(50) NOT NULL COMMENT '公告标题',
|
||||
`notice_type` char(1) NOT NULL COMMENT '公告类型(1通知 2公告)',
|
||||
`notice_content` longblob COMMENT '公告内容',
|
||||
`status` char(1) DEFAULT '0' COMMENT '公告状态(0正常 1关闭)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(255) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`notice_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='通知公告表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_oper_log`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_oper_log`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_oper_log` (
|
||||
`oper_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '日志主键',
|
||||
`title` varchar(50) DEFAULT '' COMMENT '模块标题',
|
||||
`business_type` int(2) DEFAULT '0' COMMENT '业务类型(0其它 1新增 2修改 3删除)',
|
||||
`method` varchar(200) DEFAULT '' COMMENT '方法名称',
|
||||
`request_method` varchar(10) DEFAULT '' COMMENT '请求方式',
|
||||
`operator_type` int(1) DEFAULT '0' COMMENT '操作类别(0其它 1后台用户 2手机端用户)',
|
||||
`oper_name` varchar(50) DEFAULT '' COMMENT '操作人员',
|
||||
`dept_name` varchar(50) DEFAULT '' COMMENT '部门名称',
|
||||
`oper_url` varchar(255) DEFAULT '' COMMENT '请求URL',
|
||||
`oper_ip` varchar(128) DEFAULT '' COMMENT '主机地址',
|
||||
`oper_location` varchar(255) DEFAULT '' COMMENT '操作地点',
|
||||
`oper_param` varchar(2000) DEFAULT '' COMMENT '请求参数',
|
||||
`json_result` varchar(2000) DEFAULT '' COMMENT '返回参数',
|
||||
`status` int(1) DEFAULT '0' COMMENT '操作状态(0正常 1异常)',
|
||||
`error_msg` varchar(2000) DEFAULT '' COMMENT '错误消息',
|
||||
`oper_time` datetime DEFAULT NULL COMMENT '操作时间',
|
||||
`cost_time` bigint(20) DEFAULT '0' COMMENT '消耗时间',
|
||||
PRIMARY KEY (`oper_id`),
|
||||
KEY `idx_sys_oper_log_bt` (`business_type`),
|
||||
KEY `idx_sys_oper_log_s` (`status`),
|
||||
KEY `idx_sys_oper_log_ot` (`oper_time`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=125 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='操作日志记录';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_post`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_post`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_post` (
|
||||
`post_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '岗位ID',
|
||||
`post_code` varchar(64) NOT NULL COMMENT '岗位编码',
|
||||
`post_name` varchar(50) NOT NULL COMMENT '岗位名称',
|
||||
`post_sort` int(4) NOT NULL COMMENT '显示顺序',
|
||||
`status` char(1) NOT NULL COMMENT '状态(0正常 1停用)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`post_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='岗位信息表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_role`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_role`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_role` (
|
||||
`role_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
|
||||
`role_name` varchar(30) NOT NULL COMMENT '角色名称',
|
||||
`role_key` varchar(100) NOT NULL COMMENT '角色权限字符串',
|
||||
`role_sort` int(4) NOT NULL COMMENT '显示顺序',
|
||||
`data_scope` char(1) DEFAULT '1' COMMENT '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)',
|
||||
`menu_check_strictly` tinyint(1) DEFAULT '1' COMMENT '菜单树选择项是否关联显示',
|
||||
`dept_check_strictly` tinyint(1) DEFAULT '1' COMMENT '部门树选择项是否关联显示',
|
||||
`status` char(1) NOT NULL COMMENT '角色状态(0正常 1停用)',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`role_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='角色信息表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_role_dept`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_role_dept`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_role_dept` (
|
||||
`role_id` bigint(20) NOT NULL COMMENT '角色ID',
|
||||
`dept_id` bigint(20) NOT NULL COMMENT '部门ID',
|
||||
PRIMARY KEY (`role_id`,`dept_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='角色和部门关联表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_role_menu`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_role_menu`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_role_menu` (
|
||||
`role_id` bigint(20) NOT NULL COMMENT '角色ID',
|
||||
`menu_id` bigint(20) NOT NULL COMMENT '菜单ID',
|
||||
PRIMARY KEY (`role_id`,`menu_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='角色和菜单关联表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_user`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_user`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_user` (
|
||||
`user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '用户ID',
|
||||
`dept_id` bigint(20) DEFAULT NULL COMMENT '部门ID',
|
||||
`user_name` varchar(30) NOT NULL COMMENT '用户账号',
|
||||
`nick_name` varchar(30) NOT NULL COMMENT '用户昵称',
|
||||
`user_type` varchar(2) DEFAULT '00' COMMENT '用户类型(00系统用户)',
|
||||
`email` varchar(50) DEFAULT '' COMMENT '用户邮箱',
|
||||
`phonenumber` varchar(11) DEFAULT '' COMMENT '手机号码',
|
||||
`sex` char(1) DEFAULT '0' COMMENT '用户性别(0男 1女 2未知)',
|
||||
`avatar` varchar(100) DEFAULT '' COMMENT '头像地址',
|
||||
`password` varchar(100) DEFAULT '' COMMENT '密码',
|
||||
`status` char(1) DEFAULT '0' COMMENT '账号状态(0正常 1停用)',
|
||||
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||
`login_ip` varchar(128) DEFAULT '' COMMENT '最后登录IP',
|
||||
`login_date` datetime DEFAULT NULL COMMENT '最后登录时间',
|
||||
`pwd_update_date` datetime DEFAULT NULL COMMENT '密码最后更新时间',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`user_id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户信息表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_user_post`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_user_post`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_user_post` (
|
||||
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
|
||||
`post_id` bigint(20) NOT NULL COMMENT '岗位ID',
|
||||
PRIMARY KEY (`user_id`,`post_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户与岗位关联表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Table structure for table `sys_user_role`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `sys_user_role`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sys_user_role` (
|
||||
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
|
||||
`role_id` bigint(20) NOT NULL COMMENT '角色ID',
|
||||
PRIMARY KEY (`user_id`,`role_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户和角色关联表';
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2026-03-28 9:20:02
|
||||
42
sql/loan_pricing_workflow.sql
Normal file
42
sql/loan_pricing_workflow.sql
Normal file
@@ -0,0 +1,42 @@
|
||||
-- 利率定价流程表
|
||||
DROP TABLE IF EXISTS `loan_pricing_workflow`;
|
||||
CREATE TABLE `loan_pricing_workflow` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`serial_num` varchar(50) NOT NULL COMMENT '业务方流水号',
|
||||
`model_output_id` bigint(20) NULL COMMENT '模型输出id',
|
||||
`org_code` varchar(20) NOT NULL DEFAULT '892000' COMMENT '机构编码(统一值892000)',
|
||||
`run_type` varchar(10) NOT NULL DEFAULT '1' COMMENT '运行模式: 1-同步',
|
||||
`cust_isn` varchar(50) NOT NULL COMMENT '客户内码',
|
||||
`cust_type` varchar(20) NOT NULL COMMENT '客户类型: 个人/企业',
|
||||
`guar_type` varchar(20) NOT NULL COMMENT '担保方式: 信用/保证/抵押/质押',
|
||||
`mid_per_quick_pay` varchar(10) DEFAULT NULL COMMENT '中间业务_个人_快捷支付: true/false',
|
||||
`mid_per_ele_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_个人_电费代扣: true/false',
|
||||
`mid_ent_ele_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_企业_电费代扣: true/false',
|
||||
`mid_ent_water_ddc` varchar(10) DEFAULT NULL COMMENT '中间业务_企业_水费代扣: true/false',
|
||||
`apply_amt` varchar(50) NOT NULL COMMENT '申请金额(元)',
|
||||
`is_clean_ent` varchar(10) DEFAULT NULL COMMENT '净身企业: true/false',
|
||||
`has_settle_acct` varchar(10) DEFAULT NULL COMMENT '开立基本结算账户: true/false',
|
||||
`is_manufacturing` varchar(10) DEFAULT NULL COMMENT '制造业企业: true/false',
|
||||
`is_agri_guar` varchar(10) DEFAULT NULL COMMENT '省农担担保贷款: true/false',
|
||||
`is_tax_a` varchar(10) DEFAULT NULL COMMENT '是否纳税信用等级A级: true/false',
|
||||
`is_agri_leading` varchar(10) DEFAULT NULL COMMENT '是否县级及以上农业龙头企业: true/false',
|
||||
`loan_purpose` varchar(20) DEFAULT NULL COMMENT '贷款用途: consumer-消费/business-经营',
|
||||
`biz_proof` varchar(10) DEFAULT NULL COMMENT '是否有经营佐证: true/false',
|
||||
`coll_type` varchar(20) DEFAULT NULL COMMENT '抵质押类型: 一线/一类/二类',
|
||||
`coll_third_party` varchar(10) DEFAULT NULL COMMENT '抵质押物是否三方所有: true/false',
|
||||
`loan_rate` varchar(20) NOT NULL COMMENT '贷款利率',
|
||||
`execute_rate` varchar(20) DEFAULT NULL COMMENT '执行利率(%)',
|
||||
`cust_name` varchar(100) DEFAULT NULL COMMENT '客户名称',
|
||||
`id_type` varchar(50) DEFAULT NULL COMMENT '证件类型',
|
||||
`is_inclusive_finance` varchar(10) DEFAULT NULL COMMENT '是否普惠小微借款人: true/false',
|
||||
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
|
||||
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_serial_num` (`serial_num`),
|
||||
KEY `idx_org_code` (`org_code`),
|
||||
KEY `idx_create_by` (`create_by`),
|
||||
KEY `idx_cust_name` (`cust_name`),
|
||||
KEY `idx_update_time` (`update_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='利率定价流程表';
|
||||
59
sql/model_corp.sql
Normal file
59
sql/model_corp.sql
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 客户贷款利率测算表
|
||||
*/
|
||||
DROP TABLE IF EXISTS model_corp_output_fields;
|
||||
CREATE TABLE `model_corp_output_fields` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增主键ID',
|
||||
`cust_isn` VARCHAR(100) COMMENT '客户内码',
|
||||
`cust_type` VARCHAR(100) COMMENT '客户类型',
|
||||
`guar_type` VARCHAR(100) COMMENT '担保方式',
|
||||
`cust_name` VARCHAR(100) COMMENT '客户名称',
|
||||
`id_type` VARCHAR(100) COMMENT '证件类型',
|
||||
`id_num` VARCHAR(100) COMMENT '证件号码',
|
||||
`base_loan_rate` VARCHAR(100) COMMENT '基准利率',
|
||||
`is_first_loan` VARCHAR(100) COMMENT '我行首贷客户',
|
||||
`faith_day` VARCHAR(100) COMMENT '用信天数',
|
||||
`bp_first_loan` VARCHAR(100) COMMENT 'BP_首贷',
|
||||
`bp_age_loan` VARCHAR(100) COMMENT 'BP_贷龄',
|
||||
`total_bp_loyalty` VARCHAR(100) COMMENT 'TOTAL_BP_忠诚度',
|
||||
`balance_avg` VARCHAR(100) COMMENT '存款年日均',
|
||||
`loan_avg` VARCHAR(100) COMMENT '贷款年日均',
|
||||
`derivation_rate` VARCHAR(100) COMMENT '派生率',
|
||||
`total_bp_contribution` VARCHAR(100) COMMENT 'TOTAL_BP_贡献度',
|
||||
`mid_ent_connect` VARCHAR(100) COMMENT '中间业务_企业_企业互联',
|
||||
`mid_ent_effect` VARCHAR(100) COMMENT '中间业务_企业_有效价值客户',
|
||||
`mid_ent_inter` VARCHAR(100) COMMENT '中间业务_企业_国际业务',
|
||||
`mid_ent_accept` VARCHAR(100) COMMENT '中间业务_企业_承兑',
|
||||
`mid_ent_discount` VARCHAR(100) COMMENT '中间业务_企业_贴现',
|
||||
`mid_ent_ele_ddc` VARCHAR(100) COMMENT '中间业务_企业_电费代扣',
|
||||
`mid_ent_water_ddc` VARCHAR(100) COMMENT '中间业务_企业_水费代扣',
|
||||
`mid_ent_tax` VARCHAR(100) COMMENT '中间业务_企业_税务代扣',
|
||||
`bp_mid` VARCHAR(100) COMMENT 'BP_中间业务',
|
||||
`payroll` VARCHAR(100) COMMENT '代发工资户数',
|
||||
`inv_loan_amount` VARCHAR(100) COMMENT '存量贷款余额',
|
||||
`bp_payroll` VARCHAR(100) COMMENT 'BP_代发工资',
|
||||
`is_clean_ent` VARCHAR(100) COMMENT '净身企业',
|
||||
`has_settle_acct` VARCHAR(100) COMMENT '开立基本结算账户',
|
||||
`is_agri_guar` VARCHAR(100) COMMENT '省农担担保贷款',
|
||||
`is_green_loan` VARCHAR(100) COMMENT '绿色贷款',
|
||||
`is_tech_ent` VARCHAR(100) COMMENT '科技型企业',
|
||||
`bp_ent_type` VARCHAR(100) COMMENT 'BP_企业客户类别',
|
||||
`totoal_bp_relevance` VARCHAR(100) COMMENT 'TOTAL_BP_关联度',
|
||||
`loan_term` VARCHAR(100) COMMENT '贷款期限',
|
||||
`bp_loan_term` VARCHAR(100) COMMENT 'BP_贷款期限',
|
||||
`apply_amt` VARCHAR(100) COMMENT '申请金额',
|
||||
`bp_loan_amount` VARCHAR(100) COMMENT 'BP_贷款额度',
|
||||
`coll_type` VARCHAR(100) COMMENT '抵质押类型',
|
||||
`coll_third_party` VARCHAR(100) COMMENT '抵质押物是否三方所有',
|
||||
`bp_collateral` VARCHAR(100) COMMENT 'BP_抵押物',
|
||||
`grey_cust` VARCHAR(100) COMMENT '灰名单客户',
|
||||
`prin_overdue` VARCHAR(100) COMMENT '本金逾期',
|
||||
`interest_overdue` VARCHAR(100) COMMENT '利息逾期',
|
||||
`card_overdue` VARCHAR(100) COMMENT '信用卡逾期',
|
||||
`bp_grey_overdue` VARCHAR(100) COMMENT 'BP_灰名单与逾期',
|
||||
`totoal_bp_risk` VARCHAR(100) COMMENT 'TOTAL_BP_风险度',
|
||||
`total_bp` VARCHAR(100) COMMENT '浮动BP',
|
||||
`calculate_rate` VARCHAR(100) COMMENT '测算利率',
|
||||
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='客户贷款利率测算表';
|
||||
124
sql/model_retail.sql
Normal file
124
sql/model_retail.sql
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 零售模型输出字段表
|
||||
* 存储客户基本信息、BP评分、资产信息、风险信息等贷款测算相关数据
|
||||
*/
|
||||
DROP TABLE IF EXISTS model_retail_output_fields;
|
||||
CREATE TABLE IF NOT EXISTS model_retail_output_fields (
|
||||
-- 主键ID(自增,用于表的唯一标识)
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
-- 客户内码(业务唯一标识)
|
||||
cust_isn VARCHAR(100) NOT NULL COMMENT '客户内码',
|
||||
-- 客户类型(如:个人/企业)
|
||||
cust_type VARCHAR(100) DEFAULT '' COMMENT '客户类型',
|
||||
-- 担保方式(如:信用担保/抵押担保)
|
||||
guar_type VARCHAR(100) DEFAULT '' COMMENT '担保方式',
|
||||
-- 客户名称
|
||||
cust_name VARCHAR(100) DEFAULT '' COMMENT '客户名称',
|
||||
-- 证件类型(如:身份证/营业执照)
|
||||
id_type VARCHAR(100) DEFAULT '' COMMENT '证件类型',
|
||||
-- 证件号码(脱敏存储)
|
||||
id_num VARCHAR(100) DEFAULT '' COMMENT '证件号码',
|
||||
-- 基准利率(百分比,如4.35)
|
||||
base_loan_rate VARCHAR(100) DEFAULT '' COMMENT '基准利率',
|
||||
-- 我行首贷客户(是/否)
|
||||
is_first_loan VARCHAR(100) DEFAULT '' COMMENT '我行首贷客户',
|
||||
-- 用信天数
|
||||
faith_day VARCHAR(100) DEFAULT '' COMMENT '用信天数',
|
||||
-- 客户年龄
|
||||
cust_age VARCHAR(100) DEFAULT '' COMMENT '客户年龄',
|
||||
-- BP_首贷
|
||||
bp_first_loan VARCHAR(100) DEFAULT '' COMMENT 'BP_首贷',
|
||||
-- BP_贷龄
|
||||
bp_age_loan VARCHAR(100) DEFAULT '' COMMENT 'BP_贷龄',
|
||||
-- BP_年龄
|
||||
bp_age VARCHAR(100) DEFAULT '' COMMENT 'BP_年龄',
|
||||
-- TOTAL_BP_忠诚度
|
||||
total_bp_loyalty VARCHAR(100) DEFAULT '' COMMENT 'TOTAL_BP_忠诚度',
|
||||
-- 存款年日均(元)
|
||||
balance_avg VARCHAR(100) DEFAULT '' COMMENT '存款年日均',
|
||||
-- 贷款年日均(元)
|
||||
loan_avg VARCHAR(100) DEFAULT '' COMMENT '贷款年日均',
|
||||
-- 派生率
|
||||
derivation_rate VARCHAR(100) DEFAULT '' COMMENT '派生率',
|
||||
-- TOTAL_BP_贡献度
|
||||
total_bp_contribution VARCHAR(100) DEFAULT '' COMMENT 'TOTAL_BP_贡献度',
|
||||
-- 中间业务_个人_信用卡
|
||||
mid_per_card VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_信用卡',
|
||||
-- 中间业务_个人_一码通
|
||||
mid_per_pass VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_一码通',
|
||||
-- 中间业务_个人_丰收互联
|
||||
mid_per_harvest VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_丰收互联',
|
||||
-- 中间业务_个人_有效客户(是/否)
|
||||
mid_per_effect VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_有效客户',
|
||||
-- 中间业务_个人_快捷支付
|
||||
mid_per_quick_pay VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_快捷支付',
|
||||
-- 中间业务_个人_电费代扣
|
||||
mid_per_ele_ddc VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_电费代扣',
|
||||
-- 中间业务_个人_水费代扣
|
||||
mid_per_water_ddc VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_水费代扣',
|
||||
-- 中间业务_个人_华数费代扣
|
||||
mid_per_huashu_ddc VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_华数费代扣',
|
||||
-- 中间业务_个人_煤气费代扣
|
||||
mid_per_gas_ddc VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_煤气费代扣',
|
||||
-- 中间业务_个人_市民卡
|
||||
mid_per_citizencard VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_市民卡',
|
||||
-- 中间业务_个人_理财业务
|
||||
mid_per_fin_man VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_理财业务',
|
||||
-- 中间业务_个人_etc
|
||||
mid_per_etc VARCHAR(100) DEFAULT '' COMMENT '中间业务_个人_etc',
|
||||
-- BP_中间业务
|
||||
bp_mid VARCHAR(100) DEFAULT '' COMMENT 'BP_中间业务',
|
||||
-- TOTAL_BP_关联度
|
||||
totoal_bp_relevance VARCHAR(100) DEFAULT '' COMMENT 'TOTAL_BP_关联度',
|
||||
-- 申请金额(元)
|
||||
apply_amt VARCHAR(100) DEFAULT '' COMMENT '申请金额',
|
||||
-- BP_贷款额度
|
||||
bp_loan_amount VARCHAR(100) DEFAULT '' COMMENT 'BP_贷款额度',
|
||||
-- 贷款用途(如:个人消费/经营)
|
||||
loan_purpose VARCHAR(100) DEFAULT '' COMMENT '贷款用途',
|
||||
-- 是否有经营佐证(是/否)
|
||||
biz_proof VARCHAR(100) DEFAULT '' COMMENT '是否有经营佐证',
|
||||
-- BP_贷款用途
|
||||
bp_loan_use VARCHAR(100) DEFAULT '' COMMENT 'BP_贷款用途',
|
||||
-- 循环功能(支持/不支持)
|
||||
loan_loop VARCHAR(100) DEFAULT '' COMMENT '循环功能',
|
||||
-- BP_循环功能
|
||||
bp_loan_loop VARCHAR(100) DEFAULT '' COMMENT 'BP_循环功能',
|
||||
-- 抵质押类型(如:无抵质押/房产抵押)
|
||||
coll_type VARCHAR(100) DEFAULT '' COMMENT '抵质押类型',
|
||||
-- 抵质押物是否三方所有(是/否)
|
||||
coll_third_party VARCHAR(100) DEFAULT '' COMMENT '抵质押物是否三方所有',
|
||||
-- BP_抵押物
|
||||
bp_collateral VARCHAR(100) DEFAULT '' COMMENT 'BP_抵押物',
|
||||
-- 灰名单客户(是/否)
|
||||
grey_cust VARCHAR(100) DEFAULT '' COMMENT '灰名单客户',
|
||||
-- 本金逾期(是/否)
|
||||
prin_overdue VARCHAR(100) DEFAULT '' COMMENT '本金逾期',
|
||||
-- 利息逾期(是/否)
|
||||
interest_overdue VARCHAR(100) DEFAULT '' COMMENT '利息逾期',
|
||||
-- 信用卡逾期(是/否)
|
||||
card_overdue VARCHAR(100) DEFAULT '' COMMENT '信用卡逾期',
|
||||
-- BP_灰名单与逾期
|
||||
bp_grey_overdue VARCHAR(100) DEFAULT '' COMMENT 'BP_灰名单与逾期',
|
||||
-- TOTAL_BP_风险度
|
||||
totoal_bp_risk VARCHAR(100) DEFAULT '' COMMENT 'TOTAL_BP_风险度',
|
||||
-- 浮动BP
|
||||
total_bp VARCHAR(100) DEFAULT '' COMMENT '浮动BP',
|
||||
-- 测算利率(百分比,如6.15)
|
||||
calculate_rate VARCHAR(100) DEFAULT '' COMMENT '测算利率',
|
||||
-- 历史利率
|
||||
loan_rate_history VARCHAR(100) DEFAULT '' COMMENT '历史利率',
|
||||
-- 产品最低利率下限
|
||||
min_rate_product VARCHAR(100) DEFAULT '' COMMENT '产品最低利率下限',
|
||||
-- 平滑幅度
|
||||
smooth_range VARCHAR(100) DEFAULT '' COMMENT '平滑幅度',
|
||||
-- 最终测算利率
|
||||
final_calculate_rate VARCHAR(100) DEFAULT '' COMMENT '最终测算利率',
|
||||
-- 参考利率
|
||||
reference_rate VARCHAR(100) DEFAULT '' COMMENT '参考利率',
|
||||
-- 创建时间(审计字段)
|
||||
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
-- 主键约束
|
||||
PRIMARY KEY (id)
|
||||
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='零售模型输出字段表';
|
||||
224
test_api/test_corporate_create.http
Normal file
224
test_api/test_corporate_create.http
Normal file
@@ -0,0 +1,224 @@
|
||||
### ============================================================
|
||||
### 企业客户利率定价流程接口测试脚本
|
||||
### 用途:测试企业客户发起接口的各项场景
|
||||
### ============================================================
|
||||
|
||||
### ============================================================
|
||||
### 1. 获取测试 Token(如果未获取)
|
||||
### ============================================================
|
||||
POST http://localhost:63310/login/test
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "admin123"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Request executed successfully", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 200, "Response code is 200");
|
||||
client.global.set("token", response.body.data.token);
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 2. 企业客户发起 - 成功场景(完整必填字段)
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/corporate
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "CORP001",
|
||||
"custName": "测试科技有限公司",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000000X",
|
||||
"guarType": "抵押",
|
||||
"applyAmt": "1000000",
|
||||
"loanTerm": "36",
|
||||
"isAgriGuar": "false",
|
||||
"isGreenLoan": "true",
|
||||
"isTechEnt": "true"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Corporate loan creation successful", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 200, "Response code is 200");
|
||||
client.assert(response.body.data.custType === "企业", "Customer type is 企业");
|
||||
client.assert(response.body.data.serialNum !== null, "Serial number is generated");
|
||||
client.assert(response.body.data.loanTerm === "36", "Loan term is correct");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 3. 企业客户发起 - 缺少必填字段 custIsn
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/corporate
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custName": "测试企业2",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000001X",
|
||||
"guarType": "信用",
|
||||
"applyAmt": "500000"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Missing custIsn validation works", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 500, "Response code indicates validation error");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 4. 企业客户发起 - 缺少必填字段 guarType
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/corporate
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "CORP002",
|
||||
"custName": "测试企业3",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000002X",
|
||||
"applyAmt": "800000"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Missing guarType validation works", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 500, "Response code indicates validation error");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 5. 企业客户发起 - 缺少必填字段 applyAmt
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/corporate
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "CORP003",
|
||||
"custName": "测试企业4",
|
||||
"guarType": "保证",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000003X"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Missing applyAmt validation works", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 500, "Response code indicates validation error");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 6. 企业客户发起 - 担保方式枚举验证失败
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/corporate
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "CORP004",
|
||||
"custName": "测试企业5",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000004X",
|
||||
"guarType": "无效值",
|
||||
"applyAmt": "600000"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Invalid guarType validation works", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 500, "Response code indicates validation error");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 7. 企业客户发起 - 包含省农担担保贷款标识
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/corporate
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "CORP005",
|
||||
"custName": "农业科技有限公司",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000005X",
|
||||
"guarType": "保证",
|
||||
"applyAmt": "2000000",
|
||||
"loanTerm": "60",
|
||||
"isAgriGuar": "true"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Corporate loan with agricultural guarantee", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 200, "Response code is 200");
|
||||
client.assert(response.body.data.isAgriGuar === "true", "Agricultural guarantee is set");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 8. 企业客户发起 - 贸易和建筑业企业标识
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/corporate
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "CORP006",
|
||||
"custName": "建筑工程有限公司",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000006X",
|
||||
"guarType": "质押",
|
||||
"applyAmt": "1500000",
|
||||
"loanTerm": "24",
|
||||
"isTradeConstruction": "true"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Corporate loan for trade/construction", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 200, "Response code is 200");
|
||||
client.assert(response.body.data.isTradeConstruction === "true", "Trade/construction flag is set");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 9. 企业客户发起 - 所有字段必填(信用贷款场景)
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/corporate
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "CORP007",
|
||||
"custName": "科技创新有限公司",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000007X",
|
||||
"guarType": "信用",
|
||||
"applyAmt": "3000000",
|
||||
"loanTerm": "12",
|
||||
"isAgriGuar": "false",
|
||||
"isGreenLoan": "true",
|
||||
"isTechEnt": "true",
|
||||
"isTradeConstruction": "false",
|
||||
"collType": "一类",
|
||||
"collThirdParty": "false"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Corporate loan with all required fields", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 200, "Response code is 200");
|
||||
});
|
||||
%}
|
||||
311
test_api/test_corporate_create.sh
Normal file
311
test_api/test_corporate_create.sh
Normal file
@@ -0,0 +1,311 @@
|
||||
#!/bin/bash
|
||||
# ============================================================
|
||||
# 企业客户利率定价流程接口测试脚本
|
||||
# 用途:测试企业客户发起接口的各项场景
|
||||
# 使用方法: ./test_corporate_create.sh
|
||||
# ============================================================
|
||||
|
||||
# 配置
|
||||
BASE_URL="http://localhost:63310"
|
||||
LOGIN_URL="${BASE_URL}/login/test"
|
||||
CORPORATE_CREATE_URL="${BASE_URL}/loanPricing/workflow/create/corporate"
|
||||
|
||||
# 颜色输出
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 测试结果统计
|
||||
TESTS_PASSED=0
|
||||
TESTS_FAILED=0
|
||||
|
||||
# ============================================================
|
||||
# 函数:打印测试结果
|
||||
# ============================================================
|
||||
print_result() {
|
||||
local test_name="$1"
|
||||
local result="$2"
|
||||
|
||||
if [ "$result" == "0" ]; then
|
||||
echo -e "${GREEN}✓${NC} $test_name - ${GREEN}PASSED${NC}"
|
||||
((TESTS_PASSED++))
|
||||
else
|
||||
echo -e "${RED}✗${NC} $test_name - ${RED}FAILED${NC}"
|
||||
((TESTS_FAILED++))
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# 步骤 1: 获取测试 Token
|
||||
# ============================================================
|
||||
echo "=========================================="
|
||||
echo "步骤 1: 获取测试 Token"
|
||||
echo "=========================================="
|
||||
|
||||
TOKEN_RESPONSE=$(curl -s -X POST "$LOGIN_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"username": "admin",
|
||||
"password": "admin123"
|
||||
}')
|
||||
|
||||
TOKEN=$(echo "$TOKEN_RESPONSE" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo -e "${RED}获取 Token 失败${NC}"
|
||||
echo "响应: $TOKEN_RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Token 获取成功${NC}"
|
||||
echo "Token: ${TOKEN:0:20}..."
|
||||
|
||||
# ============================================================
|
||||
# 步骤 2: 测试企业客户发起 - 成功场景
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 2: 测试企业客户发起 - 成功场景"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$CORPORATE_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "CORP001",
|
||||
"custName": "测试科技有限公司",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000000X",
|
||||
"guarType": "抵押",
|
||||
"applyAmt": "1000000",
|
||||
"loanTerm": "36",
|
||||
"isAgriGuar": "false",
|
||||
"isGreenLoan": "true",
|
||||
"isTechEnt": "true"
|
||||
}')
|
||||
|
||||
# 检查响应
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
CUST_TYPE=$(echo "$RESPONSE" | grep -o '"custType":"[^"]*"' | cut -d'"' -f4)
|
||||
SERIAL_NUM=$(echo "$RESPONSE" | grep -o '"serialNum":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
if [ "$CODE" == "200" ] && [ "$CUST_TYPE" == "企业" ] && [ -n "$SERIAL_NUM" ]; then
|
||||
print_result "企业客户发起成功场景" "0"
|
||||
echo " 业务流水号: $SERIAL_NUM"
|
||||
else
|
||||
print_result "企业客户发起成功场景" "1"
|
||||
echo " 响应: $RESPONSE"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 3: 测试缺少必填字段 custIsn
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 3: 测试缺少必填字段 custIsn"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$CORPORATE_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custName": "测试企业2",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000001X",
|
||||
"guarType": "信用",
|
||||
"applyAmt": "500000"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
if [ "$CODE" == "500" ]; then
|
||||
print_result "缺少 custIsn 字段验证" "0"
|
||||
else
|
||||
print_result "缺少 custIsn 字段验证" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 4: 测试缺少必填字段 guarType
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 4: 测试缺少必填字段 guarType"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$CORPORATE_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "CORP002",
|
||||
"custName": "测试企业3",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000002X",
|
||||
"applyAmt": "800000"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
if [ "$CODE" == "500" ]; then
|
||||
print_result "缺少 guarType 字段验证" "0"
|
||||
else
|
||||
print_result "缺少 guarType 字段验证" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 5: 测试缺少必填字段 applyAmt
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 5: 测试缺少必填字段 applyAmt"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$CORPORATE_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "CORP003",
|
||||
"custName": "测试企业4",
|
||||
"guarType": "保证",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000003X"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
if [ "$CODE" == "500" ]; then
|
||||
print_result "缺少 applyAmt 字段验证" "0"
|
||||
else
|
||||
print_result "缺少 applyAmt 字段验证" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 6: 测试担保方式枚举验证失败
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 6: 测试担保方式枚举验证失败"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$CORPORATE_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "CORP004",
|
||||
"custName": "测试企业5",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000004X",
|
||||
"guarType": "无效值",
|
||||
"applyAmt": "600000"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
if [ "$CODE" == "500" ]; then
|
||||
print_result "担保方式枚举验证" "0"
|
||||
else
|
||||
print_result "担保方式枚举验证" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 7: 测试省农担担保贷款标识
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 7: 测试省农担担保贷款标识"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$CORPORATE_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "CORP005",
|
||||
"custName": "农业科技有限公司",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000005X",
|
||||
"guarType": "保证",
|
||||
"applyAmt": "2000000",
|
||||
"loanTerm": "60",
|
||||
"isAgriGuar": "true"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
IS_AGRI_GUAR=$(echo "$RESPONSE" | grep -o '"isAgriGuar":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
if [ "$CODE" == "200" ] && [ "$IS_AGRI_GUAR" == "true" ]; then
|
||||
print_result "省农担担保贷款标识正确保存" "0"
|
||||
echo " 省农担标识: $IS_AGRI_GUAR"
|
||||
else
|
||||
print_result "省农担担保贷款标识正确保存" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 8: 测试贸易和建筑业企业标识
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 8: 测试贸易和建筑业企业标识"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$CORPORATE_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "CORP006",
|
||||
"custName": "建筑工程有限公司",
|
||||
"idType": "统一社会信用代码",
|
||||
"idNum": "91110000100000006X",
|
||||
"guarType": "质押",
|
||||
"applyAmt": "1500000",
|
||||
"loanTerm": "24",
|
||||
"isTradeConstruction": "true"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
IS_TRADE_CONSTRUCTION=$(echo "$RESPONSE" | grep -o '"isTradeConstruction":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
if [ "$CODE" == "200" ] && [ "$IS_TRADE_CONSTRUCTION" == "true" ]; then
|
||||
print_result "贸易和建筑业企业标识正确保存" "0"
|
||||
echo " 贸易建筑标识: $IS_TRADE_CONSTRUCTION"
|
||||
else
|
||||
print_result "贸易和建筑业企业标识正确保存" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 9: 测试最小必填字段
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 9: 测试最小必填字段"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$CORPORATE_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "CORP007",
|
||||
"guarType": "信用",
|
||||
"applyAmt": "3000000"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
if [ "$CODE" == "200" ]; then
|
||||
print_result "最小必填字段测试" "0"
|
||||
else
|
||||
print_result "最小必填字段测试" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 测试结果汇总
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "测试结果汇总"
|
||||
echo "=========================================="
|
||||
echo -e "${GREEN}通过: $TESTS_PASSED${NC}"
|
||||
echo -e "${RED}失败: $TESTS_FAILED${NC}"
|
||||
echo "总计: $((TESTS_PASSED + TESTS_FAILED))"
|
||||
|
||||
if [ $TESTS_FAILED -eq 0 ]; then
|
||||
echo -e "\n${GREEN}所有测试通过!${NC}"
|
||||
exit 0
|
||||
else
|
||||
echo -e "\n${RED}存在测试失败,请检查日志${NC}"
|
||||
exit 1
|
||||
fi
|
||||
196
test_api/test_personal_create.http
Normal file
196
test_api/test_personal_create.http
Normal file
@@ -0,0 +1,196 @@
|
||||
### ============================================================
|
||||
### 个人客户利率定价流程接口测试脚本
|
||||
### 用途:测试个人客户发起接口的各项场景
|
||||
### ============================================================
|
||||
|
||||
### ============================================================
|
||||
### 1. 获取测试 Token
|
||||
### ============================================================
|
||||
POST http://localhost:63310/login/test
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"username": "admin",
|
||||
"password": "admin123"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Request executed successfully", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 200, "Response code is 200");
|
||||
client.global.set("token", response.body.data.token);
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 2. 个人客户发起 - 成功场景(完整必填字段)
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/personal
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "TEST001",
|
||||
"custName": "张三",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011234",
|
||||
"guarType": "信用",
|
||||
"applyAmt": "500000",
|
||||
"bizProof": "true",
|
||||
"loanLoop": "false"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Personal loan creation successful", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 200, "Response code is 200");
|
||||
client.assert(response.body.data.custType === "个人", "Customer type is 个人");
|
||||
client.assert(response.body.data.serialNum !== null, "Serial number is generated");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 3. 个人客户发起 - 缺少必填字段 custIsn
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/personal
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custName": "张三",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011234",
|
||||
"guarType": "信用",
|
||||
"applyAmt": "500000"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Missing custIsn validation works", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 500, "Response code indicates validation error");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 4. 个人客户发起 - 缺少必填字段 guarType
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/personal
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "TEST002",
|
||||
"custName": "李四",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011235",
|
||||
"applyAmt": "300000"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Missing guarType validation works", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 500, "Response code indicates validation error");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 5. 个人客户发起 - 缺少必填字段 applyAmt
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/personal
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "TEST003",
|
||||
"custName": "王五",
|
||||
"guarType": "保证",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011236"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Missing applyAmt validation works", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 500, "Response code indicates validation error");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 6. 个人客户发起 - 担保方式枚举验证失败
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/personal
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "TEST004",
|
||||
"custName": "赵六",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011237",
|
||||
"guarType": "无效值",
|
||||
"applyAmt": "200000"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Invalid guarType validation works", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 500, "Response code indicates validation error");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 7. 个人客户发起 - 包含抵质押信息
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/personal
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "TEST005",
|
||||
"custName": "孙七",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011238",
|
||||
"guarType": "抵押",
|
||||
"applyAmt": "800000",
|
||||
"bizProof": "true",
|
||||
"loanLoop": "true",
|
||||
"collType": "一类",
|
||||
"collThirdParty": "false"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Personal loan with collateral info", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 200, "Response code is 200");
|
||||
client.assert(response.body.data.collType === "一类", "Collateral type is correct");
|
||||
client.assert(response.body.data.loanLoop === "true", "Loan loop is set");
|
||||
});
|
||||
%}
|
||||
|
||||
### ============================================================
|
||||
### 8. 个人客户发起 - 所有字段必填(质押贷款场景)
|
||||
### ============================================================
|
||||
POST http://localhost:63310/loanPricing/workflow/create/personal
|
||||
Authorization: Bearer {{token}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"custIsn": "TEST006",
|
||||
"custName": "周八",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011239",
|
||||
"guarType": "质押",
|
||||
"applyAmt": "100000",
|
||||
"bizProof": "false",
|
||||
"loanLoop": "false",
|
||||
"collType": "二类",
|
||||
"collThirdParty": "true"
|
||||
}
|
||||
|
||||
> {%
|
||||
client.test("Personal loan with all required fields", function () {
|
||||
client.assert(response.status === 200, "Response status is 200");
|
||||
client.assert(response.body.code === 200, "Response code is 200");
|
||||
client.assert(response.body.data.collThirdParty === "true", "Collateral third party is set");
|
||||
});
|
||||
%}
|
||||
281
test_api/test_personal_create.sh
Normal file
281
test_api/test_personal_create.sh
Normal file
@@ -0,0 +1,281 @@
|
||||
#!/bin/bash
|
||||
# ============================================================
|
||||
# 个人客户利率定价流程接口测试脚本
|
||||
# 用途:测试个人客户发起接口的各项场景
|
||||
# 使用方法: ./test_personal_create.sh
|
||||
# ============================================================
|
||||
|
||||
# 配置
|
||||
BASE_URL="http://localhost:63310"
|
||||
LOGIN_URL="${BASE_URL}/login/test"
|
||||
PERSONAL_CREATE_URL="${BASE_URL}/loanPricing/workflow/create/personal"
|
||||
|
||||
# 颜色输出
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# 测试结果统计
|
||||
TESTS_PASSED=0
|
||||
TESTS_FAILED=0
|
||||
|
||||
# ============================================================
|
||||
# 函数:打印测试结果
|
||||
# ============================================================
|
||||
print_result() {
|
||||
local test_name="$1"
|
||||
local result="$2"
|
||||
|
||||
if [ "$result" == "0" ]; then
|
||||
echo -e "${GREEN}✓${NC} $test_name - ${GREEN}PASSED${NC}"
|
||||
((TESTS_PASSED++))
|
||||
else
|
||||
echo -e "${RED}✗${NC} $test_name - ${RED}FAILED${NC}"
|
||||
((TESTS_FAILED++))
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================
|
||||
# 步骤 1: 获取测试 Token
|
||||
# ============================================================
|
||||
echo "=========================================="
|
||||
echo "步骤 1: 获取测试 Token"
|
||||
echo "=========================================="
|
||||
|
||||
TOKEN_RESPONSE=$(curl -s -X POST "$LOGIN_URL" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"username": "admin",
|
||||
"password": "admin123"
|
||||
}')
|
||||
|
||||
TOKEN=$(echo "$TOKEN_RESPONSE" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo -e "${RED}获取 Token 失败${NC}"
|
||||
echo "响应: $TOKEN_RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Token 获取成功${NC}"
|
||||
echo "Token: ${TOKEN:0:20}..."
|
||||
|
||||
# ============================================================
|
||||
# 步骤 2: 测试个人客户发起 - 成功场景
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 2: 测试个人客户发起 - 成功场景"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$PERSONAL_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "TEST001",
|
||||
"custName": "张三",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011234",
|
||||
"guarType": "信用",
|
||||
"applyAmt": "500000",
|
||||
"bizProof": "true",
|
||||
"loanLoop": "false"
|
||||
}')
|
||||
|
||||
# 检查响应
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
CUST_TYPE=$(echo "$RESPONSE" | grep -o '"custType":"[^"]*"' | cut -d'"' -f4)
|
||||
SERIAL_NUM=$(echo "$RESPONSE" | grep -o '"serialNum":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
if [ "$CODE" == "200" ] && [ "$CUST_TYPE" == "个人" ] && [ -n "$SERIAL_NUM" ]; then
|
||||
print_result "个人客户发起成功场景" "0"
|
||||
echo " 业务流水号: $SERIAL_NUM"
|
||||
else
|
||||
print_result "个人客户发起成功场景" "1"
|
||||
echo " 响应: $RESPONSE"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 3: 测试缺少必填字段 custIsn
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 3: 测试缺少必填字段 custIsn"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$PERSONAL_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custName": "李四",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011235",
|
||||
"guarType": "信用",
|
||||
"applyAmt": "300000"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
if [ "$CODE" == "500" ]; then
|
||||
print_result "缺少 custIsn 字段验证" "0"
|
||||
else
|
||||
print_result "缺少 custIsn 字段验证" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 4: 测试缺少必填字段 guarType
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 4: 测试缺少必填字段 guarType"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$PERSONAL_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "TEST002",
|
||||
"custName": "王五",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011236",
|
||||
"applyAmt": "300000"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
if [ "$CODE" == "500" ]; then
|
||||
print_result "缺少 guarType 字段验证" "0"
|
||||
else
|
||||
print_result "缺少 guarType 字段验证" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 5: 测试缺少必填字段 applyAmt
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 5: 测试缺少必填字段 applyAmt"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$PERSONAL_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "TEST003",
|
||||
"custName": "赵六",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011237",
|
||||
"guarType": "保证"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
if [ "$CODE" == "500" ]; then
|
||||
print_result "缺少 applyAmt 字段验证" "0"
|
||||
else
|
||||
print_result "缺少 applyAmt 字段验证" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 6: 测试担保方式枚举验证失败
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 6: 测试担保方式枚举验证失败"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$PERSONAL_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "TEST004",
|
||||
"custName": "孙七",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011238",
|
||||
"guarType": "无效值",
|
||||
"applyAmt": "200000"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
if [ "$CODE" == "500" ]; then
|
||||
print_result "担保方式枚举验证" "0"
|
||||
else
|
||||
print_result "担保方式枚举验证" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 7: 测试包含抵质押信息
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 7: 测试包含抵质押信息"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$PERSONAL_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "TEST005",
|
||||
"custName": "周八",
|
||||
"idType": "身份证",
|
||||
"idNum": "110101199001011239",
|
||||
"guarType": "抵押",
|
||||
"applyAmt": "800000",
|
||||
"bizProof": "true",
|
||||
"loanLoop": "true",
|
||||
"collType": "一类",
|
||||
"collThirdParty": "false"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
COLL_TYPE=$(echo "$RESPONSE" | grep -o '"collType":"[^"]*"' | cut -d'"' -f4)
|
||||
LOAN_LOOP=$(echo "$RESPONSE" | grep -o '"loanLoop":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
if [ "$CODE" == "200" ] && [ "$COLL_TYPE" == "一类" ] && [ "$LOAN_LOOP" == "true" ]; then
|
||||
print_result "抵质押信息正确保存" "0"
|
||||
echo " 抵质押类型: $COLL_TYPE"
|
||||
echo " 循环功能: $LOAN_LOOP"
|
||||
else
|
||||
print_result "抵质押信息正确保存" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 步骤 8: 测试最小必填字段
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "步骤 8: 测试最小必填字段"
|
||||
echo "=========================================="
|
||||
|
||||
RESPONSE=$(curl -s -X POST "$PERSONAL_CREATE_URL" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"custIsn": "TEST006",
|
||||
"guarType": "质押",
|
||||
"applyAmt": "100000"
|
||||
}')
|
||||
|
||||
CODE=$(echo "$RESPONSE" | grep -o '"code":[0-9]*' | cut -d':' -f2)
|
||||
if [ "$CODE" == "200" ]; then
|
||||
print_result "最小必填字段测试" "0"
|
||||
else
|
||||
print_result "最小必填字段测试" "1"
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# 测试结果汇总
|
||||
# ============================================================
|
||||
echo ""
|
||||
echo "=========================================="
|
||||
echo "测试结果汇总"
|
||||
echo "=========================================="
|
||||
echo -e "${GREEN}通过: $TESTS_PASSED${NC}"
|
||||
echo -e "${RED}失败: $TESTS_FAILED${NC}"
|
||||
echo "总计: $((TESTS_PASSED + TESTS_FAILED))"
|
||||
|
||||
if [ $TESTS_FAILED -eq 0 ]; then
|
||||
echo -e "\n${GREEN}所有测试通过!${NC}"
|
||||
exit 0
|
||||
else
|
||||
echo -e "\n${RED}存在测试失败,请检查日志${NC}"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user