Compare commits

...

38 Commits

Author SHA1 Message Date
yujialong ea144afa12 fix 2 weeks ago
yujialong 6d8f7a338d 提交后不再查询列表和详情 2 months ago
yujialong 0ca09ffa98 fix 2 months ago
yujialong c0299db074 实验报告loading 3 months ago
yujialong a9db2570fe fix 5 months ago
yujialong 1174a60114 实验报告且或 6 months ago
yujialong 480e5f35fe 所有策略的弹框层级降低为10 6 months ago
yujialong 83530b7bf4 fix 6 months ago
yujialong 092e66ac0b fix 6 months ago
yujialong 44a88fc28a fix 6 months ago
yujialong a5cc5d3874 eslint配置修改并修复 7 months ago
yujialong a16f29184b 配置风控里添加新增策略的入口 7 months ago
yujialong e7b21ece0b vue升级成3.2.34 7 months ago
yujialong 68a17fad68 企业信用评分及企业利率模型默认计算公式 7 months ago
yujialong 9f41401a10 element-plus升级至2.4.3 7 months ago
yujialong 4967b00c9b 模型里内置数据只能查看 7 months ago
yujialong 5723015aa5 fix 7 months ago
yujialong 0aeb30a000 策略同步的提示 7 months ago
yujialong 2ad7e088ae fix 7 months ago
yujialong 795d254f8f 模型保存后查询左侧菜单待处理数量 7 months ago
yujialong 49bf13759d fix 7 months ago
yujialong 058dbd96f6 8个策略添加是跟否单选 7 months ago
yujialong 9a0868d8c9 策略添加判断是否有绑定产品 7 months ago
yujialong 44c5a142ad 动态引入组件优化 7 months ago
yujialong f0a342b470 fix 7 months ago
yujialong 73ee648b97 模型添加loading 7 months ago
yujialong 1369206c2e 贷后管理模型联调 7 months ago
yujialong 53913f3f19 利率定价模型联调 7 months ago
yujialong 957ae65af6 信用评分联调 7 months ago
yujialong 0d12df5652 配置风控策略相关判分 7 months ago
yujialong 39534bf322 准入策略联调完成 7 months ago
yujialong 4d2374a38d 配置风控及策略联调 7 months ago
yujialong 331cf3e493 配置风控及策略联调 7 months ago
yujialong ae5899a977 fix 7 months ago
yujialong ea29e820e3 政务黑名单改成列表 7 months ago
yujialong 9cdbe2dbe7 准入模型左侧导航改成分级菜单 7 months ago
yujialong ec99648a44 测试表头字段名V1.0.3修改 8 months ago
yujialong bd996b5cc3 fix 8 months ago
  1. 4
      .env
  2. 2
      .env.production
  3. 5
      .eslintrc.js
  4. 346
      package-lock.json
  5. 8
      package.json
  6. 462
      public/tinymce/langs/zh_CN.js
  7. 419
      public/tinymce/langs/zh_TW.js
  8. 7
      public/tinymce/skins/content/dark/content.min.css
  9. 7
      public/tinymce/skins/content/default/content.min.css
  10. 7
      public/tinymce/skins/content/document/content.min.css
  11. 7
      public/tinymce/skins/content/writer/content.min.css
  12. 7
      public/tinymce/skins/ui/oxide-dark/content.inline.min.css
  13. 7
      public/tinymce/skins/ui/oxide-dark/content.min.css
  14. 7
      public/tinymce/skins/ui/oxide-dark/content.mobile.min.css
  15. BIN
      public/tinymce/skins/ui/oxide-dark/fonts/tinymce-mobile.woff
  16. 7
      public/tinymce/skins/ui/oxide-dark/skin.min.css
  17. 7
      public/tinymce/skins/ui/oxide-dark/skin.mobile.min.css
  18. 7
      public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css
  19. 7
      public/tinymce/skins/ui/oxide/content.inline.min.css
  20. 7
      public/tinymce/skins/ui/oxide/content.min.css
  21. 7
      public/tinymce/skins/ui/oxide/content.mobile.min.css
  22. BIN
      public/tinymce/skins/ui/oxide/fonts/tinymce-mobile.woff
  23. 7
      public/tinymce/skins/ui/oxide/skin.min.css
  24. 7
      public/tinymce/skins/ui/oxide/skin.mobile.min.css
  25. 7
      public/tinymce/skins/ui/oxide/skin.shadowdom.min.css
  26. 1
      src/api/bank.ts
  27. 164
      src/api/model.ts
  28. 1
      src/api/system.ts
  29. 31
      src/api/user.ts
  30. 1
      src/assets/svgs/preview.svg
  31. 2
      src/components/AliOss/upload.ts
  32. 10
      src/components/Back.vue
  33. 381
      src/components/Panel/index.vue
  34. 9
      src/components/Search.vue
  35. 34
      src/components/StrategyConfirm.vue
  36. 5
      src/components/Tinymce/index.vue
  37. 21
      src/layout/components/AppHeader.vue
  38. 3
      src/layout/components/AppMain.vue
  39. 142
      src/layout/components/AppSidebar/Menu.vue
  40. 31
      src/layout/components/AppSidebar/index.vue
  41. 3
      src/layout/components/Logo.vue
  42. 16
      src/layout/index.vue
  43. 3
      src/permission.ts
  44. 2
      src/router/index.ts
  45. 2
      src/store/useCurrentUser.ts
  46. 24
      src/store/useProduct.ts
  47. 33
      src/styles/index.scss
  48. 1
      src/utils/auth.ts
  49. 11
      src/utils/common.ts
  50. 27
      src/utils/request.ts
  51. 4
      src/views/403.vue
  52. 17
      src/views/404.vue
  53. 89
      src/views/Home.vue
  54. 90
      src/views/Role.vue
  55. 55
      src/views/bankProduct/index.vue
  56. 139
      src/views/config/level/Index.vue
  57. 110
      src/views/config/param/Buyer.vue
  58. 40
      src/views/config/param/Financial.vue
  59. 15
      src/views/config/param/Index.vue
  60. 27
      src/views/finance/Account.vue
  61. 87
      src/views/finance/Bank.vue
  62. 117
      src/views/finance/BankDetail.vue
  63. 96
      src/views/finance/Fund.vue
  64. 80
      src/views/finance/Insurance.vue
  65. 68
      src/views/finance/Order.vue
  66. 92
      src/views/finance/Publish.vue
  67. 173
      src/views/product/afterLoan/1029.vue
  68. 194
      src/views/product/afterLoan/1029/Detail.vue
  69. 157
      src/views/product/afterLoan/1029/Index.vue
  70. 186
      src/views/product/afterLoan/1030.vue
  71. 219
      src/views/product/afterLoan/1030/Detail.vue
  72. 157
      src/views/product/afterLoan/1030/Index.vue
  73. 344
      src/views/product/afterLoan/1031.vue
  74. 336
      src/views/product/afterLoan/1031/Detail.vue
  75. 157
      src/views/product/afterLoan/1031/Index.vue
  76. 130
      src/views/product/afterLoan/1032.vue
  77. 169
      src/views/product/afterLoan/1032/Detail.vue
  78. 157
      src/views/product/afterLoan/1032/Index.vue
  79. 195
      src/views/product/afterLoan/1033.vue
  80. 229
      src/views/product/afterLoan/1033/Detail.vue
  81. 157
      src/views/product/afterLoan/1033/Index.vue
  82. 89
      src/views/product/afterLoan/CardList.vue
  83. 502
      src/views/product/bank/Add.vue
  84. 55
      src/views/product/bank/Approve.vue
  85. 92
      src/views/product/bank/CardList.vue
  86. 1474
      src/views/product/bank/Config.vue
  87. 3
      src/views/product/bank/Detail.vue
  88. 273
      src/views/product/bank/Info.vue
  89. 147
      src/views/product/bank/List.vue
  90. 276
      src/views/product/fund/Add.vue
  91. 64
      src/views/product/fund/CardList.vue
  92. 3
      src/views/product/fund/Detail.vue
  93. 23
      src/views/product/fund/Info.vue
  94. 107
      src/views/product/fund/List.vue
  95. 113
      src/views/product/insurance/Add.vue
  96. 72
      src/views/product/insurance/CardList.vue
  97. 3
      src/views/product/insurance/Detail.vue
  98. 35
      src/views/product/insurance/Info.vue
  99. 118
      src/views/product/insurance/List.vue
  100. 304
      src/views/product/interestRate/772.vue
  101. Some files were not shown because too many files have changed in this diff Show More

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

@ -1 +1 @@
VITE_BASE_API=https://www.occupationlab.com VITE_BASE_API=https://izhixinyun.com

@ -17,6 +17,11 @@ module.exports = {
// '@typescript-eslint/camelcase': 'off', // '@typescript-eslint/camelcase': 'off',
'import/extensions': 'off', 'import/extensions': 'off',
'no-nested-ternary': 'off',
'no-use-before-define': 'off',
'no-unused-expressions': 'off',
'no-empty': 'off',
'no-console': 'off'
}, },
settings: { settings: {
'import/resolver': { 'import/resolver': {

346
package-lock.json generated

@ -52,9 +52,9 @@
} }
}, },
"@ctrl/tinycolor": { "@ctrl/tinycolor": {
"version": "3.4.0", "version": "3.6.1",
"resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-3.4.0.tgz", "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
"integrity": "sha512-JZButFdZ1+/xAfpguQHoabIXkcqRRKpMrWKBkpEZZyxfY9C1DpADFB8PEqGSTeFr135SaTRfKqGKx5xSCLI7ZQ==" "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA=="
}, },
"@element-plus/icons-vue": { "@element-plus/icons-vue": {
"version": "0.2.7", "version": "0.2.7",
@ -85,6 +85,28 @@
"integrity": "sha512-8HqW8EVqjnCmWXVpqAOZf+EGESdkR27odcMMMGefgKXtar00SoYNSryGv//TELI4T3QFsECo78p+0lmalk/CFA==", "integrity": "sha512-8HqW8EVqjnCmWXVpqAOZf+EGESdkR27odcMMMGefgKXtar00SoYNSryGv//TELI4T3QFsECo78p+0lmalk/CFA==",
"dev": true "dev": true
}, },
"@floating-ui/core": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.1.tgz",
"integrity": "sha512-42UH54oPZHPdRHdw6BgoBD6cg/eVTmVrFcgeRDM3jbO7uxSoipVcmcIGFcA5jmOHO5apcyvBhkSKES3fQJnu7A==",
"requires": {
"@floating-ui/utils": "^0.2.0"
}
},
"@floating-ui/dom": {
"version": "1.6.5",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.5.tgz",
"integrity": "sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==",
"requires": {
"@floating-ui/core": "^1.0.0",
"@floating-ui/utils": "^0.2.0"
}
},
"@floating-ui/utils": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.2.tgz",
"integrity": "sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw=="
},
"@intlify/bundle-utils": { "@intlify/bundle-utils": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmmirror.com/@intlify/bundle-utils/-/bundle-utils-2.2.0.tgz", "resolved": "https://registry.npmmirror.com/@intlify/bundle-utils/-/bundle-utils-2.2.0.tgz",
@ -207,9 +229,9 @@
} }
}, },
"@popperjs/core": { "@popperjs/core": {
"version": "2.11.2", "version": "npm:@sxzz/popperjs-es@2.11.7",
"resolved": "https://registry.npmmirror.com/@popperjs/core/-/core-2.11.2.tgz", "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
"integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==" "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ=="
}, },
"@rollup/pluginutils": { "@rollup/pluginutils": {
"version": "4.1.2", "version": "4.1.2",
@ -285,8 +307,15 @@
"@types/lodash": { "@types/lodash": {
"version": "4.14.178", "version": "4.14.178",
"resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.178.tgz", "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.178.tgz",
"integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw==", "integrity": "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw=="
"dev": true },
"@types/lodash-es": {
"version": "4.17.12",
"resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
"integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
"requires": {
"@types/lodash": "*"
}
}, },
"@types/node": { "@types/node": {
"version": "17.0.17", "version": "17.0.17",
@ -315,6 +344,11 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/web-bluetooth": {
"version": "0.0.16",
"resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
},
"@typescript-eslint/eslint-plugin": { "@typescript-eslint/eslint-plugin": {
"version": "4.33.0", "version": "4.33.0",
"resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz", "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz",
@ -582,16 +616,16 @@
} }
}, },
"@vue/compiler-sfc": { "@vue/compiler-sfc": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.34.tgz",
"integrity": "sha512-PminuOYIcFI7UZn+mdy2OPbogyAb0IHkVuqwmLDJiSRFhc/QAXQnO9KdS4nez3bQ9XlQmoAveQzcZuekHzdb5w==", "integrity": "sha512-I+vT4soKJtdsoREBDYAcz56+yGpZ5T3GUigvBFgC2yTeTtBtREOPzYw8kZyMuD2ZlryPYBkbV8D9xxcvU0j/aw==",
"requires": { "requires": {
"@babel/parser": "^7.16.4", "@babel/parser": "^7.16.4",
"@vue/compiler-core": "3.2.25", "@vue/compiler-core": "3.2.34",
"@vue/compiler-dom": "3.2.25", "@vue/compiler-dom": "3.2.34",
"@vue/compiler-ssr": "3.2.25", "@vue/compiler-ssr": "3.2.34",
"@vue/reactivity-transform": "3.2.25", "@vue/reactivity-transform": "3.2.34",
"@vue/shared": "3.2.25", "@vue/shared": "3.2.34",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"magic-string": "^0.25.7", "magic-string": "^0.25.7",
"postcss": "^8.1.10", "postcss": "^8.1.10",
@ -599,65 +633,65 @@
}, },
"dependencies": { "dependencies": {
"@vue/compiler-core": { "@vue/compiler-core": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.34.tgz",
"integrity": "sha512-FlffKezIqztTCTyG0klkYRwhdyL6b1PTTCIerPb4p2R9qQaczccTX5g9ysi9w6tpLQ48a1WiXnFDJhWD7XoqwA==", "integrity": "sha512-Y53lv04ZhDfqflhk4yEgBZrCL1RipbxqmqJFfl1PRkjOzt0bvJpf1sCNN81QNfXohVwFGf+Hng2ztwLwOZgbuA==",
"requires": { "requires": {
"@babel/parser": "^7.16.4", "@babel/parser": "^7.16.4",
"@vue/shared": "3.2.25", "@vue/shared": "3.2.34",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"source-map": "^0.6.1" "source-map": "^0.6.1"
} }
}, },
"@vue/compiler-dom": { "@vue/compiler-dom": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.34.tgz",
"integrity": "sha512-4JrburkRg4VWbc8AKpzKFWbNY4MDXshqjFl53+vINq7zaw3Z7aSqnLv0EkKh8B8ynf/MYsAdygGutyVbEWYxOw==", "integrity": "sha512-MFLUYDgy0aES9x1goU/pgxpzgT9IZOndO8qwQVSyVfUvl/CywEBtfBi5+8fsiBDhoGIT7g8qcsUUF1NYViU2vQ==",
"requires": { "requires": {
"@vue/compiler-core": "3.2.25", "@vue/compiler-core": "3.2.34",
"@vue/shared": "3.2.25" "@vue/shared": "3.2.34"
} }
}, },
"@vue/shared": { "@vue/shared": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.34.tgz",
"integrity": "sha512-DkHJFV2gw9WBRmUCa21eyG0WvlF0l1QFOgTkWj29O4mt2Tv3BSE5PQOKhUruZIym4bBYCqx9ZGtoD1WohDprow==" "integrity": "sha512-zhEeB8TrFmTXmTXmu/wcjEhgrjO4xqdDQrCdPhjX7NxfoLqoBVKguOm8qyihWNLbP+41svYY4za9mqXyqFLzNg=="
} }
} }
}, },
"@vue/compiler-ssr": { "@vue/compiler-ssr": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.34.tgz",
"integrity": "sha512-+BAl8U5D3JkGR6086PFx1BQQ5km3z9fT88hy/7lzf8i3vEDdPQodadnX2t6tndFjIux05MEKg43DeocOojT0mw==", "integrity": "sha512-zyaMdGJhxoA34ibWsXF7VH1PO5yrNB1MZg/ByRfXGM8JefGQaz+PpHvBy/5OI0ehEyhAyCb7279JdhYHacMZbw==",
"requires": { "requires": {
"@vue/compiler-dom": "3.2.25", "@vue/compiler-dom": "3.2.34",
"@vue/shared": "3.2.25" "@vue/shared": "3.2.34"
}, },
"dependencies": { "dependencies": {
"@vue/compiler-core": { "@vue/compiler-core": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.34.tgz",
"integrity": "sha512-FlffKezIqztTCTyG0klkYRwhdyL6b1PTTCIerPb4p2R9qQaczccTX5g9ysi9w6tpLQ48a1WiXnFDJhWD7XoqwA==", "integrity": "sha512-Y53lv04ZhDfqflhk4yEgBZrCL1RipbxqmqJFfl1PRkjOzt0bvJpf1sCNN81QNfXohVwFGf+Hng2ztwLwOZgbuA==",
"requires": { "requires": {
"@babel/parser": "^7.16.4", "@babel/parser": "^7.16.4",
"@vue/shared": "3.2.25", "@vue/shared": "3.2.34",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"source-map": "^0.6.1" "source-map": "^0.6.1"
} }
}, },
"@vue/compiler-dom": { "@vue/compiler-dom": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.34.tgz",
"integrity": "sha512-4JrburkRg4VWbc8AKpzKFWbNY4MDXshqjFl53+vINq7zaw3Z7aSqnLv0EkKh8B8ynf/MYsAdygGutyVbEWYxOw==", "integrity": "sha512-MFLUYDgy0aES9x1goU/pgxpzgT9IZOndO8qwQVSyVfUvl/CywEBtfBi5+8fsiBDhoGIT7g8qcsUUF1NYViU2vQ==",
"requires": { "requires": {
"@vue/compiler-core": "3.2.25", "@vue/compiler-core": "3.2.34",
"@vue/shared": "3.2.25" "@vue/shared": "3.2.34"
} }
}, },
"@vue/shared": { "@vue/shared": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.34.tgz",
"integrity": "sha512-DkHJFV2gw9WBRmUCa21eyG0WvlF0l1QFOgTkWj29O4mt2Tv3BSE5PQOKhUruZIym4bBYCqx9ZGtoD1WohDprow==" "integrity": "sha512-zhEeB8TrFmTXmTXmu/wcjEhgrjO4xqdDQrCdPhjX7NxfoLqoBVKguOm8qyihWNLbP+41svYY4za9mqXyqFLzNg=="
} }
} }
}, },
@ -694,89 +728,89 @@
} }
}, },
"@vue/reactivity-transform": { "@vue/reactivity-transform": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.34.tgz",
"integrity": "sha512-fOiW67PUalicMfMr4Sc9l8mUtkN7ZD+G1/zJV8blzQ8GEZSeRcJm11gqve6Ps623ju5YORu7V/Q1gZoOJ9WO4g==", "integrity": "sha512-OtsrL4/i6Md279pMhZ8wRijeDhPSdnXrH9wmqAcKDhVcp1L2kSWlgVVLa1jGIyyFYE806YiJNJiGBvXPGXMzxw==",
"requires": { "requires": {
"@babel/parser": "^7.16.4", "@babel/parser": "^7.16.4",
"@vue/compiler-core": "3.2.25", "@vue/compiler-core": "3.2.34",
"@vue/shared": "3.2.25", "@vue/shared": "3.2.34",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"magic-string": "^0.25.7" "magic-string": "^0.25.7"
}, },
"dependencies": { "dependencies": {
"@vue/compiler-core": { "@vue/compiler-core": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.34.tgz",
"integrity": "sha512-FlffKezIqztTCTyG0klkYRwhdyL6b1PTTCIerPb4p2R9qQaczccTX5g9ysi9w6tpLQ48a1WiXnFDJhWD7XoqwA==", "integrity": "sha512-Y53lv04ZhDfqflhk4yEgBZrCL1RipbxqmqJFfl1PRkjOzt0bvJpf1sCNN81QNfXohVwFGf+Hng2ztwLwOZgbuA==",
"requires": { "requires": {
"@babel/parser": "^7.16.4", "@babel/parser": "^7.16.4",
"@vue/shared": "3.2.25", "@vue/shared": "3.2.34",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"source-map": "^0.6.1" "source-map": "^0.6.1"
} }
}, },
"@vue/shared": { "@vue/shared": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.34.tgz",
"integrity": "sha512-DkHJFV2gw9WBRmUCa21eyG0WvlF0l1QFOgTkWj29O4mt2Tv3BSE5PQOKhUruZIym4bBYCqx9ZGtoD1WohDprow==" "integrity": "sha512-zhEeB8TrFmTXmTXmu/wcjEhgrjO4xqdDQrCdPhjX7NxfoLqoBVKguOm8qyihWNLbP+41svYY4za9mqXyqFLzNg=="
} }
} }
}, },
"@vue/runtime-core": { "@vue/runtime-core": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.34.tgz",
"integrity": "sha512-2+fo5+lofT4xr8W2rtjyz+AM+UB1U/UNLH6ISFdHWNWuveSWxF+vkCQaATmhp6O3XA7QJAbHoRqIZor20EWSfQ==", "integrity": "sha512-GtaHqYiuEb56OA0cbMh20UPpDiXGRX+NS1buKif4OL341JJ3NtmNOIchCzknaN76oN6KqrLiO82/+TEZXl2Xtw==",
"requires": { "requires": {
"@vue/reactivity": "3.2.25", "@vue/reactivity": "3.2.34",
"@vue/shared": "3.2.25" "@vue/shared": "3.2.34"
}, },
"dependencies": { "dependencies": {
"@vue/reactivity": { "@vue/reactivity": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.34.tgz",
"integrity": "sha512-Dxc/u/dxoneIDqyfmuwPVBR0G3OQJqe3Dtz4z3NGt+CGj4UuOZQfN5raJPmp6xGYgrtC6PAWoCgHhyrgr1qCtg==", "integrity": "sha512-xbRIOPqxdNOr0zS47moRS6zf4BKd0z+55R85UJlo4r5ezqCktk6fYy1atY4tGzo7Maqh6QoKw3LtIKvpz8d7WA==",
"requires": { "requires": {
"@vue/shared": "3.2.25" "@vue/shared": "3.2.34"
} }
}, },
"@vue/shared": { "@vue/shared": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.34.tgz",
"integrity": "sha512-DkHJFV2gw9WBRmUCa21eyG0WvlF0l1QFOgTkWj29O4mt2Tv3BSE5PQOKhUruZIym4bBYCqx9ZGtoD1WohDprow==" "integrity": "sha512-zhEeB8TrFmTXmTXmu/wcjEhgrjO4xqdDQrCdPhjX7NxfoLqoBVKguOm8qyihWNLbP+41svYY4za9mqXyqFLzNg=="
} }
} }
}, },
"@vue/runtime-dom": { "@vue/runtime-dom": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.34.tgz",
"integrity": "sha512-3gGeyHnygn4yG6bssRKhQIxnE8vgB8FtYUUwoYoA/Pm0vZ+bGPoZax4TbtZD9eW9rvs8CY8boNp4t/sJaPJrRQ==", "integrity": "sha512-uqizbaJqmNH3O4TRr+8cM1tid5ODWHyQYZ3CLWcjn3dLkf0N7wvNuhUELQUZU/wQLvVMhJUQNrmOqckHLm6Xpw==",
"requires": { "requires": {
"@vue/runtime-core": "3.2.25", "@vue/runtime-core": "3.2.34",
"@vue/shared": "3.2.25", "@vue/shared": "3.2.34",
"csstype": "^2.6.8" "csstype": "^2.6.8"
}, },
"dependencies": { "dependencies": {
"@vue/shared": { "@vue/shared": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.34.tgz",
"integrity": "sha512-DkHJFV2gw9WBRmUCa21eyG0WvlF0l1QFOgTkWj29O4mt2Tv3BSE5PQOKhUruZIym4bBYCqx9ZGtoD1WohDprow==" "integrity": "sha512-zhEeB8TrFmTXmTXmu/wcjEhgrjO4xqdDQrCdPhjX7NxfoLqoBVKguOm8qyihWNLbP+41svYY4za9mqXyqFLzNg=="
} }
} }
}, },
"@vue/server-renderer": { "@vue/server-renderer": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.34.tgz",
"integrity": "sha512-qFRmcyeyyhWbnTPn6cbCZ4bjeuPLSkUpFa98p4LEJtFBFbxjGnrHXHOjYxCY3Lznmxe0kMM3qG4t3GnjcXP12w==", "integrity": "sha512-PMnBAq1BexPFXBxuLngp4lQvc0XQD1CBDIHtEsG0pRusGWVJddBUKlR/EnnSvGaJ34YmKkAl9kdvczOz0kddew==",
"requires": { "requires": {
"@vue/compiler-ssr": "3.2.25", "@vue/compiler-ssr": "3.2.34",
"@vue/shared": "3.2.25" "@vue/shared": "3.2.34"
}, },
"dependencies": { "dependencies": {
"@vue/shared": { "@vue/shared": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.34.tgz",
"integrity": "sha512-DkHJFV2gw9WBRmUCa21eyG0WvlF0l1QFOgTkWj29O4mt2Tv3BSE5PQOKhUruZIym4bBYCqx9ZGtoD1WohDprow==" "integrity": "sha512-zhEeB8TrFmTXmTXmu/wcjEhgrjO4xqdDQrCdPhjX7NxfoLqoBVKguOm8qyihWNLbP+41svYY4za9mqXyqFLzNg=="
} }
} }
}, },
@ -796,18 +830,25 @@
} }
}, },
"@vueuse/core": { "@vueuse/core": {
"version": "7.6.1", "version": "9.13.0",
"resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-7.6.1.tgz", "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz",
"integrity": "sha512-492y7R9HRu6TXzcGBMVG5qg5o9CHjrWLfOHh+TEknJeLe3LIYHsIBi1IlUN5s/yP3OHlBynjrzMMUm4gEyBmQg==", "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
"requires": { "requires": {
"@vueuse/shared": "7.6.1", "@types/web-bluetooth": "^0.0.16",
"@vueuse/metadata": "9.13.0",
"@vueuse/shared": "9.13.0",
"vue-demi": "*" "vue-demi": "*"
} }
}, },
"@vueuse/metadata": {
"version": "9.13.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz",
"integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ=="
},
"@vueuse/shared": { "@vueuse/shared": {
"version": "7.6.1", "version": "9.13.0",
"resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-7.6.1.tgz", "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz",
"integrity": "sha512-VhURBjuyELYLW94TLqwyM+tUZ0uyWAOjp8zDnJts5wwyHZlGt/yabLbuEl70cKmt0zR9psVyAyHC+LTgRrA1Zw==", "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
"requires": { "requires": {
"vue-demi": "*" "vue-demi": "*"
} }
@ -1039,9 +1080,9 @@
"dev": true "dev": true
}, },
"async-validator": { "async-validator": {
"version": "4.0.7", "version": "4.2.5",
"resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.0.7.tgz", "resolved": "https://registry.npmjs.org/async-validator/-/async-validator-4.2.5.tgz",
"integrity": "sha512-Pj2IR7u8hmUEDOwB++su6baaRi+QvsgajuFB9j95foM1N2gy5HM4z60hfusIO0fBPG5uLAEl6yCJr1jNSVugEQ==" "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
}, },
"autoprefixer": { "autoprefixer": {
"version": "10.4.2", "version": "10.4.2",
@ -1195,9 +1236,9 @@
"dev": true "dev": true
}, },
"caniuse-lite": { "caniuse-lite": {
"version": "1.0.30001311", "version": "1.0.30001620",
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001311.tgz", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz",
"integrity": "sha512-mleTFtFKfykEeW34EyfhGIFjGCqzhh38Y0LhdQ9aWF+HorZTtdgKV/1hEE0NlFkG2ubvisPV6l400tlbPys98A==", "integrity": "sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==",
"dev": true "dev": true
}, },
"capital-case": { "capital-case": {
@ -1720,21 +1761,42 @@
"dev": true "dev": true
}, },
"element-plus": { "element-plus": {
"version": "2.0.2", "version": "2.4.3",
"resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.0.2.tgz", "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.4.3.tgz",
"integrity": "sha512-URjC0HwwiqtlLxqTmHXQ31WXrdAq4ChWyyn52OcQs3PRsnMPfahGVq2AWnfzzlzlhVeI5lY3HQiuB1zDathS+g==", "integrity": "sha512-b3q26j+lM4SBqiyzw8HybybGnP2pk4MWgrnzzzYW5qKQUgV6EG1Zg7nMCfgCVccI8tNvZoTiUHb2mFaiB9qT8w==",
"requires": { "requires": {
"@ctrl/tinycolor": "^3.4.0", "@ctrl/tinycolor": "^3.4.1",
"@element-plus/icons-vue": "^0.2.6", "@element-plus/icons-vue": "^2.3.1",
"@popperjs/core": "^2.11.2", "@floating-ui/dom": "^1.0.1",
"@vueuse/core": "^7.6.0", "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
"async-validator": "^4.0.7", "@types/lodash": "^4.14.182",
"dayjs": "^1.10.7", "@types/lodash-es": "^4.17.6",
"@vueuse/core": "^9.1.0",
"async-validator": "^4.2.5",
"dayjs": "^1.11.3",
"escape-html": "^1.0.3",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"lodash-unified": "^1.0.1", "lodash-unified": "^1.0.2",
"memoize-one": "^6.0.0", "memoize-one": "^6.0.0",
"normalize-wheel-es": "^1.1.1" "normalize-wheel-es": "^1.2.0"
},
"dependencies": {
"@element-plus/icons-vue": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz",
"integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg=="
},
"@types/lodash": {
"version": "4.17.1",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.1.tgz",
"integrity": "sha512-X+2qazGS3jxLAIz5JDXDzglAF3KpijdhFxlf/V1+hEsOUc+HnWi81L/uv/EvGuV90WY+7mPGFCUDGfQC3Gj95Q=="
},
"dayjs": {
"version": "1.11.11",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz",
"integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg=="
}
} }
}, },
"emmet": { "emmet": {
@ -3369,13 +3431,13 @@
}, },
"lodash-es": { "lodash-es": {
"version": "4.17.21", "version": "4.17.21",
"resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
}, },
"lodash-unified": { "lodash-unified": {
"version": "1.0.1", "version": "1.0.3",
"resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.1.tgz", "resolved": "https://registry.npmjs.org/lodash-unified/-/lodash-unified-1.0.3.tgz",
"integrity": "sha512-Py+twfpWn+2dFQWCuGcp21WiQRwZwnm1cyE3piSt/VtBVKVyxlR58WgOVRzXtmdmDRGJKH8F8GPaA29WK/yK8g==" "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ=="
}, },
"lodash.clonedeep": { "lodash.clonedeep": {
"version": "4.5.0", "version": "4.5.0",
@ -3513,7 +3575,7 @@
}, },
"memoize-one": { "memoize-one": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz",
"integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw=="
}, },
"merge-descriptors": { "merge-descriptors": {
@ -3818,9 +3880,9 @@
"dev": true "dev": true
}, },
"normalize-wheel-es": { "normalize-wheel-es": {
"version": "1.1.1", "version": "1.2.0",
"resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.1.1.tgz", "resolved": "https://registry.npmjs.org/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz",
"integrity": "sha512-157VNH4CngrcsvF8xOVOe22cwniIR3nxSltdctvQeHZj8JttEeOXffK28jucWfWBXs0QNetAumjc1GiInnwX4w==" "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw=="
}, },
"nprogress": { "nprogress": {
"version": "0.2.0", "version": "0.2.0",
@ -5738,48 +5800,48 @@
} }
}, },
"vue": { "vue": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.2.25.tgz", "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.34.tgz",
"integrity": "sha512-jU3t7fyQDHoCWCqhmRrnSmYZvHC35tOJTP704di7HGfq5EcFA1cU/1ZPjUV1eCxJev65Khjyfni+vk9oa+eTtw==", "integrity": "sha512-gXRg5v8OSmGT4ZiQ/X/Pcz6Fr2igHQx/wvRH/pLnt0VvjfGGqrwhnwjYZilLP4HBcO211rMD9PpU6lfWfIv3wg==",
"requires": { "requires": {
"@vue/compiler-dom": "3.2.25", "@vue/compiler-dom": "3.2.34",
"@vue/compiler-sfc": "3.2.25", "@vue/compiler-sfc": "3.2.34",
"@vue/runtime-dom": "3.2.25", "@vue/runtime-dom": "3.2.34",
"@vue/server-renderer": "3.2.25", "@vue/server-renderer": "3.2.34",
"@vue/shared": "3.2.25" "@vue/shared": "3.2.34"
}, },
"dependencies": { "dependencies": {
"@vue/compiler-core": { "@vue/compiler-core": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.34.tgz",
"integrity": "sha512-FlffKezIqztTCTyG0klkYRwhdyL6b1PTTCIerPb4p2R9qQaczccTX5g9ysi9w6tpLQ48a1WiXnFDJhWD7XoqwA==", "integrity": "sha512-Y53lv04ZhDfqflhk4yEgBZrCL1RipbxqmqJFfl1PRkjOzt0bvJpf1sCNN81QNfXohVwFGf+Hng2ztwLwOZgbuA==",
"requires": { "requires": {
"@babel/parser": "^7.16.4", "@babel/parser": "^7.16.4",
"@vue/shared": "3.2.25", "@vue/shared": "3.2.34",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"source-map": "^0.6.1" "source-map": "^0.6.1"
} }
}, },
"@vue/compiler-dom": { "@vue/compiler-dom": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.34.tgz",
"integrity": "sha512-4JrburkRg4VWbc8AKpzKFWbNY4MDXshqjFl53+vINq7zaw3Z7aSqnLv0EkKh8B8ynf/MYsAdygGutyVbEWYxOw==", "integrity": "sha512-MFLUYDgy0aES9x1goU/pgxpzgT9IZOndO8qwQVSyVfUvl/CywEBtfBi5+8fsiBDhoGIT7g8qcsUUF1NYViU2vQ==",
"requires": { "requires": {
"@vue/compiler-core": "3.2.25", "@vue/compiler-core": "3.2.34",
"@vue/shared": "3.2.25" "@vue/shared": "3.2.34"
} }
}, },
"@vue/shared": { "@vue/shared": {
"version": "3.2.25", "version": "3.2.34",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.25.tgz", "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.34.tgz",
"integrity": "sha512-DkHJFV2gw9WBRmUCa21eyG0WvlF0l1QFOgTkWj29O4mt2Tv3BSE5PQOKhUruZIym4bBYCqx9ZGtoD1WohDprow==" "integrity": "sha512-zhEeB8TrFmTXmTXmu/wcjEhgrjO4xqdDQrCdPhjX7NxfoLqoBVKguOm8qyihWNLbP+41svYY4za9mqXyqFLzNg=="
} }
} }
}, },
"vue-demi": { "vue-demi": {
"version": "0.12.1", "version": "0.14.7",
"resolved": "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.12.1.tgz", "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.7.tgz",
"integrity": "sha512-QL3ny+wX8c6Xm1/EZylbgzdoDolye+VpCXRhI2hug9dJTP3OUJ3lmiKN3CsVV3mOJKwFi0nsstbgob0vG7aoIw==" "integrity": "sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA=="
}, },
"vue-eslint-parser": { "vue-eslint-parser": {
"version": "7.11.0", "version": "7.11.0",

@ -6,8 +6,8 @@
"dev": "vite", "dev": "vite",
"test": "vite build --mode test", "test": "vite build --mode test",
"build": "vite build", "build": "vite build",
"preview": "vite preview", "lint": "eslint --ext .vue,.ts src/",
"plop": "plop" "lint:fix": "eslint --ext .vue,.ts src/ --fix"
}, },
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "^0.2.7", "@element-plus/icons-vue": "^0.2.7",
@ -17,14 +17,14 @@
"core-js": "^3.21.0", "core-js": "^3.21.0",
"cropperjs": "^1.5.12", "cropperjs": "^1.5.12",
"dayjs": "^1.10.7", "dayjs": "^1.10.7",
"element-plus": "^2.0.2", "element-plus": "^2.4.3",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mavon-editor": "^2.10.4", "mavon-editor": "^2.10.4",
"nprogress": "^0.2.0", "nprogress": "^0.2.0",
"path-to-regexp": "^6.2.0", "path-to-regexp": "^6.2.0",
"tinymce": "^5.9.2", "tinymce": "^5.9.2",
"vue": "^3.2.25", "vue": "^3.2.34",
"vue-i18n": "^9.2.0-beta.30", "vue-i18n": "^9.2.0-beta.30",
"vue-router": "^4.0.12", "vue-router": "^4.0.12",
"vuedraggable": "^4.1.0" "vuedraggable": "^4.1.0"

@ -1,462 +0,0 @@
tinymce.addI18n('zh_CN',{
"Redo": "\u91cd\u505a",
"Undo": "\u64a4\u9500",
"Cut": "\u526a\u5207",
"Copy": "\u590d\u5236",
"Paste": "\u7c98\u8d34",
"Select all": "\u5168\u9009",
"New document": "\u65b0\u6587\u4ef6",
"Ok": "\u786e\u5b9a",
"Cancel": "\u53d6\u6d88",
"Visual aids": "\u7f51\u683c\u7ebf",
"Bold": "\u7c97\u4f53",
"Italic": "\u659c\u4f53",
"Underline": "\u4e0b\u5212\u7ebf",
"Strikethrough": "\u5220\u9664\u7ebf",
"Superscript": "\u4e0a\u6807",
"Subscript": "\u4e0b\u6807",
"Clear formatting": "\u6e05\u9664\u683c\u5f0f",
"Align left": "\u5de6\u8fb9\u5bf9\u9f50",
"Align center": "\u4e2d\u95f4\u5bf9\u9f50",
"Align right": "\u53f3\u8fb9\u5bf9\u9f50",
"Justify": "\u4e24\u7aef\u5bf9\u9f50",
"Bullet list": "\u9879\u76ee\u7b26\u53f7",
"Numbered list": "\u7f16\u53f7\u5217\u8868",
"Decrease indent": "\u51cf\u5c11\u7f29\u8fdb",
"Increase indent": "\u589e\u52a0\u7f29\u8fdb",
"Close": "\u5173\u95ed",
"Formats": "\u683c\u5f0f",
"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u6253\u5f00\u526a\u8d34\u677f\uff0c\u8bf7\u4f7f\u7528Ctrl+X\/C\/V\u7b49\u5feb\u6377\u952e\u3002",
"Headers": "\u6807\u9898",
"Header 1": "\u6807\u98981",
"Header 2": "\u6807\u98982",
"Header 3": "\u6807\u98983",
"Header 4": "\u6807\u98984",
"Header 5": "\u6807\u98985",
"Header 6": "\u6807\u98986",
"Headings": "\u6807\u9898",
"Heading 1": "\u6807\u98981",
"Heading 2": "\u6807\u98982",
"Heading 3": "\u6807\u98983",
"Heading 4": "\u6807\u98984",
"Heading 5": "\u6807\u98985",
"Heading 6": "\u6807\u98986",
"Preformatted": "\u9884\u5148\u683c\u5f0f\u5316\u7684",
"Div": "Div",
"Pre": "Pre",
"Code": "\u4ee3\u7801",
"Paragraph": "\u6bb5\u843d",
"Blockquote": "\u5f15\u6587\u533a\u5757",
"Inline": "\u6587\u672c",
"Blocks": "\u57fa\u5757",
"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002",
"Fonts": "\u5b57\u4f53",
"Font Sizes": "\u5b57\u53f7",
"Class": "\u7c7b\u578b",
"Browse for an image": "\u6d4f\u89c8\u56fe\u50cf",
"OR": "\u6216",
"Drop an image here": "\u62d6\u653e\u4e00\u5f20\u56fe\u50cf\u81f3\u6b64",
"Upload": "\u4e0a\u4f20",
"Block": "\u5757",
"Align": "\u5bf9\u9f50",
"Default": "\u9ed8\u8ba4",
"Circle": "\u7a7a\u5fc3\u5706",
"Disc": "\u5b9e\u5fc3\u5706",
"Square": "\u65b9\u5757",
"Lower Alpha": "\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd",
"Lower Greek": "\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd",
"Lower Roman": "\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd",
"Upper Alpha": "\u5927\u5199\u82f1\u6587\u5b57\u6bcd",
"Upper Roman": "\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd",
"Anchor...": "\u951a\u70b9...",
"Name": "\u540d\u79f0",
"Id": "\u6807\u8bc6\u7b26",
"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "\u6807\u8bc6\u7b26\u5e94\u8be5\u4ee5\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u8ddf\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002",
"You have unsaved changes are you sure you want to navigate away?": "\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f",
"Restore last draft": "\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f",
"Special character...": "\u7279\u6b8a\u5b57\u7b26...",
"Source code": "\u6e90\u4ee3\u7801",
"Insert\/Edit code sample": "\u63d2\u5165\/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b",
"Language": "\u8bed\u8a00",
"Code sample...": "\u793a\u4f8b\u4ee3\u7801...",
"Color Picker": "\u9009\u8272\u5668",
"R": "R",
"G": "G",
"B": "B",
"Left to right": "\u4ece\u5de6\u5230\u53f3",
"Right to left": "\u4ece\u53f3\u5230\u5de6",
"Emoticons": "\u8868\u60c5",
"Emoticons...": "\u8868\u60c5\u7b26\u53f7...",
"Metadata and Document Properties": "\u5143\u6570\u636e\u548c\u6587\u6863\u5c5e\u6027",
"Title": "\u6807\u9898",
"Keywords": "\u5173\u952e\u8bcd",
"Description": "\u63cf\u8ff0",
"Robots": "\u673a\u5668\u4eba",
"Author": "\u4f5c\u8005",
"Encoding": "\u7f16\u7801",
"Fullscreen": "\u5168\u5c4f",
"Action": "\u64cd\u4f5c",
"Shortcut": "\u5feb\u6377\u952e",
"Help": "\u5e2e\u52a9",
"Address": "\u5730\u5740",
"Focus to menubar": "\u79fb\u52a8\u7126\u70b9\u5230\u83dc\u5355\u680f",
"Focus to toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u5de5\u5177\u680f",
"Focus to element path": "\u79fb\u52a8\u7126\u70b9\u5230\u5143\u7d20\u8def\u5f84",
"Focus to contextual toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u4e0a\u4e0b\u6587\u83dc\u5355",
"Insert link (if link plugin activated)": "\u63d2\u5165\u94fe\u63a5 (\u5982\u679c\u94fe\u63a5\u63d2\u4ef6\u5df2\u6fc0\u6d3b)",
"Save (if save plugin activated)": "\u4fdd\u5b58(\u5982\u679c\u4fdd\u5b58\u63d2\u4ef6\u5df2\u6fc0\u6d3b)",
"Find (if searchreplace plugin activated)": "\u67e5\u627e(\u5982\u679c\u67e5\u627e\u66ff\u6362\u63d2\u4ef6\u5df2\u6fc0\u6d3b)",
"Plugins installed ({0}):": "\u5df2\u5b89\u88c5\u63d2\u4ef6 ({0}):",
"Premium plugins:": "\u4f18\u79c0\u63d2\u4ef6\uff1a",
"Learn more...": "\u4e86\u89e3\u66f4\u591a...",
"You are using {0}": "\u4f60\u6b63\u5728\u4f7f\u7528 {0}",
"Plugins": "\u63d2\u4ef6",
"Handy Shortcuts": "\u5feb\u6377\u952e",
"Horizontal line": "\u6c34\u5e73\u5206\u5272\u7ebf",
"Insert\/edit image": "\u63d2\u5165\/\u7f16\u8f91\u56fe\u7247",
"Alternative description": "\u66ff\u4ee3\u63cf\u8ff0",
"Accessibility": "\u8f85\u52a9\u529f\u80fd",
"Image is decorative": "\u56fe\u50cf\u662f\u88c5\u9970\u6027\u7684",
"Source": "\u5730\u5740",
"Dimensions": "\u5927\u5c0f",
"Constrain proportions": "\u4fdd\u6301\u7eb5\u6a2a\u6bd4",
"General": "\u666e\u901a",
"Advanced": "\u9ad8\u7ea7",
"Style": "\u6837\u5f0f",
"Vertical space": "\u5782\u76f4\u8fb9\u8ddd",
"Horizontal space": "\u6c34\u5e73\u8fb9\u8ddd",
"Border": "\u8fb9\u6846",
"Insert image": "\u63d2\u5165\u56fe\u7247",
"Image...": "\u56fe\u7247...",
"Image list": "\u56fe\u7247\u5217\u8868",
"Rotate counterclockwise": "\u9006\u65f6\u9488\u65cb\u8f6c",
"Rotate clockwise": "\u987a\u65f6\u9488\u65cb\u8f6c",
"Flip vertically": "\u5782\u76f4\u7ffb\u8f6c",
"Flip horizontally": "\u6c34\u5e73\u7ffb\u8f6c",
"Edit image": "\u7f16\u8f91\u56fe\u7247",
"Image options": "\u56fe\u7247\u9009\u9879",
"Zoom in": "\u653e\u5927",
"Zoom out": "\u7f29\u5c0f",
"Crop": "\u88c1\u526a",
"Resize": "\u8c03\u6574\u5927\u5c0f",
"Orientation": "\u65b9\u5411",
"Brightness": "\u4eae\u5ea6",
"Sharpen": "\u9510\u5316",
"Contrast": "\u5bf9\u6bd4\u5ea6",
"Color levels": "\u989c\u8272\u5c42\u6b21",
"Gamma": "\u4f3d\u9a6c\u503c",
"Invert": "\u53cd\u8f6c",
"Apply": "\u5e94\u7528",
"Back": "\u540e\u9000",
"Insert date\/time": "\u63d2\u5165\u65e5\u671f\/\u65f6\u95f4",
"Date\/time": "\u65e5\u671f\/\u65f6\u95f4",
"Insert\/edit link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5",
"Text to display": "\u663e\u793a\u6587\u5b57",
"Url": "\u5730\u5740",
"Open link in...": "\u94fe\u63a5\u6253\u5f00\u4f4d\u7f6e...",
"Current window": "\u5f53\u524d\u7a97\u53e3",
"None": "\u65e0",
"New window": "\u5728\u65b0\u7a97\u53e3\u6253\u5f00",
"Open link": "\u6253\u5f00\u94fe\u63a5",
"Remove link": "\u5220\u9664\u94fe\u63a5",
"Anchors": "\u951a\u70b9",
"Link...": "\u94fe\u63a5...",
"Paste or type a link": "\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7f00\u5417\uff1f",
"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:\/\/:\u524d\u7f00\u5417\uff1f",
"The URL you entered seems to be an external link. Do you want to add the required https:\/\/ prefix?": "\u60a8\u8f93\u5165\u7684 URL \u4f3c\u4e4e\u662f\u4e00\u4e2a\u5916\u90e8\u94fe\u63a5\u3002\u60a8\u60f3\u6dfb\u52a0\u6240\u9700\u7684 https:\/\/ \u524d\u7f00\u5417\uff1f",
"Link list": "\u94fe\u63a5\u5217\u8868",
"Insert video": "\u63d2\u5165\u89c6\u9891",
"Insert\/edit video": "\u63d2\u5165\/\u7f16\u8f91\u89c6\u9891",
"Insert\/edit media": "\u63d2\u5165\/\u7f16\u8f91\u5a92\u4f53",
"Alternative source": "\u955c\u50cf",
"Alternative source URL": "\u66ff\u4ee3\u6765\u6e90\u7f51\u5740",
"Media poster (Image URL)": "\u5c01\u9762(\u56fe\u7247\u5730\u5740)",
"Paste your embed code below:": "\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:",
"Embed": "\u5185\u5d4c",
"Media...": "\u591a\u5a92\u4f53...",
"Nonbreaking space": "\u4e0d\u95f4\u65ad\u7a7a\u683c",
"Page break": "\u5206\u9875\u7b26",
"Paste as text": "\u7c98\u8d34\u4e3a\u6587\u672c",
"Preview": "\u9884\u89c8",
"Print...": "\u6253\u5370...",
"Save": "\u4fdd\u5b58",
"Find": "\u67e5\u627e",
"Replace with": "\u66ff\u6362\u4e3a",
"Replace": "\u66ff\u6362",
"Replace all": "\u5168\u90e8\u66ff\u6362",
"Previous": "\u4e0a\u4e00\u4e2a",
"Next": "\u4e0b\u4e00\u4e2a",
"Find and Replace": "\u67e5\u627e\u548c\u66ff\u6362",
"Find and replace...": "\u67e5\u627e\u5e76\u66ff\u6362...",
"Could not find the specified string.": "\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9.",
"Match case": "\u533a\u5206\u5927\u5c0f\u5199",
"Find whole words only": "\u5168\u5b57\u5339\u914d",
"Find in selection": "\u5728\u9009\u533a\u4e2d\u67e5\u627e",
"Spellcheck": "\u62fc\u5199\u68c0\u67e5",
"Spellcheck Language": "\u62fc\u5199\u68c0\u67e5\u8bed\u8a00",
"No misspellings found.": "\u6ca1\u6709\u53d1\u73b0\u62fc\u5199\u9519\u8bef",
"Ignore": "\u5ffd\u7565",
"Ignore all": "\u5168\u90e8\u5ffd\u7565",
"Finish": "\u5b8c\u6210",
"Add to Dictionary": "\u6dfb\u52a0\u5230\u5b57\u5178",
"Insert table": "\u63d2\u5165\u8868\u683c",
"Table properties": "\u8868\u683c\u5c5e\u6027",
"Delete table": "\u5220\u9664\u8868\u683c",
"Cell": "\u5355\u5143\u683c",
"Row": "\u884c",
"Column": "\u5217",
"Cell properties": "\u5355\u5143\u683c\u5c5e\u6027",
"Merge cells": "\u5408\u5e76\u5355\u5143\u683c",
"Split cell": "\u62c6\u5206\u5355\u5143\u683c",
"Insert row before": "\u5728\u4e0a\u65b9\u63d2\u5165",
"Insert row after": "\u5728\u4e0b\u65b9\u63d2\u5165",
"Delete row": "\u5220\u9664\u884c",
"Row properties": "\u884c\u5c5e\u6027",
"Cut row": "\u526a\u5207\u884c",
"Copy row": "\u590d\u5236\u884c",
"Paste row before": "\u7c98\u8d34\u5230\u4e0a\u65b9",
"Paste row after": "\u7c98\u8d34\u5230\u4e0b\u65b9",
"Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165",
"Insert column after": "\u5728\u53f3\u4fa7\u63d2\u5165",
"Delete column": "\u5220\u9664\u5217",
"Cols": "\u5217",
"Rows": "\u884c",
"Width": "\u5bbd",
"Height": "\u9ad8",
"Cell spacing": "\u5355\u5143\u683c\u5916\u95f4\u8ddd",
"Cell padding": "\u5355\u5143\u683c\u5185\u8fb9\u8ddd",
"Caption": "\u6807\u9898",
"Show caption": "\u663e\u793a\u6807\u9898",
"Left": "\u5de6\u5bf9\u9f50",
"Center": "\u5c45\u4e2d",
"Right": "\u53f3\u5bf9\u9f50",
"Cell type": "\u5355\u5143\u683c\u7c7b\u578b",
"Scope": "\u8303\u56f4",
"Alignment": "\u5bf9\u9f50\u65b9\u5f0f",
"H Align": "\u6c34\u5e73\u5bf9\u9f50",
"V Align": "\u5782\u76f4\u5bf9\u9f50",
"Top": "\u9876\u90e8\u5bf9\u9f50",
"Middle": "\u5782\u76f4\u5c45\u4e2d",
"Bottom": "\u5e95\u90e8\u5bf9\u9f50",
"Header cell": "\u8868\u5934\u5355\u5143\u683c",
"Row group": "\u884c\u7ec4",
"Column group": "\u5217\u7ec4",
"Row type": "\u884c\u7c7b\u578b",
"Header": "\u8868\u5934",
"Body": "\u8868\u4f53",
"Footer": "\u8868\u5c3e",
"Border color": "\u8fb9\u6846\u989c\u8272",
"Insert template...": "\u63d2\u5165\u6a21\u677f...",
"Templates": "\u6a21\u677f",
"Template": "\u6a21\u677f",
"Text color": "\u6587\u5b57\u989c\u8272",
"Background color": "\u80cc\u666f\u8272",
"Custom...": "\u81ea\u5b9a\u4e49...",
"Custom color": "\u81ea\u5b9a\u4e49\u989c\u8272",
"No color": "\u65e0",
"Remove color": "\u79fb\u9664\u989c\u8272",
"Table of Contents": "\u5185\u5bb9\u5217\u8868",
"Show blocks": "\u663e\u793a\u533a\u5757\u8fb9\u6846",
"Show invisible characters": "\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26",
"Word count": "\u5b57\u6570",
"Count": "\u8ba1\u6570",
"Document": "\u6587\u6863",
"Selection": "\u9009\u62e9",
"Words": "\u5355\u8bcd",
"Words: {0}": "\u5b57\u6570\uff1a{0}",
"{0} words": "{0} \u5b57",
"File": "\u6587\u4ef6",
"Edit": "\u7f16\u8f91",
"Insert": "\u63d2\u5165",
"View": "\u89c6\u56fe",
"Format": "\u683c\u5f0f",
"Table": "\u8868\u683c",
"Tools": "\u5de5\u5177",
"Powered by {0}": "\u7531{0}\u9a71\u52a8",
"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9",
"Image title": "\u56fe\u7247\u6807\u9898",
"Border width": "\u8fb9\u6846\u5bbd\u5ea6",
"Border style": "\u8fb9\u6846\u6837\u5f0f",
"Error": "\u9519\u8bef",
"Warn": "\u8b66\u544a",
"Valid": "\u6709\u6548",
"To open the popup, press Shift+Enter": "\u6309Shitf+Enter\u952e\u6253\u5f00\u5bf9\u8bdd\u6846",
"Rich Text Area. Press ALT-0 for help.": "\u7f16\u8f91\u533a\u3002\u6309Alt+0\u952e\u6253\u5f00\u5e2e\u52a9\u3002",
"System Font": "\u7cfb\u7edf\u5b57\u4f53",
"Failed to upload image: {0}": "\u56fe\u7247\u4e0a\u4f20\u5931\u8d25: {0}",
"Failed to load plugin: {0} from url {1}": "\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25: {0} \u6765\u81ea\u94fe\u63a5 {1}",
"Failed to load plugin url: {0}": "\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25 \u94fe\u63a5: {0}",
"Failed to initialize plugin: {0}": "\u63d2\u4ef6\u521d\u59cb\u5316\u5931\u8d25: {0}",
"example": "\u793a\u4f8b",
"Search": "\u641c\u7d22",
"All": "\u5168\u90e8",
"Currency": "\u8d27\u5e01",
"Text": "\u6587\u5b57",
"Quotations": "\u5f15\u7528",
"Mathematical": "\u6570\u5b66",
"Extended Latin": "\u62c9\u4e01\u8bed\u6269\u5145",
"Symbols": "\u7b26\u53f7",
"Arrows": "\u7bad\u5934",
"User Defined": "\u81ea\u5b9a\u4e49",
"dollar sign": "\u7f8e\u5143\u7b26\u53f7",
"currency sign": "\u8d27\u5e01\u7b26\u53f7",
"euro-currency sign": "\u6b27\u5143\u7b26\u53f7",
"colon sign": "\u5192\u53f7",
"cruzeiro sign": "\u514b\u9c81\u8d5b\u7f57\u5e01\u7b26\u53f7",
"french franc sign": "\u6cd5\u90ce\u7b26\u53f7",
"lira sign": "\u91cc\u62c9\u7b26\u53f7",
"mill sign": "\u5bc6\u5c14\u7b26\u53f7",
"naira sign": "\u5948\u62c9\u7b26\u53f7",
"peseta sign": "\u6bd4\u585e\u5854\u7b26\u53f7",
"rupee sign": "\u5362\u6bd4\u7b26\u53f7",
"won sign": "\u97e9\u5143\u7b26\u53f7",
"new sheqel sign": "\u65b0\u8c22\u514b\u5c14\u7b26\u53f7",
"dong sign": "\u8d8a\u5357\u76fe\u7b26\u53f7",
"kip sign": "\u8001\u631d\u57fa\u666e\u7b26\u53f7",
"tugrik sign": "\u56fe\u683c\u91cc\u514b\u7b26\u53f7",
"drachma sign": "\u5fb7\u62c9\u514b\u9a6c\u7b26\u53f7",
"german penny symbol": "\u5fb7\u56fd\u4fbf\u58eb\u7b26\u53f7",
"peso sign": "\u6bd4\u7d22\u7b26\u53f7",
"guarani sign": "\u74dc\u62c9\u5c3c\u7b26\u53f7",
"austral sign": "\u6fb3\u5143\u7b26\u53f7",
"hryvnia sign": "\u683c\u91cc\u592b\u5c3c\u4e9a\u7b26\u53f7",
"cedi sign": "\u585e\u5730\u7b26\u53f7",
"livre tournois sign": "\u91cc\u5f17\u5f17\u5c14\u7b26\u53f7",
"spesmilo sign": "spesmilo\u7b26\u53f7",
"tenge sign": "\u575a\u6208\u7b26\u53f7",
"indian rupee sign": "\u5370\u5ea6\u5362\u6bd4",
"turkish lira sign": "\u571f\u8033\u5176\u91cc\u62c9",
"nordic mark sign": "\u5317\u6b27\u9a6c\u514b",
"manat sign": "\u9a6c\u7eb3\u7279\u7b26\u53f7",
"ruble sign": "\u5362\u5e03\u7b26\u53f7",
"yen character": "\u65e5\u5143\u5b57\u6837",
"yuan character": "\u4eba\u6c11\u5e01\u5143\u5b57\u6837",
"yuan character, in hong kong and taiwan": "\u5143\u5b57\u6837\uff08\u6e2f\u53f0\u5730\u533a\uff09",
"yen\/yuan character variant one": "\u5143\u5b57\u6837\uff08\u5927\u5199\uff09",
"Loading emoticons...": "\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7...",
"Could not load emoticons": "\u4e0d\u80fd\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7",
"People": "\u4eba\u7c7b",
"Animals and Nature": "\u52a8\u7269\u548c\u81ea\u7136",
"Food and Drink": "\u98df\u7269\u548c\u996e\u54c1",
"Activity": "\u6d3b\u52a8",
"Travel and Places": "\u65c5\u6e38\u548c\u5730\u70b9",
"Objects": "\u7269\u4ef6",
"Flags": "\u65d7\u5e1c",
"Characters": "\u5b57\u7b26",
"Characters (no spaces)": "\u5b57\u7b26(\u65e0\u7a7a\u683c)",
"{0} characters": "{0} \u4e2a\u5b57\u7b26",
"Error: Form submit field collision.": "\u9519\u8bef: \u8868\u5355\u63d0\u4ea4\u5b57\u6bb5\u51b2\u7a81\u3002",
"Error: No form element found.": "\u9519\u8bef: \u6ca1\u6709\u8868\u5355\u63a7\u4ef6\u3002",
"Update": "\u66f4\u65b0",
"Color swatch": "\u989c\u8272\u6837\u672c",
"Turquoise": "\u9752\u7eff\u8272",
"Green": "\u7eff\u8272",
"Blue": "\u84dd\u8272",
"Purple": "\u7d2b\u8272",
"Navy Blue": "\u6d77\u519b\u84dd",
"Dark Turquoise": "\u6df1\u84dd\u7eff\u8272",
"Dark Green": "\u6df1\u7eff\u8272",
"Medium Blue": "\u4e2d\u84dd\u8272",
"Medium Purple": "\u4e2d\u7d2b\u8272",
"Midnight Blue": "\u6df1\u84dd\u8272",
"Yellow": "\u9ec4\u8272",
"Orange": "\u6a59\u8272",
"Red": "\u7ea2\u8272",
"Light Gray": "\u6d45\u7070\u8272",
"Gray": "\u7070\u8272",
"Dark Yellow": "\u6697\u9ec4\u8272",
"Dark Orange": "\u6df1\u6a59\u8272",
"Dark Red": "\u6df1\u7ea2\u8272",
"Medium Gray": "\u4e2d\u7070\u8272",
"Dark Gray": "\u6df1\u7070\u8272",
"Light Green": "\u6d45\u7eff\u8272",
"Light Yellow": "\u6d45\u9ec4\u8272",
"Light Red": "\u6d45\u7ea2\u8272",
"Light Purple": "\u6d45\u7d2b\u8272",
"Light Blue": "\u6d45\u84dd\u8272",
"Dark Purple": "\u6df1\u7d2b\u8272",
"Dark Blue": "\u6df1\u84dd\u8272",
"Black": "\u9ed1\u8272",
"White": "\u767d\u8272",
"Switch to or from fullscreen mode": "\u5207\u6362\u5168\u5c4f\u6a21\u5f0f",
"Open help dialog": "\u6253\u5f00\u5e2e\u52a9\u5bf9\u8bdd\u6846",
"history": "\u5386\u53f2",
"styles": "\u6837\u5f0f",
"formatting": "\u683c\u5f0f\u5316",
"alignment": "\u5bf9\u9f50",
"indentation": "\u7f29\u8fdb",
"Font": "\u5b57\u4f53",
"Size": "\u5b57\u53f7",
"More...": "\u66f4\u591a...",
"Select...": "\u9009\u62e9...",
"Preferences": "\u9996\u9009\u9879",
"Yes": "\u662f",
"No": "\u5426",
"Keyboard Navigation": "\u952e\u76d8\u6307\u5f15",
"Version": "\u7248\u672c",
"Code view": "\u4ee3\u7801\u89c6\u56fe",
"Open popup menu for split buttons": "\u6253\u5f00\u5f39\u51fa\u5f0f\u83dc\u5355\uff0c\u7528\u4e8e\u62c6\u5206\u6309\u94ae",
"List Properties": "\u5217\u8868\u5c5e\u6027",
"List properties...": "\u6807\u9898\u5b57\u4f53\u5c5e\u6027",
"Start list at number": "\u4ee5\u6570\u5b57\u5f00\u59cb\u5217\u8868",
"Line height": "\u884c\u9ad8",
"comments": "\u5907\u6ce8",
"Format Painter": "\u683c\u5f0f\u5237",
"Insert\/edit iframe": "\u63d2\u5165\/\u7f16\u8f91\u6846\u67b6",
"Capitalization": "\u5927\u5199",
"lowercase": "\u5c0f\u5199",
"UPPERCASE": "\u5927\u5199",
"Title Case": "\u9996\u5b57\u6bcd\u5927\u5199",
"permanent pen": "\u8bb0\u53f7\u7b14",
"Permanent Pen Properties": "\u6c38\u4e45\u7b14\u5c5e\u6027",
"Permanent pen properties...": "\u6c38\u4e45\u7b14\u5c5e\u6027...",
"case change": "\u6848\u4f8b\u66f4\u6539",
"page embed": "\u9875\u9762\u5d4c\u5165",
"Advanced sort...": "\u9ad8\u7ea7\u6392\u5e8f...",
"Advanced Sort": "\u9ad8\u7ea7\u6392\u5e8f",
"Sort table by column ascending": "\u6309\u5217\u5347\u5e8f\u8868",
"Sort table by column descending": "\u6309\u5217\u964d\u5e8f\u8868",
"Sort": "\u6392\u5e8f",
"Order": "\u6392\u5e8f",
"Sort by": "\u6392\u5e8f\u65b9\u5f0f",
"Ascending": "\u5347\u5e8f",
"Descending": "\u964d\u5e8f",
"Column {0}": "\u5217{0}",
"Row {0}": "\u884c{0}",
"Spellcheck...": "\u62fc\u5199\u68c0\u67e5...",
"Misspelled word": "\u62fc\u5199\u9519\u8bef\u7684\u5355\u8bcd",
"Suggestions": "\u5efa\u8bae",
"Change": "\u66f4\u6539",
"Finding word suggestions": "\u67e5\u627e\u5355\u8bcd\u5efa\u8bae",
"Success": "\u6210\u529f",
"Repair": "\u4fee\u590d",
"Issue {0} of {1}": "\u5171\u8ba1{1}\u95ee\u9898{0}",
"Images must be marked as decorative or have an alternative text description": "\u56fe\u50cf\u5fc5\u987b\u6807\u8bb0\u4e3a\u88c5\u9970\u6027\u6216\u5177\u6709\u66ff\u4ee3\u6587\u672c\u63cf\u8ff0",
"Images must have an alternative text description. Decorative images are not allowed.": "\u56fe\u50cf\u5fc5\u987b\u5177\u6709\u66ff\u4ee3\u6587\u672c\u63cf\u8ff0\u3002\u4e0d\u5141\u8bb8\u4f7f\u7528\u88c5\u9970\u56fe\u50cf\u3002",
"Or provide alternative text:": "\u6216\u63d0\u4f9b\u5907\u9009\u6587\u672c\uff1a",
"Make image decorative:": "\u4f7f\u56fe\u50cf\u88c5\u9970\uff1a",
"ID attribute must be unique": "ID \u5c5e\u6027\u5fc5\u987b\u662f\u552f\u4e00\u7684",
"Make ID unique": "\u4f7f ID \u72ec\u4e00\u65e0\u4e8c",
"Keep this ID and remove all others": "\u4fdd\u7559\u6b64 ID \u5e76\u5220\u9664\u6240\u6709\u5176\u4ed6",
"Remove this ID": "\u5220\u9664\u6b64 ID",
"Remove all IDs": "\u6e05\u9664\u5168\u90e8IDs",
"Checklist": "\u6e05\u5355",
"Anchor": "\u951a\u70b9",
"Special character": "\u7279\u6b8a\u7b26\u53f7",
"Code sample": "\u4ee3\u7801\u793a\u4f8b",
"Color": "\u989c\u8272",
"Document properties": "\u6587\u6863\u5c5e\u6027",
"Image description": "\u56fe\u7247\u63cf\u8ff0",
"Image": "\u56fe\u7247",
"Insert link": "\u63d2\u5165\u94fe\u63a5",
"Target": "\u6253\u5f00\u65b9\u5f0f",
"Link": "\u94fe\u63a5",
"Poster": "\u5c01\u9762",
"Media": "\u5a92\u4f53",
"Print": "\u6253\u5370",
"Prev": "\u4e0a\u4e00\u4e2a",
"Find and replace": "\u67e5\u627e\u548c\u66ff\u6362",
"Whole words": "\u5168\u5b57\u5339\u914d",
"Insert template": "\u63d2\u5165\u6a21\u677f"
});

@ -1,419 +0,0 @@
tinymce.addI18n('zh_TW',{
"Redo": "\u91cd\u505a",
"Undo": "\u64a4\u92b7",
"Cut": "\u526a\u4e0b",
"Copy": "\u8907\u88fd",
"Paste": "\u8cbc\u4e0a",
"Select all": "\u5168\u9078",
"New document": "\u65b0\u6587\u4ef6",
"Ok": "\u78ba\u5b9a",
"Cancel": "\u53d6\u6d88",
"Visual aids": "\u5c0f\u5e6b\u624b",
"Bold": "\u7c97\u9ad4",
"Italic": "\u659c\u9ad4",
"Underline": "\u4e0b\u5283\u7dda",
"Strikethrough": "\u522a\u9664\u7dda",
"Superscript": "\u4e0a\u6a19",
"Subscript": "\u4e0b\u6a19",
"Clear formatting": "\u6e05\u9664\u683c\u5f0f",
"Align left": "\u5de6\u908a\u5c0d\u9f4a",
"Align center": "\u4e2d\u9593\u5c0d\u9f4a",
"Align right": "\u53f3\u908a\u5c0d\u9f4a",
"Justify": "\u5de6\u53f3\u5c0d\u9f4a",
"Bullet list": "\u9805\u76ee\u6e05\u55ae",
"Numbered list": "\u6578\u5b57\u6e05\u55ae",
"Decrease indent": "\u6e1b\u5c11\u7e2e\u6392",
"Increase indent": "\u589e\u52a0\u7e2e\u6392",
"Close": "\u95dc\u9589",
"Formats": "\u683c\u5f0f",
"Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u60a8\u7684\u700f\u89bd\u5668\u4e0d\u652f\u63f4\u5b58\u53d6\u526a\u8cbc\u7c3f\uff0c\u53ef\u4ee5\u4f7f\u7528\u5feb\u901f\u9375 Ctrl + X\/C\/V \u4ee3\u66ff\u526a\u4e0b\u3001\u8907\u88fd\u8207\u8cbc\u4e0a\u3002",
"Headers": "\u6a19\u984c",
"Header 1": "\u6a19\u984c 1",
"Header 2": "\u6a19\u984c 2",
"Header 3": "\u6a19\u984c 3",
"Header 4": "\u6a19\u984c 4",
"Header 5": "\u6a19\u984c 5",
"Header 6": "\u6a19\u984c 6",
"Headings": "\u6a19\u984c",
"Heading 1": "\u6a19\u984c1",
"Heading 2": "\u6a19\u984c2",
"Heading 3": "\u6a19\u984c3",
"Heading 4": "\u6a19\u984c4",
"Heading 5": "\u6a19\u984c5",
"Heading 6": "\u6a19\u984c6",
"Preformatted": "\u9810\u5148\u683c\u5f0f\u5316\u7684",
"Div": "Div",
"Pre": "Pre",
"Code": "\u4ee3\u78bc",
"Paragraph": "\u6bb5\u843d",
"Blockquote": "\u5f15\u6587\u5340\u584a",
"Inline": "\u5167\u806f",
"Blocks": "\u57fa\u584a",
"Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u76ee\u524d\u5c07\u4ee5\u7d14\u6587\u5b57\u7684\u6a21\u5f0f\u8cbc\u4e0a\uff0c\u60a8\u53ef\u4ee5\u518d\u9ede\u9078\u4e00\u6b21\u53d6\u6d88\u3002",
"Fonts": "\u5b57\u578b",
"Font Sizes": "\u5b57\u578b\u5927\u5c0f",
"Class": "\u985e\u578b",
"Browse for an image": "\u5f9e\u5716\u7247\u4e2d\u700f\u89bd",
"OR": "\u6216",
"Drop an image here": "\u62d6\u66f3\u5716\u7247\u81f3\u6b64",
"Upload": "\u4e0a\u50b3",
"Block": "\u5340\u584a",
"Align": "\u5c0d\u9f4a",
"Default": "\u9810\u8a2d",
"Circle": "\u7a7a\u5fc3\u5713",
"Disc": "\u5be6\u5fc3\u5713",
"Square": "\u6b63\u65b9\u5f62",
"Lower Alpha": "\u5c0f\u5beb\u82f1\u6587\u5b57\u6bcd",
"Lower Greek": "\u5e0c\u81d8\u5b57\u6bcd",
"Lower Roman": "\u5c0f\u5beb\u7f85\u99ac\u6578\u5b57",
"Upper Alpha": "\u5927\u5beb\u82f1\u6587\u5b57\u6bcd",
"Upper Roman": "\u5927\u5beb\u7f85\u99ac\u6578\u5b57",
"Anchor...": "\u9328\u9ede...",
"Name": "\u540d\u7a31",
"Id": "Id",
"Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "Id\u61c9\u4ee5\u5b57\u6bcd\u958b\u982d\uff0c\u5f8c\u9762\u63a5\u8457\u5b57\u6bcd\uff0c\u6578\u5b57\uff0c\u7834\u6298\u865f\uff0c\u9ede\u6578\uff0c\u5192\u865f\u6216\u4e0b\u5283\u7dda\u3002",
"You have unsaved changes are you sure you want to navigate away?": "\u7de8\u8f2f\u5c1a\u672a\u88ab\u5132\u5b58\uff0c\u4f60\u78ba\u5b9a\u8981\u96e2\u958b\uff1f",
"Restore last draft": "\u8f09\u5165\u4e0a\u4e00\u6b21\u7de8\u8f2f\u7684\u8349\u7a3f",
"Special character...": "\u7279\u6b8a\u5b57\u5143......",
"Source code": "\u539f\u59cb\u78bc",
"Insert\/Edit code sample": "\u63d2\u5165\/\u7de8\u8f2f \u7a0b\u5f0f\u78bc\u7bc4\u4f8b",
"Language": "\u8a9e\u8a00",
"Code sample...": "\u7a0b\u5f0f\u78bc\u7bc4\u4f8b...",
"Color Picker": "\u9078\u8272\u5668",
"R": "\u7d05",
"G": "\u7da0",
"B": "\u85cd",
"Left to right": "\u5f9e\u5de6\u5230\u53f3",
"Right to left": "\u5f9e\u53f3\u5230\u5de6",
"Emoticons...": "\u8868\u60c5\u7b26\u865f\u2026",
"Metadata and Document Properties": "\u5f8c\u8a2d\u8cc7\u6599\u8207\u6587\u4ef6\u5c6c\u6027",
"Title": "\u6a19\u984c",
"Keywords": "\u95dc\u9375\u5b57",
"Description": "\u63cf\u8ff0",
"Robots": "\u6a5f\u5668\u4eba",
"Author": "\u4f5c\u8005",
"Encoding": "\u7de8\u78bc",
"Fullscreen": "\u5168\u87a2\u5e55",
"Action": "\u52d5\u4f5c",
"Shortcut": "\u5feb\u901f\u9375",
"Help": "\u5e6b\u52a9",
"Address": "\u5730\u5740",
"Focus to menubar": "\u8df3\u81f3\u9078\u55ae\u5217",
"Focus to toolbar": "\u8df3\u81f3\u5de5\u5177\u5217",
"Focus to element path": "\u8df3\u81f3HTML\u5143\u7d20\u5217",
"Focus to contextual toolbar": "\u8df3\u81f3\u5feb\u6377\u9078\u55ae",
"Insert link (if link plugin activated)": "\u65b0\u589e\u6377\u5f91 (\u6377\u5f91\u5916\u639b\u555f\u7528\u6642)",
"Save (if save plugin activated)": "\u5132\u5b58 (\u5132\u5b58\u5916\u639b\u555f\u7528\u6642)",
"Find (if searchreplace plugin activated)": "\u5c0b\u627e (\u5c0b\u627e\u53d6\u4ee3\u5916\u639b\u555f\u7528\u6642)",
"Plugins installed ({0}):": "({0}) \u500b\u5916\u639b\u5df2\u5b89\u88dd\uff1a",
"Premium plugins:": "\u52a0\u503c\u5916\u639b\uff1a",
"Learn more...": "\u4e86\u89e3\u66f4\u591a...",
"You are using {0}": "\u60a8\u6b63\u5728\u4f7f\u7528 {0}",
"Plugins": "\u5916\u639b",
"Handy Shortcuts": "\u5feb\u901f\u9375",
"Horizontal line": "\u6c34\u5e73\u7dda",
"Insert\/edit image": "\u63d2\u5165\/\u7de8\u8f2f \u5716\u7247",
"Image description": "\u5716\u7247\u63cf\u8ff0",
"Source": "\u5716\u7247\u7db2\u5740",
"Dimensions": "\u5c3a\u5bf8",
"Constrain proportions": "\u7b49\u6bd4\u4f8b\u7e2e\u653e",
"General": "\u4e00\u822c",
"Advanced": "\u9032\u968e",
"Style": "\u6a23\u5f0f",
"Vertical space": "\u9ad8\u5ea6",
"Horizontal space": "\u5bec\u5ea6",
"Border": "\u908a\u6846",
"Insert image": "\u63d2\u5165\u5716\u7247",
"Image...": "\u5716\u7247......",
"Image list": "\u5716\u7247\u6e05\u55ae",
"Rotate counterclockwise": "\u9006\u6642\u91dd\u65cb\u8f49",
"Rotate clockwise": "\u9806\u6642\u91dd\u65cb\u8f49",
"Flip vertically": "\u5782\u76f4\u7ffb\u8f49",
"Flip horizontally": "\u6c34\u5e73\u7ffb\u8f49",
"Edit image": "\u7de8\u8f2f\u5716\u7247",
"Image options": "\u5716\u7247\u9078\u9805",
"Zoom in": "\u653e\u5927",
"Zoom out": "\u7e2e\u5c0f",
"Crop": "\u88c1\u526a",
"Resize": "\u8abf\u6574\u5927\u5c0f",
"Orientation": "\u65b9\u5411",
"Brightness": "\u4eae\u5ea6",
"Sharpen": "\u92b3\u5316",
"Contrast": "\u5c0d\u6bd4",
"Color levels": "\u984f\u8272\u5c64\u6b21",
"Gamma": "\u4f3d\u99ac\u503c",
"Invert": "\u53cd\u8f49",
"Apply": "\u61c9\u7528",
"Back": "\u5f8c\u9000",
"Insert date\/time": "\u63d2\u5165 \u65e5\u671f\/\u6642\u9593",
"Date\/time": "\u65e5\u671f\/\u6642\u9593",
"Insert\/Edit Link": "\u63d2\u5165\/\u7de8\u8f2f\u9023\u7d50",
"Insert\/edit link": "\u63d2\u5165\/\u7de8\u8f2f\u9023\u7d50",
"Text to display": "\u986f\u793a\u6587\u5b57",
"Url": "\u7db2\u5740",
"Open link in...": "\u958b\u555f\u9023\u7d50\u65bc...",
"Current window": "\u76ee\u524d\u8996\u7a97",
"None": "\u7121",
"New window": "\u53e6\u958b\u8996\u7a97",
"Remove link": "\u79fb\u9664\u9023\u7d50",
"Anchors": "\u52a0\u5165\u9328\u9ede",
"Link...": "\u9023\u7d50...",
"Paste or type a link": "\u8cbc\u4e0a\u6216\u8f38\u5165\u9023\u7d50",
"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u4f60\u6240\u586b\u5beb\u7684URL\u70ba\u96fb\u5b50\u90f5\u4ef6\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7db4\u55ce\uff1f",
"The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u4f60\u6240\u586b\u5beb\u7684URL\u5c6c\u65bc\u5916\u90e8\u93c8\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:\/\/:\u524d\u7db4\u55ce\uff1f",
"Link list": "\u9023\u7d50\u6e05\u55ae",
"Insert video": "\u63d2\u5165\u5f71\u97f3",
"Insert\/edit video": "\u63d2\u4ef6\/\u7de8\u8f2f \u5f71\u97f3",
"Insert\/edit media": "\u63d2\u5165\/\u7de8\u8f2f \u5a92\u9ad4",
"Alternative source": "\u66ff\u4ee3\u5f71\u97f3",
"Alternative source URL": "\u66ff\u4ee3\u4f86\u6e90URL",
"Media poster (Image URL)": "\u5a92\u9ad4\u6d77\u5831\uff08\u5f71\u50cfImage URL\uff09",
"Paste your embed code below:": "\u8acb\u5c07\u60a8\u7684\u5d4c\u5165\u5f0f\u7a0b\u5f0f\u78bc\u8cbc\u5728\u4e0b\u9762:",
"Embed": "\u5d4c\u5165\u78bc",
"Media...": "\u5a92\u9ad4...",
"Nonbreaking space": "\u4e0d\u5206\u884c\u7684\u7a7a\u683c",
"Page break": "\u5206\u9801",
"Paste as text": "\u4ee5\u7d14\u6587\u5b57\u8cbc\u4e0a",
"Preview": "\u9810\u89bd",
"Print...": "\u5217\u5370...",
"Save": "\u5132\u5b58",
"Find": "\u641c\u5c0b",
"Replace with": "\u66f4\u63db",
"Replace": "\u66ff\u63db",
"Replace all": "\u66ff\u63db\u5168\u90e8",
"Previous": "\u4e0a\u4e00\u500b",
"Next": "\u4e0b\u4e00\u500b",
"Find and replace...": "\u5c0b\u627e\u53ca\u53d6\u4ee3...",
"Could not find the specified string.": "\u7121\u6cd5\u67e5\u8a62\u5230\u6b64\u7279\u5b9a\u5b57\u4e32",
"Match case": "\u76f8\u5339\u914d\u6848\u4ef6",
"Find whole words only": "\u50c5\u627e\u51fa\u5b8c\u6574\u5b57\u532f",
"Spell check": "\u62fc\u5beb\u6aa2\u67e5",
"Ignore": "\u5ffd\u7565",
"Ignore all": "\u5ffd\u7565\u6240\u6709",
"Finish": "\u5b8c\u6210",
"Add to Dictionary": "\u52a0\u5165\u5b57\u5178\u4e2d",
"Insert table": "\u63d2\u5165\u8868\u683c",
"Table properties": "\u8868\u683c\u5c6c\u6027",
"Delete table": "\u522a\u9664\u8868\u683c",
"Cell": "\u5132\u5b58\u683c",
"Row": "\u5217",
"Column": "\u884c",
"Cell properties": "\u5132\u5b58\u683c\u5c6c\u6027",
"Merge cells": "\u5408\u4f75\u5132\u5b58\u683c",
"Split cell": "\u5206\u5272\u5132\u5b58\u683c",
"Insert row before": "\u63d2\u5165\u5217\u5728...\u4e4b\u524d",
"Insert row after": "\u63d2\u5165\u5217\u5728...\u4e4b\u5f8c",
"Delete row": "\u522a\u9664\u5217",
"Row properties": "\u5217\u5c6c\u6027",
"Cut row": "\u526a\u4e0b\u5217",
"Copy row": "\u8907\u88fd\u5217",
"Paste row before": "\u8cbc\u4e0a\u5217\u5728...\u4e4b\u524d",
"Paste row after": "\u8cbc\u4e0a\u5217\u5728...\u4e4b\u5f8c",
"Insert column before": "\u63d2\u5165\u6b04\u4f4d\u5728...\u4e4b\u524d",
"Insert column after": "\u63d2\u5165\u6b04\u4f4d\u5728...\u4e4b\u5f8c",
"Delete column": "\u522a\u9664\u884c",
"Cols": "\u6b04\u4f4d\u6bb5",
"Rows": "\u5217",
"Width": "\u5bec\u5ea6",
"Height": "\u9ad8\u5ea6",
"Cell spacing": "\u5132\u5b58\u683c\u5f97\u9593\u8ddd",
"Cell padding": "\u5132\u5b58\u683c\u7684\u908a\u8ddd",
"Show caption": "\u986f\u793a\u6a19\u984c",
"Left": "\u5de6\u908a",
"Center": "\u4e2d\u9593",
"Right": "\u53f3\u908a",
"Cell type": "\u5132\u5b58\u683c\u7684\u985e\u578b",
"Scope": "\u7bc4\u570d",
"Alignment": "\u5c0d\u9f4a",
"H Align": "\u6c34\u5e73\u4f4d\u7f6e",
"V Align": "\u5782\u76f4\u4f4d\u7f6e",
"Top": "\u7f6e\u9802",
"Middle": "\u7f6e\u4e2d",
"Bottom": "\u7f6e\u5e95",
"Header cell": "\u6a19\u982d\u5132\u5b58\u683c",
"Row group": "\u5217\u7fa4\u7d44",
"Column group": "\u6b04\u4f4d\u7fa4\u7d44",
"Row type": "\u884c\u7684\u985e\u578b",
"Header": "\u6a19\u982d",
"Body": "\u4e3b\u9ad4",
"Footer": "\u9801\u5c3e",
"Border color": "\u908a\u6846\u984f\u8272",
"Insert template...": "\u63d2\u5165\u6a23\u7248...",
"Templates": "\u6a23\u7248",
"Template": "\u6a23\u677f",
"Text color": "\u6587\u5b57\u984f\u8272",
"Background color": "\u80cc\u666f\u984f\u8272",
"Custom...": "\u81ea\u8a02",
"Custom color": "\u81ea\u8a02\u984f\u8272",
"No color": "No color",
"Remove color": "\u79fb\u9664\u984f\u8272",
"Table of Contents": "\u76ee\u9304",
"Show blocks": "\u986f\u793a\u5340\u584a\u8cc7\u8a0a",
"Show invisible characters": "\u986f\u793a\u96b1\u85cf\u5b57\u5143",
"Word count": "\u8a08\u7b97\u5b57\u6578",
"Count": "\u8a08\u7b97",
"Document": "\u6587\u4ef6",
"Selection": "\u9078\u9805",
"Words": "\u5b57\u6578",
"Words: {0}": "\u5b57\u6578\uff1a{0}",
"{0} words": "{0} \u5b57\u5143",
"File": "\u6a94\u6848",
"Edit": "\u7de8\u8f2f",
"Insert": "\u63d2\u5165",
"View": "\u6aa2\u8996",
"Format": "\u683c\u5f0f",
"Table": "\u8868\u683c",
"Tools": "\u5de5\u5177",
"Powered by {0}": "\u7531 {0} \u63d0\u4f9b",
"Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u8c50\u5bcc\u7684\u6587\u672c\u5340\u57df\u3002\u6309ALT-F9\u524d\u5f80\u4e3b\u9078\u55ae\u3002\u6309ALT-F10\u547c\u53eb\u5de5\u5177\u6b04\u3002\u6309ALT-0\u5c0b\u6c42\u5e6b\u52a9",
"Image title": "\u5716\u7247\u6a19\u984c",
"Border width": "\u6846\u7dda\u5bec\u5ea6",
"Border style": "\u6846\u7dda\u6a23\u5f0f",
"Error": "\u932f\u8aa4",
"Warn": "\u8b66\u544a",
"Valid": "\u6709\u6548",
"To open the popup, press Shift+Enter": "\u8981\u958b\u555f\u5f48\u51fa\u8996\u7a97\uff0c\u8acb\u6309Shift+Enter",
"Rich Text Area. Press ALT-0 for help.": "\u5bcc\u6587\u672c\u5340\u57df\u3002\u8acb\u6309ALT-0\u5c0b\u6c42\u5354\u52a9\u3002",
"System Font": "\u7cfb\u7d71\u5b57\u578b",
"Failed to upload image: {0}": "\u7121\u6cd5\u4e0a\u50b3\u5f71\u50cf\uff1a{0}",
"Failed to load plugin: {0} from url {1}": "\u7121\u6cd5\u4e0a\u50b3\u63d2\u4ef6\uff1a{0}\u81eaurl{1}",
"Failed to load plugin url: {0}": "\u7121\u6cd5\u4e0a\u50b3\u63d2\u4ef6\uff1a{0}",
"Failed to initialize plugin: {0}": "\u7121\u6cd5\u555f\u52d5\u63d2\u4ef6\uff1a{0}",
"example": "\u7bc4\u4f8b",
"Search": "\u641c\u7d22",
"All": "\u5168\u90e8",
"Currency": "\u8ca8\u5e63",
"Text": "\u6587\u672c",
"Quotations": "\u5f15\u7528",
"Mathematical": "\u6578\u5b78",
"Extended Latin": "\u62c9\u4e01\u5b57\u6bcd\u64f4\u5145",
"Symbols": "\u7b26\u865f",
"Arrows": "\u7bad\u982d",
"User Defined": "\u4f7f\u7528\u8005\u5df2\u5b9a\u7fa9",
"dollar sign": "\u7f8e\u5143\u7b26\u865f",
"currency sign": "\u8ca8\u5e63\u7b26\u865f",
"euro-currency sign": "\u6b50\u5143\u7b26\u865f",
"colon sign": "\u79d1\u6717\u7b26\u865f",
"cruzeiro sign": "\u514b\u9b6f\u8cfd\u7f85\u7b26\u865f",
"french franc sign": "\u6cd5\u6717\u7b26\u865f",
"lira sign": "\u91cc\u62c9\u7b26\u865f",
"mill sign": "\u6587\u7b26\u865f",
"naira sign": "\u5948\u62c9\u7b26\u865f",
"peseta sign": "\u6bd4\u585e\u5854\u7b26\u865f",
"rupee sign": "\u76e7\u6bd4\u7b26\u865f",
"won sign": "\u97d3\u571c\u7b26\u865f",
"new sheqel sign": "\u65b0\u8b1d\u514b\u723e\u7b26\u865f",
"dong sign": "\u8d8a\u5357\u76fe\u7b26\u865f",
"kip sign": "\u8001\u64be\u5e63\u7b26\u865f",
"tugrik sign": "\u8499\u53e4\u5e63\u7b26\u865f",
"drachma sign": "\u5fb7\u514b\u62c9\u99ac\u7b26\u865f",
"german penny symbol": "\u5fb7\u570b\u5206\u7b26\u865f",
"peso sign": "\u62ab\u7d22\u7b26\u865f",
"guarani sign": "\u5df4\u62c9\u572d\u5e63\u7b26\u865f",
"austral sign": "\u963f\u6839\u5ef7\u5e63\u7b26\u865f",
"hryvnia sign": "\u70cf\u514b\u862d\u5e63\u7b26\u865f",
"cedi sign": "\u8fe6\u7d0d\u5e63\u7b26\u865f",
"livre tournois sign": "\u91cc\u5f17\u723e\u7b26\u865f",
"spesmilo sign": "\u570b\u969b\u5e63\u7b26\u865f",
"tenge sign": "\u54c8\u85a9\u514b\u5e63\u7b26\u865f",
"indian rupee sign": "\u5370\u5ea6\u76e7\u6bd4\u7b26\u865f",
"turkish lira sign": "\u571f\u8033\u5176\u91cc\u62c9\u7b26\u865f",
"nordic mark sign": "\u5317\u6b50\u99ac\u514b\u7b26\u865f",
"manat sign": "\u4e9e\u585e\u62dc\u7136\u5e63\u7b26\u865f",
"ruble sign": "\u76e7\u5e03\u7b26\u865f",
"yen character": "\u65e5\u5713\u7b26\u865f",
"yuan character": "\u4eba\u6c11\u5e63\u7b26\u865f",
"yuan character, in hong kong and taiwan": "\u6e2f\u5143\u8207\u53f0\u5e63\u7b26\u865f",
"yen\/yuan character variant one": "\u65e5\u5713\/\u4eba\u6c11\u5e63\u7b26\u865f\u8b8a\u5316\u578b",
"Loading emoticons...": "\u8f09\u5165\u8868\u60c5\u7b26\u865f\u2026",
"Could not load emoticons": "\u7121\u6cd5\u8f09\u5165\u8868\u60c5\u7b26\u865f",
"People": "\u4eba",
"Animals and Nature": "\u52d5\u7269\u8207\u81ea\u7136",
"Food and Drink": "\u98f2\u98df",
"Activity": "\u6d3b\u52d5",
"Travel and Places": "\u65c5\u884c\u8207\u5730\u9ede",
"Objects": "\u7269\u4ef6",
"Flags": "\u65d7\u6a19",
"Characters": "\u5b57\u5143",
"Characters (no spaces)": "\u5b57\u5143\uff08\u7121\u7a7a\u683c\uff09",
"{0} characters": "{0}\u5b57\u5143",
"Error: Form submit field collision.": "\u932f\u8aa4\uff1a\u8868\u683c\u905e\u4ea4\u6b04\u4f4d\u885d\u7a81\u3002",
"Error: No form element found.": "\u932f\u8aa4\uff1a\u627e\u4e0d\u5230\u8868\u683c\u5143\u7d20\u3002",
"Update": "\u66f4\u65b0",
"Color swatch": "\u8272\u5f69\u6a23\u672c",
"Turquoise": "\u571f\u8033\u5176\u85cd",
"Green": "\u7da0\u8272",
"Blue": "\u85cd\u8272",
"Purple": "\u7d2b\u8272",
"Navy Blue": "\u6df1\u85cd\u8272",
"Dark Turquoise": "\u6df1\u571f\u8033\u5176\u85cd",
"Dark Green": "\u6df1\u7da0\u8272",
"Medium Blue": "\u4e2d\u85cd\u8272",
"Medium Purple": "\u4e2d\u7d2b\u8272",
"Midnight Blue": "\u9ed1\u85cd\u8272",
"Yellow": "\u9ec3\u8272",
"Orange": "\u6a59\u8272",
"Red": "\u7d05\u8272",
"Light Gray": "\u6dfa\u7070\u8272",
"Gray": "\u7070\u8272",
"Dark Yellow": "\u6df1\u9ec3\u8272",
"Dark Orange": "\u6df1\u6a59\u8272",
"Dark Red": "\u6697\u7d05\u8272",
"Medium Gray": "\u4e2d\u7070\u8272",
"Dark Gray": "\u6df1\u7070\u8272",
"Light Green": "\u6de1\u7da0\u8272",
"Light Yellow": "\u6dfa\u9ec3\u8272",
"Light Red": "\u6dfa\u7d05\u8272",
"Light Purple": "\u6dfa\u7d2b\u8272",
"Light Blue": "\u6dfa\u85cd\u8272",
"Dark Purple": "\u6df1\u7d2b\u8272",
"Dark Blue": "\u6df1\u85cd\u8272",
"Black": "\u9ed1\u8272",
"White": "\u767d\u8272",
"Switch to or from fullscreen mode": "\u8f49\u63db\u81ea\/\u81f3\u5168\u87a2\u5e55\u6a21\u5f0f",
"Open help dialog": "\u958b\u555f\u5354\u52a9\u5c0d\u8a71",
"history": "\u6b77\u53f2",
"styles": "\u6a23\u5f0f",
"formatting": "\u683c\u5f0f",
"alignment": "\u5c0d\u9f4a",
"indentation": "\u7e2e\u6392",
"permanent pen": "\u6c38\u4e45\u6027\u7b46",
"comments": "\u8a3b\u89e3",
"Format Painter": "\u8907\u88fd\u683c\u5f0f",
"Insert\/edit iframe": "\u63d2\u5165\/\u7de8\u8f2fiframe",
"Capitalization": "\u5927\u5beb",
"lowercase": "\u5c0f\u5beb",
"UPPERCASE": "\u5927\u5beb",
"Title Case": "\u5b57\u9996\u5927\u5beb",
"Permanent Pen Properties": "\u6c38\u4e45\u6a19\u8a18\u5c6c\u6027",
"Permanent pen properties...": "\u6c38\u4e45\u6a19\u8a18\u5c6c\u6027......",
"Font": "\u5b57\u578b",
"Size": "\u5b57\u5f62\u5927\u5c0f",
"More...": "\u66f4\u591a\u8cc7\u8a0a......",
"Spellcheck Language": "\u62fc\u5beb\u8a9e\u8a00",
"Select...": "\u9078\u64c7......",
"Preferences": "\u9996\u9078\u9805",
"Yes": "\u662f",
"No": "\u5426",
"Keyboard Navigation": "\u9375\u76e4\u5c0e\u822a",
"Version": "\u7248\u672c",
"Anchor": "\u52a0\u5165\u9328\u9ede",
"Special character": "\u7279\u6b8a\u5b57\u5143",
"Code sample": "\u7a0b\u5f0f\u78bc\u7bc4\u4f8b",
"Color": "\u984f\u8272",
"Emoticons": "\u8868\u60c5",
"Document properties": "\u6587\u4ef6\u7684\u5c6c\u6027",
"Image": "\u5716\u7247",
"Insert link": "\u63d2\u5165\u9023\u7d50",
"Target": "\u958b\u555f\u65b9\u5f0f",
"Link": "\u9023\u7d50",
"Poster": "\u9810\u89bd\u5716\u7247",
"Media": "\u5a92\u9ad4",
"Print": "\u5217\u5370",
"Prev": "\u4e0a\u4e00\u500b",
"Find and replace": "\u5c0b\u627e\u53ca\u53d6\u4ee3",
"Whole words": "\u6574\u500b\u55ae\u5b57",
"Spellcheck": "\u62fc\u5b57\u6aa2\u67e5",
"Caption": "\u8868\u683c\u6a19\u984c",
"Insert template": "\u63d2\u5165\u6a23\u7248"
});

@ -1,7 +0,0 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
body{background-color:#2f3742;color:#dfe0e4;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem}

@ -1,7 +0,0 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}

@ -1,7 +0,0 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
@media screen{html{background:#f4f4f4;min-height:100%}}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif}@media screen{body{background-color:#fff;box-shadow:0 0 4px rgba(0,0,0,.15);box-sizing:border-box;margin:1rem auto 0;max-width:820px;min-height:calc(100vh - 1rem);padding:4rem 6rem 6rem 6rem}}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure figcaption{color:#999;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}

@ -1,7 +0,0 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem auto;max-width:900px}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,7 +0,0 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{background-color:green;display:inline-block;opacity:.5;position:absolute}body{-webkit-text-size-adjust:none}body img{max-width:96vw}body table img{max-width:95%}body{font-family:sans-serif}table{border-collapse:collapse}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,7 +0,0 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;left:0;margin:0;overflow:hidden;-ms-scroll-chaining:none;overscroll-behavior:none;padding:0;position:fixed;top:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox.tox-tinymce.tox-fullscreen{background-color:transparent;z-index:1200}.tox-shadowhost.tox-fullscreen{z-index:1200}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,7 +0,0 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{background-color:green;display:inline-block;opacity:.5;position:absolute}body{-webkit-text-size-adjust:none}body img{max-width:96vw}body table img{max-width:95%}body{font-family:sans-serif}table{border-collapse:collapse}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,7 +0,0 @@
/**
* Copyright (c) Tiny Technologies, Inc. All rights reserved.
* Licensed under the LGPL or a commercial license.
* For LGPL see License.txt in the project root for license information.
* For commercial licenses see https://www.tiny.cloud/
*/
body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;left:0;margin:0;overflow:hidden;-ms-scroll-chaining:none;overscroll-behavior:none;padding:0;position:fixed;top:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox.tox-tinymce.tox-fullscreen{background-color:transparent;z-index:1200}.tox-shadowhost.tox-fullscreen{z-index:1200}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}

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

@ -3,35 +3,103 @@ import { getIds } from '@/utils/common';
const host = `http://192.168.31.51:9000`; const host = `http://192.168.31.51:9000`;
export const accessStrategyGovernmentBlacklistFind = async (): Promise<any> => (await axios.post(`/product/accessStrategyGovernmentBlacklist/details`, getIds())).data; export const accessStrategyGovernmentBlacklistList = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/accessStrategyGovernmentBlacklist/list`, {
...getIds(),
...data,
})
).data;
export const accessStrategyGovernmentBlacklistFind = async (params: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyGovernmentBlacklist/details`, {}, { params })).data;
export const accessStrategyGovernmentBlacklistSave = async (data: Record<string, any>): Promise<any> => export const accessStrategyGovernmentBlacklistSave = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyGovernmentBlacklist/saveOrUpdate`, data)).data; (await axios.post(`/product/accessStrategyGovernmentBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyGovernmentBlacklistDel = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyGovernmentBlacklist/delete`, data)).data;
export const accessStrategyEnterpriseBlacklistFind = async (): Promise<any> => (await axios.post(`/product/accessStrategyEnterpriseBlacklist/details`, getIds())).data; export const accessStrategyEnterpriseBlacklist = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/accessStrategyEnterpriseBlacklist/list`, {
...getIds(),
...data,
})
).data;
export const accessStrategyEnterpriseBlacklistFind = async (params: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyEnterpriseBlacklist/details`, {}, { params })).data;
export const accessStrategyEnterpriseBlacklistSave = async (data: Record<string, any>): Promise<any> => export const accessStrategyEnterpriseBlacklistSave = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyEnterpriseBlacklist/saveOrUpdate`, data)).data; (await axios.post(`/product/accessStrategyEnterpriseBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyEnterpriseBlacklistDel = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyEnterpriseBlacklist/delete`, data)).data;
export const accessStrategyAntiFraudStrategyFind = async (): Promise<any> => (await axios.post(`/product/accessStrategyAntiFraudStrategy/details`, getIds())).data; export const accessStrategyAntiFraudStrategy = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/accessStrategyAntiFraudStrategy/list`, {
...getIds(),
...data,
})
).data;
export const accessStrategyAntiFraudStrategyFind = async (params: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyAntiFraudStrategy/details`, {}, { params })).data;
export const accessStrategyAntiFraudStrategySave = async (data: Record<string, any>): Promise<any> => export const accessStrategyAntiFraudStrategySave = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyAntiFraudStrategy/saveOrUpdate`, data)).data; (await axios.post(`/product/accessStrategyAntiFraudStrategy/saveOrUpdate`, data)).data;
export const accessStrategyAntiFraudStrategyDel = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyAntiFraudStrategy/delete`, data)).data;
export const accessStrategyBusinessBlacklistFind = async (): Promise<any> => (await axios.post(`/product/accessStrategyBusinessBlacklist/details`, getIds())).data; export const accessStrategyBusinessBlacklist = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/accessStrategyBusinessBlacklist/list`, {
...getIds(),
...data,
})
).data;
export const accessStrategyBusinessBlacklistFind = async (params: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyBusinessBlacklist/details`, {}, { params })).data;
export const accessStrategyBusinessBlacklistSave = async (data: Record<string, any>): Promise<any> => export const accessStrategyBusinessBlacklistSave = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyBusinessBlacklist/saveOrUpdate`, data)).data; (await axios.post(`/product/accessStrategyBusinessBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyBusinessBlacklistDel = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyBusinessBlacklist/delete`, data)).data;
export const accessStrategyCreditBlacklistFind = async (): Promise<any> => (await axios.post(`/product/accessStrategyCreditBlacklist/details`, getIds())).data; export const accessStrategyCreditBlacklist = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/accessStrategyCreditBlacklist/list`, {
...getIds(),
...data,
})
).data;
export const accessStrategyCreditBlacklistFind = async (params: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyCreditBlacklist/details`, {}, { params })).data;
export const accessStrategyCreditBlacklistSave = async (data: Record<string, any>): Promise<any> => export const accessStrategyCreditBlacklistSave = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyCreditBlacklist/saveOrUpdate`, data)).data; (await axios.post(`/product/accessStrategyCreditBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyCreditBlacklistDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/accessStrategyCreditBlacklist/delete`, data)).data;
export const accessStrategyInlineBlacklistFind = async (): Promise<any> => (await axios.post(`/product/accessStrategyInlineBlacklist/details`, getIds())).data; export const accessStrategyInlineBlacklist = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/accessStrategyInlineBlacklist/list`, {
...getIds(),
...data,
})
).data;
export const accessStrategyInlineBlacklistFind = async (params: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyInlineBlacklist/details`, {}, { params })).data;
export const accessStrategyInlineBlacklistSave = async (data: Record<string, any>): Promise<any> => export const accessStrategyInlineBlacklistSave = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyInlineBlacklist/saveOrUpdate`, data)).data; (await axios.post(`/product/accessStrategyInlineBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyInlineBlacklistDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/accessStrategyInlineBlacklist/delete`, data)).data;
export const accessStrategyNegativeIndustryStrategyFind = async (): Promise<any> => (await axios.post(`/product/accessStrategyNegativeIndustryStrategy/details`, getIds())).data; export const accessStrategyNegativeIndustryStrategy = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/accessStrategyNegativeIndustryStrategy/list`, {
...getIds(),
...data,
})
).data;
export const accessStrategyNegativeIndustryStrategyFind = async (params: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyNegativeIndustryStrategy/details`, {}, { params })).data;
export const accessStrategyNegativeIndustryStrategySave = async (data: Record<string, any>): Promise<any> => export const accessStrategyNegativeIndustryStrategySave = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyNegativeIndustryStrategy/saveOrUpdate`, data)).data; (await axios.post(`/product/accessStrategyNegativeIndustryStrategy/saveOrUpdate`, data)).data;
export const accessStrategyNegativeIndustryStrategyDel = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyNegativeIndustryStrategy/delete`, data)).data;
export const delCredit = async (id: number): Promise<any> => (await axios.post(`/product/creditScoringStrategy/delete?strategyId=${id}`)).data; export const delCredit = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/creditScoringStrategy/delete`, data)).data;
export const findCredit = async (id: number): Promise<any> => (await axios.post(`/product/creditScoringStrategy/details?strategyId=${id}`)).data; export const findCredit = async (id: number): Promise<any> => (await axios.post(`/product/creditScoringStrategy/details?strategyId=${id}`)).data;
export const listCredit = async (data: Record<string, any>): Promise<any> => export const listCredit = async (data: Record<string, any>): Promise<any> =>
( (
@ -51,31 +119,95 @@ export const detailRick = async (type: number): Promise<any> =>
).data; ).data;
export const saveRick = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/riskDegreeStrategy/saveOrUpdate`, data)).data; export const saveRick = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/riskDegreeStrategy/saveOrUpdate`, data)).data;
export const businessInterestRateDetails = async (): Promise<any> => (await axios.post(`/product/interestRateModel/businessInterestRateDetails`, getIds())).data; export const interestRateModelList = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/interestRateModel/list`, {
...getIds(),
...data,
})
).data;
export const businessInterestRateDetails = async (params: Record<string, any>): Promise<any> =>
(await axios.post(`/product/interestRateModel/businessInterestRateDetails`, {}, { params })).data;
export const businessInterestRateSaveOrUpdate = async (data: Record<string, any>): Promise<any> => export const businessInterestRateSaveOrUpdate = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/interestRateModel/businessInterestRateSaveOrUpdate`, data)).data; (await axios.post(`/product/interestRateModel/businessInterestRateSaveOrUpdate`, data)).data;
export const personalInterestRateDetails = async (): Promise<any> => (await axios.post(`/product/interestRateModel/personalInterestRateDetails`, getIds())).data; export const personalInterestRateDetails = async (params: Record<string, any>): Promise<any> =>
(await axios.post(`/product/interestRateModel/personalInterestRateDetails`, {}, { params })).data;
export const personalInterestRateSaveOrUpdate = async (data: Record<string, any>): Promise<any> => export const personalInterestRateSaveOrUpdate = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/interestRateModel/personalInterestRateSaveOrUpdate`, data)).data; (await axios.post(`/product/interestRateModel/personalInterestRateSaveOrUpdate`, data)).data;
export const deleteBusinessInterestRate = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/interestRateModel/deleteBusinessInterestRate`, data)).data;
export const deletePersonalInterestRate = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/interestRateModel/deletePersonalInterestRate`, data)).data;
export const quotaModelList = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/quotaModel/list`, {
...getIds(),
...data,
})
).data;
export const quotaModelDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/quotaModel/delete`, data)).data;
export const businessQuotaModelDetails = async (): Promise<any> => (await axios.post(`/product/quotaModel/businessQuotaModelDetails`, getIds())).data; export const businessQuotaModelDetails = async (): Promise<any> => (await axios.post(`/product/quotaModel/businessQuotaModelDetails`, getIds())).data;
export const businessQuotaModelSaveOrUpdate = async (data: Record<string, any>): Promise<any> => export const businessQuotaModelSaveOrUpdate = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/quotaModel/businessQuotaModelSaveOrUpdate`, data)).data; (await axios.post(`/product/quotaModel/businessQuotaModelSaveOrUpdate`, data)).data;
export const personalCreditModelDetails = async (): Promise<any> => (await axios.post(`/product/quotaModel/personalCreditModelDetails`, getIds())).data; export const personalCreditModelDetails = async (params: Record<string, any>): Promise<any> =>
(await axios.post(`/product/quotaModel/personalCreditModelDetails`, {}, { params })).data;
export const personalCreditModelSaveOrUpdate = async (data: Record<string, any>): Promise<any> => export const personalCreditModelSaveOrUpdate = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/quotaModel/personalCreditModelSaveOrUpdate`, data)).data; (await axios.post(`/product/quotaModel/personalCreditModelSaveOrUpdate`, data)).data;
export const fiveLevelClassificationDetails = async (): Promise<any> => (await axios.post(`/product/fiveLevelClassification/details`, getIds())).data; export const fiveLevelClassification = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/fiveLevelClassification/list`, {
...getIds(),
...data,
})
).data;
export const fiveLevelClassificationDetails = async (params: Record<string, any>): Promise<any> =>
(await axios.post(`/product/fiveLevelClassification/details`, {}, { params })).data;
export const fiveLevelClassificationSave = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/fiveLevelClassification/saveOrUpdate`, data)).data; export const fiveLevelClassificationSave = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/fiveLevelClassification/saveOrUpdate`, data)).data;
export const fiveLevelClassificationDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/fiveLevelClassification/delete`, data)).data;
export const postLoanInspectionDetails = async (): Promise<any> => (await axios.post(`/product/postLoanInspection/details`, getIds())).data; export const postLoanInspection = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/postLoanInspection/list`, {
...getIds(),
...data,
})
).data;
export const postLoanInspectionDetails = async (params: Record<string, any>): Promise<any> => (await axios.post(`/product/postLoanInspection/details`, {}, { params })).data;
export const postLoanInspectionSave = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postLoanInspection/saveOrUpdate`, data)).data; export const postLoanInspectionSave = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postLoanInspection/saveOrUpdate`, data)).data;
export const postLoanInspectionDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postLoanInspection/delete`, data)).data;
export const postCreditScoreDetails = async (): Promise<any> => (await axios.post(`/product/postCreditScore/details`, getIds())).data; export const postCreditScore = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/postCreditScore/list`, {
...getIds(),
...data,
})
).data;
export const postCreditScoreDetails = async (params: Record<string, any>): Promise<any> => (await axios.post(`/product/postCreditScore/details`, {}, { params })).data;
export const postCreditScoreSave = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postCreditScore/saveOrUpdate`, data)).data; export const postCreditScoreSave = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postCreditScore/saveOrUpdate`, data)).data;
export const postCreditScoreDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postCreditScore/delete`, data)).data;
export const postLoanWarningDetails = async (): Promise<any> => (await axios.post(`/product/postLoanWarning/details`, getIds())).data; export const postLoanWarning = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/postLoanWarning/list`, {
...getIds(),
...data,
})
).data;
export const postLoanWarningDetails = async (params: Record<string, any>): Promise<any> => (await axios.post(`/product/postLoanWarning/details`, {}, { params })).data;
export const postLoanWarningSave = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postLoanWarning/saveOrUpdate`, data)).data; export const postLoanWarningSave = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postLoanWarning/saveOrUpdate`, data)).data;
export const postLoanWarningDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postLoanWarning/delete`, data)).data;
export const collectionAfterLoanDetails = async (): Promise<any> => (await axios.post(`/product/collectionAfterLoan/details`, getIds())).data; export const collectionAfterLoan = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(`/product/collectionAfterLoan/list`, {
...getIds(),
...data,
})
).data;
export const collectionAfterLoanDetails = async (params: Record<string, any>): Promise<any> => (await axios.post(`/product/collectionAfterLoan/details`, {}, { params })).data;
export const collectionAfterLoanSave = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/collectionAfterLoan/saveOrUpdate`, data)).data; export const collectionAfterLoanSave = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/collectionAfterLoan/saveOrUpdate`, data)).data;
export const collectionAfterLoanDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/collectionAfterLoan/delete`, data)).data;
export const isTheStrategyRelatedToTheProduct = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/managerOfRiskControl/bankRiskControlAllocation/isTheStrategyRelatedToTheProduct`, data)).data;

@ -17,3 +17,4 @@ export const editExperimentalData = async (data: Record<string, any>): Promise<a
export const getStartTime = async (params: Record<string, any>): Promise<any> => (await axios.get('/python/python/getStartTime', { params })).data; export const getStartTime = async (params: Record<string, any>): Promise<any> => (await axios.get('/python/python/getStartTime', { params })).data;
export const getCurrentTime = async (): Promise<any> => (await axios.get('/competition/competition/management/getCurrentTime')).data; export const getCurrentTime = async (): Promise<any> => (await axios.get('/competition/competition/management/getCurrentTime')).data;
export const heartbeatDetection = async (): Promise<any> => (await axios.get('/nakadai/message/heartbeatDetection')).data; export const heartbeatDetection = async (): Promise<any> => (await axios.get('/nakadai/message/heartbeatDetection')).data;
export const initData = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/product/bank/operation/initData`, data)).data;

@ -1,31 +0,0 @@
import axios from '@/utils/request';
export const queryOrgList = async (params?: Record<string, any>): Promise<any> => (await axios.get('/backend/core/org', { params })).data;
export const queryOrg = async (id: number): Promise<any> => (await axios.get(`/backend/core/org/${id}`)).data;
export const createOrg = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/org', data)).data;
export const updateOrg = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/org?_method=put', data)).data;
export const updateOrgOrder = async (data: number[]): Promise<any> => (await axios.post('/backend/core/org/order?_method=put', data)).data;
export const deleteOrg = async (data: number[]): Promise<any> => (await axios.post('/backend/core/org?_method=delete', data)).data;
export const queryRoleList = async (params?: Record<string, any>): Promise<any> => (await axios.get('/backend/core/role', { params })).data;
export const queryRole = async (id: number): Promise<any> => (await axios.get(`/backend/core/role/${id}`)).data;
export const createRole = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/role', data)).data;
export const updateRole = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/role?_method=put', data)).data;
export const updateRoleOrder = async (data: number[]): Promise<any> => (await axios.post('/backend/core/role/order?_method=put', data)).data;
export const deleteRole = async (data: number[]): Promise<any> => (await axios.post('/backend/core/role?_method=delete', data)).data;
export const queryGroupList = async (params?: Record<string, any>): Promise<any> => (await axios.get('/backend/core/group', { params })).data;
export const queryGroup = async (id: number): Promise<any> => (await axios.get(`/backend/core/group/${id}`)).data;
export const createGroup = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/group', data)).data;
export const updateGroup = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/group?_method=put', data)).data;
export const updateGroupOrder = async (data: number[]): Promise<any> => (await axios.post('/backend/core/group/order?_method=put', data)).data;
export const deleteGroup = async (data: number[]): Promise<any> => (await axios.post('/backend/core/group?_method=delete', data)).data;
export const queryUserPage = async (params?: Record<string, any>): Promise<any> => (await axios.get('/backend/core/user', { params })).data;
export const queryUser = async (id: number): Promise<any> => (await axios.get(`/backend/core/user/${id}`)).data;
export const createUser = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/user', data)).data;
export const updateUser = async (data: Record<string, any>): Promise<any> => (await axios.post('/backend/core/user?_method=put', data)).data;
export const deleteUser = async (data: number[]): Promise<any> => (await axios.post('/backend/core/user?_method=delete', data)).data;
export const usernameValidation = async (username?: string): Promise<any> => (await axios.get('/backend/core/user/username-validation', { params: { username } })).data;
export const emailValidation = async (email?: string): Promise<any> => (await axios.get('/backend/core/user/email-validation', { params: { email } })).data;
export const mobileValidation = async (mobile?: string): Promise<any> => (await axios.get('/backend/core/user/mobile-validation', { params: { mobile } })).data;

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1713852488689" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2030" width="20" height="20" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M900.896 240.832c-21.344-29.024-51.04-63.04-83.584-95.552s-66.528-62.304-95.552-83.552c-49.44-36.256-73.376-40.384-87.136-40.384l-475.296 0c-42.336 0-76.704 34.336-76.704 76.672l0 827.968c0 42.336 34.368 76.704 76.704 76.704l705.248 0c42.208 0 76.768-34.336 76.768-76.704l0-597.952c-0.032-13.792-4.256-37.792-40.48-87.168l0 0 0 0zM773.856 188.672c29.504 29.472 52.544 55.968 69.568 77.984l-147.552 0 0-147.552c22.016 17.056 48.544 40.16 77.984 69.536l0 0 0 0 0 0zM880.032 925.952c0 8.384-7.008 15.392-15.392 15.392l-705.248 0c-8.384 0-15.392-7.008-15.392-15.392l0-827.936c0-8.288 7.008-15.328 15.392-15.328l475.296 0 0 214.688c0 16.864 13.728 30.688 30.688 30.688l214.688 0 0.032 597.92zM779.872 823.296l-172.928-172.96c29.024-36.384 46.432-82.464 46.432-132.704 0-117.6-95.328-212.896-212.896-212.896-117.632 0-212.896 95.296-212.896 212.896s95.328 212.896 212.896 212.896c46.304 0 83.744-9.344 118.688-34.496l173.984 173.984c6.56 6.56 17.088 6.56 23.584 0l23.136-23.072c6.432-6.528 6.432-17.12 0-23.648l0 0 0 0zM440.448 656.832c-76.896 0-139.232-62.336-139.232-139.232s62.336-139.232 139.232-139.232 139.232 62.336 139.232 139.232-62.304 139.232-139.232 139.232l0 0 0 0z" fill="#006bff" p-id="2031"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -17,7 +17,7 @@ export default {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
try { try {
// 上传到阿里云oss // 上传到阿里云oss
const res = await client.multipartUpload(Date.now() + '.' + getFileExt(file.name), file); const res = await client.multipartUpload(`${Date.now()}.${getFileExt(file.name)}`, file);
resolve({ resolve({
format: getFileExt(file.name), format: getFileExt(file.name),
name: file.name, name: file.name,

@ -1,10 +1,7 @@
<template> <template>
<div class="flex items-center p-3 mb-5 bg-white rounded-[10px]"> <div class="flex items-center p-3 mb-5 bg-white rounded-[10px]">
<div class="inline-flex items-center cursor-pointer" <div class="inline-flex items-center cursor-pointer" @click="back">
@click="back"> <img src="@/assets/images/back.png" alt="" class="" />
<img src="@/assets/images/back.png"
alt=""
class="" />
<span class="ml-[6px] text-sm text-[#3C65FF]">返回</span> <span class="ml-[6px] text-sm text-[#3C65FF]">返回</span>
</div> </div>
<span class="mx-5 text-sm text-[#999]">|</span> <span class="mx-5 text-sm text-[#999]">|</span>
@ -12,8 +9,7 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref } from 'vue'; import { useRouter } from 'vue-router';
import { useRouter, useRoute } from 'vue-router';
import { logout } from '@/store/useCurrentUser'; import { logout } from '@/store/useCurrentUser';
const props = defineProps({ const props = defineProps({

@ -1,83 +1,48 @@
<template> <template>
<div v-if="!hidePanel" <div v-if="!hidePanel" :class="['panel', { active: visible }]" id="panel" ref="container" :style="style" v-loading="loading">
:class="['panel', { active: visible }]" <el-container class="scrollbar" id="container" v-show="visible">
id="panel" <el-header class="panel-header" id="panelHeader">
ref="container" <div class="project">
:style="style"> <div class="inline-flex items-center">
<el-container class="scrollbar" <p class="whitespace-nowrap">实训项目</p>
id="container" <el-tooltip effect="dark" content="点击右侧“下三角”按钮可切换实验项目" placement="bottom">
v-show="visible"> <i class="info el-icon-warning" style="margin-left: 10px"></i>
<el-header id="header"> </el-tooltip>
<div class="panel-header"
id="panelHeader">
<div class="project">
<div class="inline-flex items-center">
<p>实训项目</p>
<el-tooltip effect="dark"
content="点击右侧“下三角”按钮可切换实验项目"
placement="bottom">
<i class="info el-icon-warning"
style="margin-left: 10px"></i>
</el-tooltip>
</div>
<el-select v-model="param.projectId"
placeholder="请选择"
class="select"
:disabled="per != 0"
@change="getCache(1)">
<el-option v-for="(item, i) in projectList"
:key="item.projectId"
:label="i + 1 + '. ' + item.projectName"
:value="item.projectId"></el-option>
</el-select>
</div>
<div class="item">
<div class="count">
实训{{ text }}时间 <span>{{ day }}</span> <span>{{ hour }}</span>小时 <span>{{ minutes }}</span> <span>{{ seconds }}</span>
</div>
</div>
<div class="item">
<div>
总得分
<span class="total-score">{{ grade }}</span>
</div>
</div> </div>
<div> <el-select v-model="param.projectId" placeholder="请选择" class="select" :disabled="per != 0" @change="getCache(1)">
<el-button class="h-[40px]" <el-option v-for="(item, i) in projectList" :key="item.projectId" :label="i + 1 + '. ' + item.projectName" :value="item.projectId"></el-option>
@click="toReport" </el-select>
v-if="isSubmit">查看实验报告</el-button> </div>
<el-button class="reload h-[40px]" <div class="item">
@click="reload(1)" <div class="count">
v-show="per == 0">重新开始</el-button> 实训{{ text }}时间 <span>{{ day }}</span
<el-button type="primary" > <span>{{ hour }}</span
class="submit btn h-[40px]" >小时 <span>{{ minutes }}</span
:loading="submiting" > <span>{{ seconds }}</span
@click="confirmSubmit" >
:disabled="isSubmit || !projectList.length">提交</el-button>
</div> </div>
</div> </div>
<div v-if="per !== 2" class="item">
总得分
<span class="total-score">{{ grade }}</span>
</div>
<div class="actions">
<el-button class="h-[40px]" @click="toReport" v-if="isSubmit">查看实验报告</el-button>
<el-button class="reload h-[40px]" @click="reloadConfirm" v-show="per == 0">重新开始</el-button>
<el-button type="primary" class="submit btn h-[40px]" :loading="submiting" @click="confirmSubmit" :disabled="isSubmit || !projectList.length">提交</el-button>
</div>
</el-header> </el-header>
<el-container id="infoContainer"> <el-container id="infoContainer">
<el-aside id="aside" <el-aside id="aside" width="30%">
width="30%">
<div class="aside-header"> <div class="aside-header">
<div class="p-title"> <div class="p-title">
<i class="el-icon-s-order"></i> <i class="el-icon-s-order"></i>
<p>实验目标</p> <p>实验目标</p>
</div> </div>
<div class="goal"> <div class="goal">
<div v-if="pd.experimentTargetType == 0 || !pd.experimentTargetType" <div v-if="pd.experimentTargetType == 0 || !pd.experimentTargetType" class="ql-editor" v-html="pd.experimentTarget"></div>
class="ql-editor"
v-html="pd.experimentTarget"></div>
<mavon-editor v-else <mavon-editor v-else class="md" v-model="pd.experimentTarget" :ishljs="true" :subfield="false" :editable="false" :toolbarsFlag="false" :boxShadowStyle="none" />
class="md"
v-model="pd.experimentTarget"
:ishljs="true"
:subfield="false"
:editable="false"
:toolbarsFlag="false"
:boxShadowStyle="none" />
</div> </div>
</div> </div>
<div class="aside-footer"> <div class="aside-footer">
@ -88,35 +53,20 @@
<div> <div>
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<el-card shadow="never" <el-card shadow="never" :border="false">
:border="false"> <el-table class="task-table" :data="taskList" :stripe="true">
<el-table class="task-table"
:data="taskList"
:stripe="true">
<el-table-column type="index"></el-table-column> <el-table-column type="index"></el-table-column>
<el-table-column prop="name" <el-table-column prop="name" label="判分点" align="center"></el-table-column>
label="判分点" <el-table-column prop="score" label="分值" width="60" align="center"></el-table-column>
align="center"></el-table-column>
<el-table-column prop="score"
label="分值"
width="60"
align="center"></el-table-column>
<template v-if="!param.competitionId"> <template v-if="!param.competitionId">
<el-table-column label="结果" <el-table-column label="结果" width="60" align="center">
width="60" <template #default="{ row }">
align="center">
<template v-slot="scope">
<template v-if="isSubmit"> <template v-if="isSubmit">
<div v-if="!param.competitionId" <div v-if="!param.competitionId" class="flex justify-center items-center">
class="flex justify-center items-center"> <el-icon v-if="row.finishedResult" color="#15d500" :size="16">
<el-icon v-if="scope.row.finishedResult"
color="#15d500"
:size="16">
<Check /> <Check />
</el-icon> </el-icon>
<el-icon v-else <el-icon v-else color="#f00" :size="16">
color="#f00"
:size="16">
<Close /> <Close />
</el-icon> </el-icon>
</div> </div>
@ -124,12 +74,9 @@
</template> </template>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="score" <el-table-column label="得分" width="60" align="center">
label="得分" <template #default="{ row }">
width="60" <template v-if="isSubmit">{{ param.competitionId ? '-' : row.examScore }}</template>
align="center">
<template v-slot="scope">
<template v-if="isSubmit">{{ param.competitionId ? '-' : scope.row.examScore }}</template>
</template> </template>
</el-table-column> </el-table-column>
</template> </template>
@ -141,65 +88,38 @@
</div> </div>
</el-aside> </el-aside>
<el-main id="main"> <el-main id="main">
<el-tabs class="info-tab" <el-tabs class="info-tab" v-model="pannelTab" type="card">
v-model="pannelTab" <el-tab-pane label="项目背景" name="first">
type="card"> <div v-if="pd.experimentDescriptionType == 0 || !pd.experimentDescriptionType" class="ql-editor" v-html="pd.experimentDescription"></div>
<el-tab-pane label="项目背景"
name="first">
<div v-if="pd.experimentDescriptionType == 0 || !pd.experimentDescriptionType"
class="ql-editor"
v-html="pd.experimentDescription"></div>
<mavon-editor v-else <mavon-editor v-else class="md" v-model="pd.experimentDescription" :ishljs="true" :subfield="false" :editable="false" :toolbarsFlag="false" :boxShadowStyle="none" />
class="md"
v-model="pd.experimentDescription"
:ishljs="true"
:subfield="false"
:editable="false"
:toolbarsFlag="false"
:boxShadowStyle="none" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="实验要求" <el-tab-pane label="实验要求" name="second">
name="second">
<el-collapse v-model="curReq"> <el-collapse v-model="curReq">
<el-collapse-item v-for="item in points" <el-collapse-item v-for="item in points" :name="item.judgmentId" :key="item.judgmentId">
:name="item.judgmentId"
:key="item.judgmentId">
<template v-slot:title> <template v-slot:title>
<i class="el-icon-s-ticket"></i> <i class="el-icon-s-ticket"></i>
<div class="break-all des" <div class="break-all des" v-html="item.name"></div>
v-html="item.name"></div>
</template> </template>
<div v-if="item.experimentalRequirementsType == 0 || !item.experimentalRequirementsType" <div v-if="item.experimentalRequirementsType == 0 || !item.experimentalRequirementsType" class="ql-editor" v-html="item.experimentalRequirements"></div>
class="ql-editor"
v-html="item.experimentalRequirements"></div>
<mavon-editor v-else <mavon-editor
class="md" v-else
v-model="item.experimentalRequirements" class="md"
:ishljs="true" v-model="item.experimentalRequirements"
:subfield="false" :ishljs="true"
:editable="false" :subfield="false"
:toolbarsFlag="false" :editable="false"
:boxShadowStyle="none" /> :toolbarsFlag="false"
:boxShadowStyle="none"
/>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="实验提示" <el-tab-pane label="实验提示" name="third" v-if="hintOpen">
name="third" <div v-if="pd.experimentHintType == 0 || !pd.experimentHintType" class="ql-editor" v-html="pd.experimentHint"></div>
v-if="hintOpen">
<div v-if="pd.experimentHintType == 0 || !pd.experimentHintType"
class="ql-editor"
v-html="pd.experimentHint"></div>
<mavon-editor v-else <mavon-editor v-else class="md" v-model="pd.experimentHint" :ishljs="true" :subfield="false" :editable="false" :toolbarsFlag="false" :boxShadowStyle="none" />
class="md"
v-model="pd.experimentHint"
:ishljs="true"
:subfield="false"
:editable="false"
:toolbarsFlag="false"
:boxShadowStyle="none" />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</el-main> </el-main>
@ -207,25 +127,19 @@
</el-container> </el-container>
<div :class="['toggle absolute top-[200px] text-center', visible ? 'top-[35%] left-[100%]' : '']"> <div :class="['toggle absolute top-[200px] text-center', visible ? 'top-[35%] left-[100%]' : '']">
<el-icon class="cursor-pointer" <el-icon class="cursor-pointer" color="#f1772b" :size="24">
color="#f1772b"
:size="24">
<Rank id="toggle" /> <Rank id="toggle" />
</el-icon> </el-icon>
<div class="toggle-panel w-[40px] h-[175px] bg-[length:100%_100%] bg-no-repeat cursor-pointer" <div class="toggle-panel w-[40px] h-[175px] bg-[length:100%_100%] bg-no-repeat cursor-pointer" :class="{ active: visible }" ref="handle" @click="pannelToggle"></div>
:class="{ active: visible }"
ref="handle"
@click="visible = !visible"></div>
</div> </div>
</div> </div>
<div v-if="isSubmit && !isReport" <div v-if="isSubmit && !isReport" class="z-[199] fixed top-[64px] right-0 bottom-0 left-0 bg-[rgba(0,0,0,.3)]"></div>
class="z-[199] fixed top-[64px] right-0 bottom-0 left-0 bg-[rgba(0,0,0,.3)]"></div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted, inject, computed, watch, onUnmounted } from 'vue'; import { ref, reactive, onMounted, inject, computed, watch, onUnmounted } from 'vue';
import { submitOpe } from '@/api/bank'; import { submitOpe } from '@/api/bank';
import { getSandTableLastCache, deleteOperationData } from '@/api/judgment'; import { getSandTableLastCache, deleteOperationData } from '@/api/judgment';
import { getProjectBySystemId, getProjectDetail, getDetailById, getCompetition, getStartTime, heartbeatDetection } from '@/api/system'; import { getProjectBySystemId, getProjectDetail, getDetailById, getCompetition, getStartTime, heartbeatDetection, initData } from '@/api/system';
import Settings from '@/settings'; import Settings from '@/settings';
import { useRouter, useRoute, beforeRouteLeave } from 'vue-router'; import { useRouter, useRoute, beforeRouteLeave } from 'vue-router';
import type { Action } from 'element-plus'; import type { Action } from 'element-plus';
@ -236,9 +150,9 @@ import Cookies from 'js-cookie';
import { mavonEditor } from 'mavon-editor'; import { mavonEditor } from 'mavon-editor';
import 'mavon-editor/dist/css/index.css'; import 'mavon-editor/dist/css/index.css';
import '@vueup/vue-quill/dist/vue-quill.snow.css'; import '@vueup/vue-quill/dist/vue-quill.snow.css';
import { useDraggable } from '@vueuse/core'; import { useDraggable, useWindowSize, Position } from '@vueuse/core';
import { logout } from '@/store/useCurrentUser'; import { logout } from '@/store/useCurrentUser';
import { getIds, getNow } from '@/utils/common'; import { getNow } from '@/utils/common';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
@ -266,20 +180,23 @@ const judgmentId = ref<string | number>('');
const curReq = ref<Record<string, any>[]>([]); const curReq = ref<Record<string, any>[]>([]);
const taskList = ref<Record<string, any>[]>([]); const taskList = ref<Record<string, any>[]>([]);
const pannelTab = ref<string>('first'); const pannelTab = ref<string>('first');
const loading = ref<boolean>(false);
const submiting = ref<boolean>(false); const submiting = ref<boolean>(false);
const reportId = ref<string | number>(''); const reportId = ref<string | number>('');
const countVal = ref<any>(''); const countVal = ref<any>('');
const getLevel = ref(); const getLevel = ref();
const container = ref<HTMLElement | null>(null); const container = ref<HTMLElement | null>(null);
const handle = ref<HTMLElement | null>(null); const handle = ref<HTMLElement | null>(null);
const { width, height } = useWindowSize();
// //
const { x, y, style } = useDraggable(container, { const { x, y, style } = useDraggable(container, {
initialValue: { x: 0, y: 200 }, initialValue: { x: 0, y: 200 },
stopPropagation: true, stopPropagation: true,
handle: handle.value, handle: handle.value,
onStart(position, e) { onStart: (p: Position, e: PointerEvent): boolean => {
const { id } = e.target; const { id } = e.target;
if (id !== 'panelHeader' && id !== 'toggle') return false; if (id !== 'panelHeader' && id !== 'toggle') return false;
return true;
}, },
}); });
@ -494,8 +411,18 @@ let setNewProject = (reloadPage?: number) => {
} }
} }
}; };
//
const initBuiltInData = async () => {
await initData({
assessmentId: param.assessmentId,
cid: param.cid,
competitionId: param.competitionId,
projectId: param.projectId,
});
};
// //
let getCache = async (reloadPage?: number) => { let getCache = async (reloadPage?: number) => {
initBuiltInData();
// //
const res = await getSandTableLastCache({ const res = await getSandTableLastCache({
cid: param.cid, cid: param.cid,
@ -535,7 +462,7 @@ let getCache = async (reloadPage?: number) => {
}); });
} else { } else {
Cookies.remove('sand-level'); Cookies.remove('sand-level');
setNewProject(); setNewProject(reloadPage);
} }
}; };
let handleCache = () => { let handleCache = () => {
@ -547,15 +474,10 @@ let handleCache = () => {
}; };
// //
const toReport = () => { const toReport = () => {
router.push('/report'); router.replace('/report');
}; };
// //
let reload = async (fromReload?: number) => { let reload = async () => {
if (fromReload) {
getEntryTime(1);
await delCache(); //
Cookies.remove('sand-level');
}
if (!per.value) { if (!per.value) {
reloadCount(); reloadCount();
startCount(); startCount();
@ -565,6 +487,34 @@ let reload = async (fromReload?: number) => {
router.push('/'); router.push('/');
} }
}; };
//
let reloadConfirm = async () => {
if (isSubmit.value) {
reload();
} else {
ElMessageBox.confirm('<p class="text-danger">点击重新开始,之前操作会清空。</p><p>确定重新开始吗?</p>', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
dangerouslyUseHTMLString: true,
})
.then(() => {
getEntryTime(1);
delCache().then(); //
Cookies.remove('sand-level');
reload();
})
.catch(() => {
submiting.value = false;
});
}
};
let pannelToggle = () => {
visible.value = !visible.value;
x.value = 0;
y.value = 200;
};
// //
let submit = async () => { let submit = async () => {
if (!submiting.value) { if (!submiting.value) {
@ -610,7 +560,7 @@ let submit = async () => {
} catch (e) {} } catch (e) {}
}); });
const score = retMap.totalScore; const score = retMap.totalScore;
grade.value = score < 10 && !(score % 1) ? '0' + score : score; grade.value = score < 10 && !(score % 1) ? `0${score}` : score;
reportId.value = retMap.reportId; reportId.value = retMap.reportId;
Cookies.set('sand-reportId', retMap.reportId); Cookies.set('sand-reportId', retMap.reportId);
Cookies.set('sand-score', grade.value); Cookies.set('sand-score', grade.value);
@ -655,38 +605,42 @@ let confirmSubmit = () => {
// //
let getProDetail = async () => { let getProDetail = async () => {
const res = await getProjectDetail({ loading.value = true;
projectId: param.projectId, try {
stuAssessent: 1, const res = await getProjectDetail({
}); projectId: param.projectId,
const pointsList = res.projectJudgmentVos; stuAssessent: 1,
const project = res.projectManage; });
Cookies.set('sand-projectId', param.projectId); const pointsList = res.projectJudgmentVos;
// / const project = res.projectManage;
if (per.value) { Cookies.set('sand-projectId', param.projectId);
projectList.value = [ // /
{ if (per.value) {
projectId: param.projectId, projectList.value = [
projectName: project.projectName, {
}, projectId: param.projectId,
]; projectName: project.projectName,
// Cookies.set('sand-projectName', project.projectName); },
} ];
curReq.value = pointsList.map((e) => e.judgmentId); // judgmentIditem }
points.value = pointsList; curReq.value = pointsList.map((e) => e.judgmentId); // judgmentIditem
taskList.value = isSubmit.value ? JSON.parse(localStorage.getItem('sand-taskList')) : pointsList; // points.value = pointsList;
grade.value = isSubmit.value ? Cookies.get('sand-score') : '00'; taskList.value = isSubmit.value ? JSON.parse(localStorage.getItem('sand-taskList')) : pointsList; //
judgmentId.value = pointsList[0].judgmentId; // grade.value = isSubmit.value ? Cookies.get('sand-score') : '00';
pd.value = project; judgmentId.value = pointsList[0].judgmentId; //
curSystemId.value = project.systemId; pd.value = project;
hintOpen.value = project.founder ? !project.hintOpenBySchool : !project.hintOpen; // 01 curSystemId.value = project.systemId;
const isPrac = per.value === 0; // hintOpen.value = project.founder ? !project.hintOpenBySchool : !project.hintOpen; // 01
text.value = isPrac ? '已用' : '剩余'; const isPrac = per.value === 0; //
// text.value = isPrac ? '已用' : '剩余';
if (!param.competitionId && !isSubmit.value) { //
const now = await getNow(); if (!param.competitionId && !isSubmit.value) {
countVal.value = (isPrac ? now - entryTime.value : new Date(param.stopTime).getTime() - now) / 1000; // const now = await getNow();
startCount(); countVal.value = (isPrac ? now - entryTime.value : new Date(param.stopTime).getTime() - now) / 1000; //
startCount();
}
} finally {
loading.value = false;
} }
}; };
@ -781,6 +735,7 @@ onMounted(init);
onUnmounted(() => { onUnmounted(() => {
counter = null; counter = null;
submit = null; submit = null;
pannelToggle = null;
setHeartbeatDetection = null; setHeartbeatDetection = null;
getProDetail = null; getProDetail = null;
getCache = null; getCache = null;
@ -795,30 +750,25 @@ onUnmounted(() => {
delCache = null; delCache = null;
setNewProject = null; setNewProject = null;
reload = null; reload = null;
reloadConfirm = null;
startCount = null; startCount = null;
setSubmit = null; setSubmit = null;
clearInterval(counterTimer.value); clearInterval(counterTimer.value);
clearInterval(heartBeatTimer.value); clearInterval(heartBeatTimer.value);
console.log('onUnmounted'); console.log('onUnmounted');
// next();
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.el-main { .el-main {
width: 60%; @apply w-[60%] p-0 mr-5 mb-2 ml-2 text-[#333] text-base whitespace-pre-wrap bg-white overflow-hidden;
background-color: #fff;
color: #333;
padding: 0;
font-size: 16px;
margin: 0px 20px 10px 10px;
white-space: pre-wrap;
overflow: hidden;
} }
.panel-header { .panel-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
flex-wrap: wrap;
height: auto !important;
.project { .project {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@ -959,7 +909,7 @@ onUnmounted(() => {
font-size: 14px; font-size: 14px;
} }
:deep(.select) { :deep(.select) {
@apply flex-1; @apply flex-1 min-w-[180px];
.el-select__caret:before { .el-select__caret:before {
// content: '\e78f'; // content: '\e78f';
padding: 3px; padding: 3px;
@ -974,7 +924,7 @@ onUnmounted(() => {
.el-input { .el-input {
padding: 10px 0; padding: 10px 0;
} }
.el-input--suffix .el-input__inner { .el-input--suffix .el-input__wrapper {
height: 40px !important; height: 40px !important;
padding-right: 50px; padding-right: 50px;
margin-left: 15px; margin-left: 15px;
@ -986,6 +936,7 @@ onUnmounted(() => {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
box-shadow: none;
} }
} }
.panel { .panel {
@ -1032,4 +983,14 @@ onUnmounted(() => {
.ql-editor { .ql-editor {
@apply text-sm; @apply text-sm;
} }
@media (max-width: 1450px) {
.panel-header {
.actions {
z-index: 10;
position: absolute;
top: 70px;
right: 30px;
}
}
}
</style> </style>

@ -1,12 +1,7 @@
<template> <template>
<div class="search"> <div class="search">
<input type="text" <input type="text" placeholder="搜索" maxlength="20" v-model="val" />
placeholder="搜索" <img src="@/assets/images/search.png" alt="" class="icon" />
maxlength="20"
v-model="val" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
</div> </div>
</template> </template>

@ -0,0 +1,34 @@
<template>
<!-- 保存策略时的confirm询问 -->
<el-dialog v-model="visible" width="500px">
<p>修改后的策略同步已关联这条策略的贷款产品会导致关联产品下架并重新配置风控</p>
<p class="my-3 text-[#006BFF]">确定修改这条策略吗</p>
<el-checkbox v-model="syncCheck" label="策略修改同步之前关联的产品" />
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="submit">确定</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
const props = defineProps({
modelValue: { type: Boolean, default: false },
});
const emit = defineEmits(['update:modelValue', 'submit']);
const visible = computed({
get: () => props.modelValue,
set: (value) => {
emit('update:modelValue', value);
},
});
const syncCheck = ref<boolean>(false);
const submit = () => {
visible.value = false;
emit('submit', +syncCheck.value);
};
</script>

@ -1,7 +1,6 @@
<template> <template>
<div> <div>
<textarea :id="elementId" <textarea :id="elementId" ref="element"></textarea>
ref="element"></textarea>
</div> </div>
</template> </template>
@ -55,8 +54,8 @@ import 'tinymce/plugins/visualblocks';
import 'tinymce/plugins/visualchars'; import 'tinymce/plugins/visualchars';
// import 'tinymce/plugins/wordcount'; // import 'tinymce/plugins/wordcount';
import { isTextarea, uuid, initEditor } from './utils';
import Oss from '@/components/AliOss/upload.ts'; import Oss from '@/components/AliOss/upload.ts';
import { isTextarea, uuid, initEditor } from './utils';
export default defineComponent({ export default defineComponent({
name: 'Tinymce', name: 'Tinymce',

@ -1,23 +1,12 @@
<template> <template>
<div class="width-[100%] flex justify-between items-center w-full py-6 lg:py-4 px-5 overflow-hidden bg-transparent"> <div class="width-[100%] flex justify-between items-center w-full py-6 lg:py-4 px-5 overflow-hidden bg-transparent">
<logo /> <logo />
<div v-if="!hidePanel" <div v-if="!hidePanel" class="inline-flex items-center">
class="inline-flex items-center"> <el-tooltip effect="light" content="退出实训" placement="bottom">
<el-tooltip effect="light" <img class="mr-3 cursor-pointer" src="@/assets/images/11.png" alt="" @click="logout" />
content="退出实训"
placement="bottom">
<img class="mr-3 cursor-pointer"
src="@/assets/images/11.png"
alt=""
@click="logout" />
</el-tooltip> </el-tooltip>
<el-tooltip effect="light" <el-tooltip effect="light" content="返回选择角色" placement="bottom">
content="返回选择角色" <img class="cursor-pointer" src="@/assets/images/4.png" alt="" @click="toRole" />
placement="bottom">
<img class="cursor-pointer"
src="@/assets/images/4.png"
alt=""
@click="toRole" />
</el-tooltip> </el-tooltip>
</div> </div>
</div> </div>

@ -1,8 +1,7 @@
<template> <template>
<section class="px-3"> <section class="px-3">
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<transition name="fade-transform" <transition name="fade-transform" mode="out-in">
mode="out-in">
<component :is="Component" /> <component :is="Component" />
</transition> </transition>
</router-view> </router-view>

@ -2,124 +2,74 @@
<ul class="switch px-7 lg:px-2"> <ul class="switch px-7 lg:px-2">
<!-- 产品经理 --> <!-- 产品经理 -->
<template v-if="role == 41"> <template v-if="role == 41">
<el-badge :value="num1"> <el-badge :value="productState.stat1">
<li :class="{ active: active == 1 }" <li :class="{ active: active == 1 }" @click="toPage('/product/bank?type=0&i=1&role=41')">
@click="toPage('/product/bank?type=0&i=1&role=41')"> <img class="icon" src="@/assets/images/icon5.png" alt="" />
<img class="icon" <img class="icon-1" src="@/assets/images/icon5-1.png" alt="" />
src="@/assets/images/icon5.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon5-1.png"
alt="" />
<p class="text">个人产品</p> <p class="text">个人产品</p>
</li> </li>
</el-badge> </el-badge>
<el-badge :value="num2"> <el-badge :value="productState.stat2">
<li :class="{ active: active == 2 }" <li :class="{ active: active == 2 }" @click="toPage('/product/bank?type=1&i=2&role=41')">
@click="toPage('/product/bank?type=1&i=2&role=41')"> <img class="icon" src="@/assets/images/icon6.png" alt="" />
<img class="icon" <img class="icon-1" src="@/assets/images/icon6-1.png" alt="" />
src="@/assets/images/icon6.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon6-1.png"
alt="" />
<p class="text">企业产品</p> <p class="text">企业产品</p>
</li> </li>
</el-badge> </el-badge>
</template> </template>
<!-- 风控经理 --> <!-- 风控经理 -->
<template v-else-if="role == 42"> <template v-else-if="role == 42">
<el-badge :value="num1"> <el-badge :value="productState.stat1">
<li :class="{ active: active == 1 }" <li :class="{ active: active == 1 }" @click="toPage('/product/bank?type=&i=1&role=42')">
@click="toPage('/product/bank?type=&i=1&role=42')"> <img class="icon" src="@/assets/images/icon1.png" alt="" />
<img class="icon" <img class="icon-1" src="@/assets/images/icon1-1.png" alt="" />
src="@/assets/images/icon1.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon1-1.png"
alt="" />
<p class="text">产品风控配置</p> <p class="text">产品风控配置</p>
</li> </li>
</el-badge> </el-badge>
<li :class="{ active: active == 2 }" <li :class="{ active: active == 2 }" @click="toPage('/product/strategy?i=2&role=42&id=150')">
@click="toPage('/product/strategy?i=2&role=42&id=150')"> <img class="icon" src="@/assets/images/icon2.png" alt="" />
<img class="icon" <img class="icon-1" src="@/assets/images/icon2-1.png" alt="" />
src="@/assets/images/icon2.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon2-1.png"
alt="" />
<p class="text">贷前准入模型</p> <p class="text">贷前准入模型</p>
</li> </li>
<li :class="{ active: active == 3 }" <li :class="{ active: active == 3 }" @click="toPage('/product/interestRate?&i=3&role=42&id=772')">
@click="toPage('/product/interestRate/tab1?&i=3&role=42&id=772')"> <img class="icon" src="@/assets/images/icon3.png" alt="" />
<img class="icon" <img class="icon-1" src="@/assets/images/icon3-1.png" alt="" />
src="@/assets/images/icon3.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon3-1.png"
alt="" />
<p class="text">利率定价模型</p> <p class="text">利率定价模型</p>
</li> </li>
<li :class="{ active: active == 4 }" <li :class="{ active: active == 4 }" @click="toPage('/product/afterLoan?&i=4&role=42&id=1029')">
@click="toPage('/product/afterLoan?&i=4&role=42&id=1029')"> <img class="icon" src="@/assets/images/icon4.png" alt="" />
<img class="icon" <img class="icon-1" src="@/assets/images/icon4-1.png" alt="" />
src="@/assets/images/icon4.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon4-1.png"
alt="" />
<p class="text">贷后管理模型</p> <p class="text">贷后管理模型</p>
</li> </li>
</template> </template>
<!-- 专家委员会 --> <!-- 专家委员会 -->
<el-badge v-else-if="role == 43" <el-badge v-else-if="role == 43" :value="productState.stat1">
:value="num1">
<li class="active"> <li class="active">
<img class="icon-1" <img class="icon-1" src="@/assets/images/icon7-1.png" alt="" />
src="@/assets/images/icon7-1.png"
alt="" />
<p class="text">审批产品</p> <p class="text">审批产品</p>
</li> </li>
</el-badge> </el-badge>
<!-- 保险 --> <!-- 保险 -->
<li v-else-if="route.path.includes('insurance')" <li v-else-if="route.path.includes('insurance')" class="active">
class="active"> <img class="icon-1" src="@/assets/images/icon4-1.png" alt="" />
<img class="icon-1"
src="@/assets/images/icon4-1.png"
alt="" />
<p class="text">保险产品</p> <p class="text">保险产品</p>
</li> </li>
<!-- 基金 --> <!-- 基金 -->
<li v-else-if="route.path.includes('fund')" <li v-else-if="route.path.includes('fund')" class="active">
class="active"> <img class="icon-1" src="@/assets/images/icon3-1.png" alt="" />
<img class="icon-1"
src="@/assets/images/icon3-1.png"
alt="" />
<p class="text">基金产品</p> <p class="text">基金产品</p>
</li> </li>
<!-- 配置 --> <!-- 配置 -->
<template v-else> <template v-else>
<li :class="{ active: route.path === '/config/index' }" <li :class="{ active: route.path === '/config/index' }" @click="toPage('/config/index')">
@click="toPage('/config/index')"> <img class="icon" src="@/assets/images/icon4.png" alt="" />
<img class="icon" <img class="icon-1" src="@/assets/images/icon4-1.png" alt="" />
src="@/assets/images/icon4.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon4-1.png"
alt="" />
<p class="text">参数配置</p> <p class="text">参数配置</p>
</li> </li>
<!-- 中台进来的才需要显示关卡配置 --> <!-- 中台进来的才需要显示关卡配置 -->
<li v-if="isAdmin" <li v-if="isAdmin" :class="{ active: route.path === '/config/level' }" @click="toPage('/config/level')">
:class="{ active: route.path === '/config/level' }" <img class="icon" src="@/assets/images/icon1.png" alt="" />
@click="toPage('/config/level')"> <img class="icon-1" src="@/assets/images/icon1-1.png" alt="" />
<img class="icon"
src="@/assets/images/icon1.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon1-1.png"
alt="" />
<p class="text">关卡配置</p> <p class="text">关卡配置</p>
</li> </li>
</template> </template>
@ -130,42 +80,24 @@
import { onMounted, computed, ref } from 'vue'; import { onMounted, computed, ref } from 'vue';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { statistics } from '@/api/bank'; import { productState, getStat } from '@/store/useProduct';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const active = computed(() => route.query.i); const active = computed(() => route.query.i);
const role = computed(() => route.query.role); const role = computed(() => route.query.role);
const projectId = +Cookies.get('sand-projectId');
const levelId = +Cookies.get('sand-level');
const isAdmin = ref<number | string>(route.query.admin ?? Cookies.get('sand-admin')); // const isAdmin = ref<number | string>(route.query.admin ?? Cookies.get('sand-admin')); //
const num1 = ref<number | string>('');
const num2 = ref<number>(0);
// //
const toPage = (path: string) => { const toPage = (path: string) => {
router.push(path); router.push(path);
}; };
//
const getNum = async (status?: number, type?: number) => {
const { data } = await statistics({
checkpointId: levelId,
projectId,
status,
productType: type,
});
if (type === 1) {
// -
num2.value = data || '';
} else {
num1.value = data || '';
}
};
onMounted(() => { onMounted(() => {
const status = role.value === '41' ? 299 : role.value === '42' ? 295 : role.value === '43' ? 296 : ''; // (1- 2-3-4-5- const status = role.value === '41' ? 299 : role.value === '42' ? 295 : role.value === '43' ? 296 : ''; // (1- 2-3-4-5-
if (status) { if (status) {
getNum(status, role.value === '41' ? 0 : ''); getStat(status, role.value === '41' ? 0 : '');
role.value === '41' && getNum(status, 1); role.value === '41' && getStat(status, 1);
} }
}); });
</script> </script>

@ -1,11 +1,8 @@
<template> <template>
<div> <div>
<el-scrollbar wrap-style="height: calc(100% - 85px)"> <el-scrollbar wrap-style="height: calc(100% - 85px)">
<div v-if="!isConfig" <div v-if="!isConfig" class="avatar py-3 mx-auto mb-5 text-center">
class="avatar py-3 mx-auto mb-5 text-center"> <img class="mx-auto" src="@/assets/images/6.png" alt="" />
<img class="mx-auto"
src="@/assets/images/6.png"
alt="" />
<p class="text-white text-base lg:text-sm">{{ roleName }}</p> <p class="text-white text-base lg:text-sm">{{ roleName }}</p>
<p class="my-2 text-white text-sm lg:text-xs">产品部门</p> <p class="my-2 text-white text-sm lg:text-xs">产品部门</p>
<div class="flex justify-center items-center text-white text-xs lg:text-[10px]"> <div class="flex justify-center items-center text-white text-xs lg:text-[10px]">
@ -19,22 +16,14 @@
<menus></menus> <menus></menus>
</el-scrollbar> </el-scrollbar>
<el-dialog v-model="dateVisible" <el-dialog v-model="dateVisible" title="选择交易日期" width="400px" center>
title="选择交易日期"
width="400px"
center>
<div class="text-center"> <div class="text-center">
<el-date-picker v-model="diaDate" <el-date-picker v-model="diaDate" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" />
format="YYYY/MM/DD"
value-format="YYYY-MM-DD"
type="date" />
</div> </div>
<template #footer> <template #footer>
<span class="flex justify-center"> <span class="flex justify-center">
<div class="dia-btn mr-3 cancel" <div class="dia-btn cancel" @click="dateVisible = false">取消</div>
@click="dateVisible = false">取消</div> <div class="dia-btn" @click="submitDate">确定</div>
<div class="dia-btn"
@click="submitDate">确定</div>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -44,11 +33,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, computed } from 'vue'; import { onMounted, ref, computed } from 'vue';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import Menus from './Menu.vue';
import { getOperationTime, saveOperationTime } from '@/api/config'; import { getOperationTime, saveOperationTime } from '@/api/config';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { getNow } from '@/utils/common'; import { getNow } from '@/utils/common';
import Menus from './Menu.vue';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
@ -67,9 +56,11 @@ const roleIds = {
const roleName = computed(() => { const roleName = computed(() => {
if (route.query.role) { if (route.query.role) {
return roleIds[+route.query.role]; return roleIds[+route.query.role];
} else if (route.path.includes('insurance')) { }
if (route.path.includes('insurance')) {
return '保险产品经理'; return '保险产品经理';
} else if (route.path.includes('fund')) { }
if (route.path.includes('fund')) {
return '基金产品经理'; return '基金产品经理';
} }
}); });

@ -1,7 +1,6 @@
<template> <template>
<div class="flex items-center justify-center overflow-hidden"> <div class="flex items-center justify-center overflow-hidden">
<router-link class="whitespace-nowrap text-center" <router-link class="whitespace-nowrap text-center" to="/">
to="/">
<h1 class="ml-1 text-[22px] lg:text-lg leading-[1] font-bold text-[#333]">{{ title }}</h1> <h1 class="ml-1 text-[22px] lg:text-lg leading-[1] font-bold text-[#333]">{{ title }}</h1>
</router-link> </router-link>
</div> </div>

@ -1,15 +1,9 @@
<template> <template>
<div class="min-h-full bg-[url('@/assets/images/1.png')] bg-[length:100%_100%] bg-no-repeat"> <div class="min-h-full bg-[url('@/assets/images/1.png')] bg-[length:100%_100%] bg-no-repeat">
<app-header /> <app-header />
<Back v-if="hidePanel" <Back v-if="hidePanel" class="mx-3" name="金融产品设计及数字化营销沙盘系统后台管理系统" :isLogout="true" />
class="mx-3" <app-sidebar v-if="!hideNav" class="sidebar fixed h-full px-5 overflow-hidden transition-width duration-300" />
name="金融产品设计及数字化营销沙盘系统后台管理系统" <div class="main h-[calc(100vh-86px)] transition-margin duration-300 overflow-auto" :class="{ ml: !hideNav }" id="appMain">
:isLogout="true" />
<app-sidebar v-if="!hideNav"
class="sidebar fixed h-full px-5 overflow-hidden transition-width duration-300 z-40" />
<div class="main h-[calc(100vh-86px)] transition-margin duration-300 overflow-auto"
:class="{ 'ml': !hideNav }"
id="appMain">
<app-main /> <app-main />
</div> </div>
<Panel /> <Panel />
@ -20,10 +14,10 @@
import { defineComponent, computed } from 'vue'; import { defineComponent, computed } from 'vue';
import { useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import Settings from '@/settings'; import Settings from '@/settings';
import { AppSidebar, AppHeader, AppMain } from './components';
import useResizeHandler from './composables/useResizeHandler';
import Panel from '@/components/Panel/index.vue'; import Panel from '@/components/Panel/index.vue';
import Back from '@/components/Back.vue'; import Back from '@/components/Back.vue';
import { AppSidebar, AppHeader, AppMain } from './components';
import useResizeHandler from './composables/useResizeHandler';
export default defineComponent({ export default defineComponent({
name: 'Layout', name: 'Layout',

@ -2,12 +2,11 @@ import NProgress from 'nprogress'; // progress bar
import 'nprogress/nprogress.css'; // progress bar style import 'nprogress/nprogress.css'; // progress bar style
import { RouteLocationNormalized } from 'vue-router'; import { RouteLocationNormalized } from 'vue-router';
import getPageTitle from '@/utils/getPageTitle'; import getPageTitle from '@/utils/getPageTitle';
import { getAccessToken } from '@/utils/auth'; // get token from cookie
import router from './router'; import router from './router';
NProgress.configure({ showSpinner: false }); // NProgress Configuration NProgress.configure({ showSpinner: false }); // NProgress Configuration
router.beforeEach(async (to: RouteLocationNormalized) => { router.beforeEach(async () => {
NProgress.start(); NProgress.start();
return true; return true;
}); });

@ -37,7 +37,7 @@ export const routes: Array<RouteRecordRaw> = [
{ path: 'strategy', component: () => import('@/views/product/strategy/CardList.vue'), meta: { title: '产品列表' } }, { path: 'strategy', component: () => import('@/views/product/strategy/CardList.vue'), meta: { title: '产品列表' } },
{ path: 'insurance', component: () => import('@/views/product/insurance/List.vue'), meta: { title: '保险产品' } }, { path: 'insurance', component: () => import('@/views/product/insurance/List.vue'), meta: { title: '保险产品' } },
{ path: 'insurance/:action', component: () => import('@/views/product/insurance/CardList.vue'), meta: { title: '保险产品' } }, { path: 'insurance/:action', component: () => import('@/views/product/insurance/CardList.vue'), meta: { title: '保险产品' } },
{ path: 'interestRate/:action', component: () => import('@/views/product/interestRate/CardList.vue'), meta: { title: '利率定价模型' } }, { path: 'interestRate', component: () => import('@/views/product/interestRate/CardList.vue'), meta: { title: '利率定价模型' } },
{ path: 'fund', component: () => import('@/views/product/fund/List.vue'), meta: { title: '基金产品' } }, { path: 'fund', component: () => import('@/views/product/fund/List.vue'), meta: { title: '基金产品' } },
{ path: 'fund/:action', component: () => import('@/views/product/fund/CardList.vue'), meta: { title: '基金产品' } }, { path: 'fund/:action', component: () => import('@/views/product/fund/CardList.vue'), meta: { title: '基金产品' } },
{ path: 'afterLoan', component: () => import('@/views/product/afterLoan/CardList.vue'), meta: { title: '贷后管理' } }, { path: 'afterLoan', component: () => import('@/views/product/afterLoan/CardList.vue'), meta: { title: '贷后管理' } },

@ -1,4 +1,4 @@
import { reactive, readonly } from 'vue'; import { reactive } from 'vue';
import { RouteRecordRaw } from 'vue-router'; import { RouteRecordRaw } from 'vue-router';
import { removeAccessToken, removeParam } from '@/utils/auth'; import { removeAccessToken, removeParam } from '@/utils/auth';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';

@ -1,7 +1,11 @@
import { reactive, readonly } from 'vue'; import { reactive, readonly } from 'vue';
import { statistics } from '@/api/bank';
import Cookies from 'js-cookie';
export interface Product { export interface Product {
status?: Record<string, any>; status?: Record<string, any>;
stat1?: number | string;
stat2?: number | string;
} }
const state = reactive<Product>({ const state = reactive<Product>({
@ -32,9 +36,12 @@ const state = reactive<Product>({
name: '审批打回', name: '审批打回',
}, },
], ],
// 左侧菜单项的右上角badge统计
stat1: '',
stat2: '',
}); });
export const productState = readonly(state); export const productState = state;
// 专家委员会产品进度(去除配置风控) // 专家委员会产品进度(去除配置风控)
export const getExpertStatus = (): Record<string, any>[] => { export const getExpertStatus = (): Record<string, any>[] => {
const newStatus = JSON.parse(JSON.stringify(state.status)); const newStatus = JSON.parse(JSON.stringify(state.status));
@ -45,3 +52,18 @@ export const getExpertStatus = (): Record<string, any>[] => {
export const getStatus = (id: number | string): string => { export const getStatus = (id: number | string): string => {
return state.status.find((e) => e.id === id)?.name; return state.status.find((e) => e.id === id)?.name;
}; };
// 获取产品数量
export const getStat = async (status?: number, type?: number): Promise<void> => {
const { data } = await statistics({
checkpointId: Cookies.get('sand-level'),
projectId: Cookies.get('sand-projectId'),
status,
productType: type,
});
if (type === 1) {
// 产品经理-企业
state.stat2 = data || '';
} else {
state.stat1 = data || '';
}
};

@ -49,9 +49,7 @@ body {
// global css // global css
.block { .block {
@apply p-5; @apply p-5 rounded-lg bg-white;
@apply rounded-lg;
@apply bg-white;
} }
.inline-form .el-form-item { .inline-form .el-form-item {
@ -102,11 +100,21 @@ body {
@apply flex-1 w-[calc(100vw-533px)] max-h-[calc(100vh-100px)] overflow-auto px-5 pt-2; @apply flex-1 w-[calc(100vw-533px)] max-h-[calc(100vh-100px)] overflow-auto px-5 pt-2;
} }
} }
.menu-card {
@apply flex;
.left {
@apply mr-4 rounded-lg border-r-0;
}
.right {
@apply flex-1 w-[calc(100vw-533px)] max-h-[calc(100vh-100px)] overflow-auto p-4 bg-white rounded-lg;
}
}
// .c-auto { // .c-auto {
// @apply w-[calc(100vw-533px)] max-h-[calc(100vh-160px)] overflow-auto; // @apply w-[calc(100vw-533px)] max-h-[calc(100vh-160px)] overflow-auto;
// } // }
.c-table { .c-table {
@apply rounded-[10px]; @apply rounded-[10px];
th.el-table__cell { th.el-table__cell {
@apply bg-[#F8FBFC]; @apply bg-[#F8FBFC];
} }
@ -117,7 +125,7 @@ body {
.el-input { .el-input {
@apply lg:text-xs; @apply lg:text-xs;
} }
.el-input__inner { .el-input__wrapper {
@apply px-2; @apply px-2;
} }
} }
@ -130,7 +138,7 @@ body {
} }
.el-select { .el-select {
@apply w-[170px]; @apply w-[170px];
.el-input__inner { .el-input__wrapper {
@apply pl-[41px] rounded-[18px] border-[#dfe9f8]; @apply pl-[41px] rounded-[18px] border-[#dfe9f8];
} }
} }
@ -149,19 +157,18 @@ body {
} }
} }
.dia-btn { .dia-btn {
padding: 11px 26px; @apply py-[11px] px-[26px] text-sm leading-[1] text-white rounded-[18px] cursor-pointer;
font-size: 14px;
line-height: 1;
color: #fff;
background: linear-gradient(-36deg, #006bff, #2ab1ff); background: linear-gradient(-36deg, #006bff, #2ab1ff);
border-radius: 18px;
cursor: pointer;
&.cancel { &.cancel {
font-size: 600; @apply mr-3 font-semibold text-[#333];
color: #333;
background: #f4f8fc; background: #f4f8fc;
} }
} }
.model-drawer {
.el-drawer__header > :first-child {
@apply text-[#333] text-xl font-semibold text-center;
}
}
@media screen and (-webkit-min-device-pixel-ratio: 1.5), screen and (min-resolution: 144dpi) { @media screen and (-webkit-min-device-pixel-ratio: 1.5), screen and (min-resolution: 144dpi) {
body { body {

@ -24,6 +24,7 @@ export const removeParam = (): void => {
Cookies.remove('sand-systemId'); Cookies.remove('sand-systemId');
Cookies.remove('sand-level'); Cookies.remove('sand-level');
Cookies.remove('sand-submit'); Cookies.remove('sand-submit');
Cookies.remove('sand-loaded');
}; };
export const getAuthHeaders = (): any => { export const getAuthHeaders = (): any => {

@ -273,3 +273,14 @@ export const whethers = [
name: '不启用', name: '不启用',
}, },
]; ];
export const opt1 = [
{
id: 345,
name: '是',
},
{
id: 346,
name: '否',
},
];

@ -5,9 +5,9 @@ import { logout } from '@/store/useCurrentUser';
const service = axios.create({ const service = axios.create({
baseURL: import.meta.env.VITE_BASE_API, baseURL: import.meta.env.VITE_BASE_API,
timeout: 10000, timeout: 60 * 1000,
}); });
let loaded = 0; let logouted = 0;
service.interceptors.request.use( service.interceptors.request.use(
(config) => { (config) => {
config.headers = { ...config.headers, ...getAuthHeaders() }; config.headers = { ...config.headers, ...getAuthHeaders() };
@ -18,12 +18,27 @@ service.interceptors.request.use(
service.interceptors.response.use( service.interceptors.response.use(
(res) => { (res) => {
const { message, status } = res.data; const { message, status, code, msg } = res.data;
if (status) { if (status) {
if (status === 200) { if (status === 200) {
return res; return res;
} }
message === '无缓存' || ElMessage.error(message);
ElMessage.error(message);
} else if (code === 401) {
// 账号互踢
if (!logouted) {
ElMessageBox.alert(msg.includes('顶') ? '您的账号已在其他设备登录,您已被迫下线!' : '登录过期,请重新登录!', {
confirmButtonText: '重新登录',
type: 'warning',
closeOnClickModal: false,
showClose: false,
}).then(() => {
// 未登录
logout();
});
logouted = 1;
}
} else { } else {
return res; return res;
} }
@ -36,12 +51,12 @@ service.interceptors.response.use(
}, },
} = e; } = e;
if (status === 401) { if (status === 401) {
loaded || logouted ||
ElMessageBox.alert('登录状态已过期,请重新登录', { confirmButtonText: '重新登录', type: 'warning', closeOnClickModal: false, showClose: false }).then(() => { ElMessageBox.alert('登录状态已过期,请重新登录', { confirmButtonText: '重新登录', type: 'warning', closeOnClickModal: false, showClose: false }).then(() => {
// 未登录 // 未登录
logout(); logout();
}); });
loaded = 1; logouted = 1;
} else if (message) { } else if (message) {
ElMessage.error(message); ElMessage.error(message);
} }

@ -4,9 +4,7 @@
<h1 class="font-bold text-3xl">403</h1> <h1 class="font-bold text-3xl">403</h1>
<p class="mt-4">对不起您没有该页面的访问权限</p> <p class="mt-4">对不起您没有该页面的访问权限</p>
<p class="mt-4"> <p class="mt-4">
<el-button type="primary" <el-button type="primary" @click="handleLogout()" plain>退出</el-button>
@click="handleLogout()"
plain>退出</el-button>
</p> </p>
</div> </div>
</div> </div>

@ -2,15 +2,16 @@
<div class="wscn-http404-container"> <div class="wscn-http404-container">
<div class="wscn-http404"> <div class="wscn-http404">
<div class="pic-404"> <div class="pic-404">
<img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404"> <img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404" />
<img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404"> <img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404" />
<img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404"> <img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404" />
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404"> <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404" />
</div> </div>
<div class="bullshit"> <div class="bullshit">
<div class="bullshit__oops">OOPS!</div> <div class="bullshit__oops">OOPS!</div>
<div class="bullshit__info">All rights reserved <div class="bullshit__info">
<a style="color:#20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a> All rights reserved
<a style="color: #20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a>
</div> </div>
<div class="bullshit__headline">{{ message }}</div> <div class="bullshit__headline">{{ message }}</div>
<div class="bullshit__info">Please check that the URL you entered is correct, or click the button below to return to the homepage.</div> <div class="bullshit__info">Please check that the URL you entered is correct, or click the button below to return to the homepage.</div>
@ -34,8 +35,8 @@ export default defineComponent({
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.wscn-http404-container{ .wscn-http404-container {
transform: translate(-50%,-50%); transform: translate(-50%, -50%);
position: absolute; position: absolute;
top: 40%; top: 40%;
left: 50%; left: 50%;

@ -2,64 +2,40 @@
<div class="flex justify-between items-center h-[64px] px-5 bg-white"> <div class="flex justify-between items-center h-[64px] px-5 bg-white">
<h1>金融产品设计及数字化营销沙盘系统</h1> <h1>金融产品设计及数字化营销沙盘系统</h1>
<div class="inline-flex items-center"> <div class="inline-flex items-center">
<el-tooltip effect="light" <el-tooltip effect="light" content="退出实训" placement="bottom">
content="退出实训" <img class="mr-3 cursor-pointer" src="@/assets/images/11.png" alt="" @click="logout" />
placement="bottom">
<img class="mr-3 cursor-pointer"
src="@/assets/images/11.png"
alt=""
@click="logout" />
</el-tooltip> </el-tooltip>
</div> </div>
</div> </div>
<div class="relative h-[calc(100vh-64px)] pt-5 pl-5 bg-[url('@/assets/images/level/4.png')] bg-[length:100%_100%] bg-no-repeat bg-fixed overflow-auto" <div class="relative h-[calc(100vh-64px)] pt-5 pl-5 bg-[url('@/assets/images/level/4.png')] bg-[length:100%_100%] bg-no-repeat bg-fixed overflow-auto" id="wrap">
id="wrap">
<div class="fixed z-10"> <div class="fixed z-10">
<div class="w-[354px] h-[68px] bg-[url('@/assets/images/level/5.png')] bg-[length:100%_100%] bg-no-repeat"></div> <div class="w-[354px] h-[68px] bg-[url('@/assets/images/level/5.png')] bg-[length:100%_100%] bg-no-repeat"></div>
<div class="absolute top-5 left-40 flex items-center cursor-pointer" <div class="absolute top-5 left-40 flex items-center cursor-pointer" @click="getLevel(1)">
@click="getLevel(1)"> <img v-if="collected" src="@/assets/images/level/7.png" alt="" />
<img v-if="collected" <img v-else src="@/assets/images/level/6.png" alt="" />
src="@/assets/images/level/7.png"
alt="" />
<img v-else
src="@/assets/images/level/6.png"
alt="" />
<span class="ml-2 text-sm text-[#999]">仅显示已收藏的关卡</span> <span class="ml-2 text-sm text-[#999]">仅显示已收藏的关卡</span>
</div> </div>
</div> </div>
<div class="relative mt-20"> <div class="relative mt-20">
<div v-for="(item, i) in levels" <div v-for="(item, i) in levels" :key="i" :class="['item', { active: curLevel === item.checkpointId, disabled: !item.enableOrNot }]" @click="selecLevel(item)">
:key="i" <span class="num">LV.{{ i + 1 }}</span>
:class="['item', { active: curLevel === item.checkpointId }]"
@click="selecLevel(item)">
<span class="num">LV.{{ item.serialNumber }}</span>
<div class="texts"> <div class="texts">
<h6>{{ numToChinese(item.serialNumber) }}</h6> <h6>{{ numToChinese(i + 1) }}</h6>
<p class="des mul-ellipsis2">{{ item.customsPassName }}</p> <p class="des mul-ellipsis2">{{ item.customsPassName }}</p>
<img v-if="item.collect" <img v-if="item.collect" class="icon" src="@/assets/images/level/star2.png" alt="" @click.stop="collectItem(item)" />
class="icon" <img v-else class="icon" src="@/assets/images/level/star1.png" alt="" @click.stop="collectItem(item)" />
src="@/assets/images/level/star2.png"
alt=""
@click.stop="collectItem(item)" />
<img v-else
class="icon"
src="@/assets/images/level/star1.png"
alt=""
@click.stop="collectItem(item)" />
</div> </div>
</div> </div>
</div> </div>
<div class="arrow top-[68px] left-[50%] translate-x-[-50%] w-[64px] h-[64px] bg-[url('@/assets/images/level/arrow-up.png')]" <div class="arrow top-[68px] left-[50%] translate-x-[-50%] w-[64px] h-[64px] bg-[url('@/assets/images/level/arrow-up.png')]" @click="move('up')"></div>
@click="move('up')"></div> <div class="arrow right-0 top-[50%] translate-y-[-50%] w-[64px] h-[64px] bg-[url('@/assets/images/level/arrow-right.png')]" @click="move('right')"></div>
<div class="arrow right-0 top-[50%] translate-y-[-50%] w-[64px] h-[64px] bg-[url('@/assets/images/level/arrow-right.png')]" <div class="arrow bottom-0 left-[50%] translate-x-[-50%] w-[64px] h-[64px] bg-[url('@/assets/images/level/arrow-down.png')]" @click="move('down')"></div>
@click="move('right')"></div> <div class="arrow left-0 top-[50%] translate-y-[-50%] w-[64px] h-[64px] bg-[url('@/assets/images/level/arrow-left.png')]" @click="move('left')"></div>
<div class="arrow bottom-0 left-[50%] translate-x-[-50%] w-[64px] h-[64px] bg-[url('@/assets/images/level/arrow-down.png')]" <div
@click="move('down')"></div> class="fixed bottom-2 right-1 w-[262px] h-[74px] bg-[url('@/assets/images/level/submit.png')] bg-[length:100%_100%] bg-no-repeat cursor-pointer hover:bg-[url('@/assets/images/level/submit-hover.png')]"
<div class="arrow left-0 top-[50%] translate-y-[-50%] w-[64px] h-[64px] bg-[url('@/assets/images/level/arrow-left.png')]" @click="toRole"
@click="move('left')"></div> ></div>
<div class="fixed bottom-2 right-1 w-[262px] h-[74px] bg-[url('@/assets/images/level/submit.png')] bg-[length:100%_100%] bg-no-repeat cursor-pointer hover:bg-[url('@/assets/images/level/submit-hover.png')]"
@click="toRole"></div>
</div> </div>
<Panel /> <Panel />
</template> </template>
@ -90,19 +66,21 @@ const getLevel = async (only: any = '') => {
provide('getLevel', getLevel); provide('getLevel', getLevel);
// //
const selecLevel = (item: Record<string, any>) => { const selecLevel = (item: Record<string, any>) => {
curLevel.value = item.checkpointId; if (item.enableOrNot) curLevel.value = item.checkpointId;
}; };
// //
const collectItem = async (item: Record<string, any>) => { const collectItem = async (item: Record<string, any>) => {
if (item.collect) { if (item.enableOrNot) {
await cancelCollection(item.favoriteId); if (item.collect) {
} else { await cancelCollection(item.favoriteId);
await collect({ } else {
checkpointId: item.checkpointId, await collect({
projectId, checkpointId: item.checkpointId,
}); projectId,
});
}
getLevel();
} }
getLevel();
}; };
// //
const toRole = () => { const toRole = () => {
@ -127,9 +105,7 @@ const move = (dir: string) => {
if (dir === 'up' || dir === 'down') param.top = el.scrollTop + (dir === 'up' ? -150 : 150); if (dir === 'up' || dir === 'down') param.top = el.scrollTop + (dir === 'up' ? -150 : 150);
el.scrollTo(param); el.scrollTo(param);
}; };
onMounted(() => { onMounted(getLevel);
getLevel();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -185,6 +161,9 @@ onMounted(() => {
-webkit-text-fill-color: #fff; -webkit-text-fill-color: #fff;
} }
} }
&.disabled {
@apply opacity-30 cursor-not-allowed;
}
&:nth-child(2) { &:nth-child(2) {
@apply top-[var(--line2)] left-[160px]; @apply top-[var(--line2)] left-[160px];

@ -41,49 +41,50 @@
<p class="text">今日渠道订单</p> <p class="text">今日渠道订单</p>
</div> </div>
</div> </div>
<el-tooltip effect="light" <el-tooltip effect="light" content="退出实训" placement="bottom">
content="退出实训" <img class="mr-3 cursor-pointer" src="@/assets/images/11.png" alt="" @click="logout" />
placement="bottom">
<img class="mr-3 cursor-pointer"
src="@/assets/images/11.png"
alt=""
@click="logout" />
</el-tooltip> </el-tooltip>
<el-tooltip effect="light" <el-tooltip effect="light" content="返回关卡" placement="bottom">
content="返回关卡" <img class="mr-3 cursor-pointer" src="@/assets/images/2.png" alt="" @click="toLevel" />
placement="bottom">
<img class="mr-3 cursor-pointer"
src="@/assets/images/2.png"
alt=""
@click="toLevel" />
</el-tooltip> </el-tooltip>
</div> </div>
</div> </div>
<div class="relative h-[calc(100vh-64px)] overflow-hidden bg-[#e5eafe]"> <div class="relative h-[calc(100vh-64px)] overflow-hidden bg-[#e5eafe]">
<img class="w-full h-full" <img class="w-full h-full" src="@/assets/images/role/bg.png" alt="" />
src="@/assets/images/role/bg.png"
alt="">
<div class="absolute top-5 left-[18px] w-[204px] h-[68px] bg-[url('@/assets/images/role/2.png')] bg-[length:100%_100%] bg-no-repeat"></div> <div class="absolute top-5 left-[18px] w-[204px] h-[68px] bg-[url('@/assets/images/role/2.png')] bg-[length:100%_100%] bg-no-repeat"></div>
<div class="date absolute top-[70px] left-[54%] w-[198px] h-[46px] pt-[10px] pl-[56px] text-base text-white bg-[url('@/assets/images/role/date.png')] bg-no-repeat transition"> <div class="date absolute top-[70px] left-[54%] w-[198px] h-[46px] pt-[10px] pl-[56px] text-base text-white bg-[url('@/assets/images/role/date.png')] bg-no-repeat transition">
{{ date }} {{ date }}
</div> </div>
<div class="role top-[30%] left-[17%] xl:top-[31%] lg:top-[32%] lg:left-[15%] bg-[url('@/assets/images/role/product.png')] hover:bg-[url('@/assets/images/role/product1.png')]" <div
@click="selectRole(41)"></div> class="role top-[30%] left-[17%] xl:top-[31%] lg:top-[32%] lg:left-[15%] bg-[url('@/assets/images/role/product.png')] hover:bg-[url('@/assets/images/role/product1.png')]"
<div class="role top-[22%] left-[25%] xl:top-[24%] lg:top-[25%] lg:left-[23%] bg-[url('@/assets/images/role/committee.png')] hover:bg-[url('@/assets/images/role/committee1.png')]" @click="selectRole(41)"
@click="selectRole(43)"></div> ></div>
<div class="role top-[17%] left-[31.5%] xl:top-[16%] xl:left-[31%] lg:left-[30%] bg-[url('@/assets/images/role/riskControl.png')] hover:bg-[url('@/assets/images/role/riskControl1.png')]" <div
@click="selectRole(42)"></div> class="role top-[22%] left-[25%] xl:top-[24%] lg:top-[25%] lg:left-[23%] bg-[url('@/assets/images/role/committee.png')] hover:bg-[url('@/assets/images/role/committee1.png')]"
<div class="role bottom-[200px] left-[100px] xl:bottom-[150px] lg:bottom-[120px] bg-[url('@/assets/images/role/insurance.png')] hover:bg-[url('@/assets/images/role/insurance1.png')]" @click="selectRole(43)"
@click="selectRole(275)"></div> ></div>
<div class="role relative bottom-[70px] left-[25%] bg-[url('@/assets/images/role/fund.png')] hover:bg-[url('@/assets/images/role/fund1.png')]" <div
@click="selectRole(1161)"></div> class="role top-[17%] left-[31.5%] xl:top-[16%] xl:left-[31%] lg:left-[30%] bg-[url('@/assets/images/role/riskControl.png')] hover:bg-[url('@/assets/images/role/riskControl1.png')]"
<div class="role relative bottom-[220px] left-[41%] bg-[url('@/assets/images/role/market-bank.png')] hover:bg-[url('@/assets/images/role/market-bank1.png')]" @click="selectRole(42)"
@click="selectRole('bank')"></div> ></div>
<div class="role relative bottom-[360px] left-[52%] bg-[url('@/assets/images/role/market-insurance.png')] hover:bg-[url('@/assets/images/role/market-insurance1.png')]" <div
@click="selectRole('insurance')"></div> class="role bottom-[200px] left-[100px] xl:bottom-[150px] lg:bottom-[120px] bg-[url('@/assets/images/role/insurance.png')] hover:bg-[url('@/assets/images/role/insurance1.png')]"
<div class="role relative bottom-[490px] left-[63%] bg-[url('@/assets/images/role/market-fund.png')] hover:bg-[url('@/assets/images/role/market-fund1.png')]" @click="selectRole(275)"
@click="selectRole('fund')"></div> ></div>
<div class="role relative bottom-[70px] left-[25%] bg-[url('@/assets/images/role/fund.png')] hover:bg-[url('@/assets/images/role/fund1.png')]" @click="selectRole(1161)"></div>
<div
class="role relative bottom-[220px] left-[41%] bg-[url('@/assets/images/role/market-bank.png')] hover:bg-[url('@/assets/images/role/market-bank1.png')]"
@click="selectRole('bank')"
></div>
<div
class="role relative bottom-[360px] left-[52%] bg-[url('@/assets/images/role/market-insurance.png')] hover:bg-[url('@/assets/images/role/market-insurance1.png')]"
@click="selectRole('insurance')"
></div>
<div
class="role relative bottom-[490px] left-[63%] bg-[url('@/assets/images/role/market-fund.png')] hover:bg-[url('@/assets/images/role/market-fund1.png')]"
@click="selectRole('fund')"
></div>
</div> </div>
<!-- <div class="fixed top-[80px] right-[80px]"> <!-- <div class="fixed top-[80px] right-[80px]">
<div class="flex items-center h-[60px] px-4 rounded-tl-[20px] rounded-tr-[20px]" <div class="flex items-center h-[60px] px-4 rounded-tl-[20px] rounded-tr-[20px]"
@ -124,20 +125,14 @@
<Panel /> <Panel />
<el-dialog v-model="dateVisible" <el-dialog v-model="dateVisible" title="选择交易日期" width="400px" center>
title="选择交易日期"
width="400px"
center>
<div class="text-center"> <div class="text-center">
<el-date-picker v-model="diaDate" <el-date-picker v-model="diaDate" type="date" />
type="date" />
</div> </div>
<template #footer> <template #footer>
<span class="flex justify-center"> <span class="flex justify-center">
<div class="dia-btn mr-3 cancel" <div class="dia-btn cancel" @click="dateVisible = false">取消</div>
@click="dateVisible = false">取消</div> <div class="dia-btn" @click="submitDate">确定</div>
<div class="dia-btn"
@click="submitDate">确定</div>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>
@ -155,11 +150,8 @@ import dayjs from 'dayjs';
import { getNow } from '@/utils/common'; import { getNow } from '@/utils/common';
const router = useRouter(); const router = useRouter();
const route = useRoute();
const projectId = +Cookies.get('sand-projectId'); const projectId = +Cookies.get('sand-projectId');
const levelId = +Cookies.get('sand-level'); const levelId = +Cookies.get('sand-level');
const collected = ref<boolean>(false);
const curLevel = ref<number | string>('');
const dateVisible = ref<boolean>(false); const dateVisible = ref<boolean>(false);
const date = ref<string>(dayjs(new Date()).format('YYYY-MM-DD')); const date = ref<string>(dayjs(new Date()).format('YYYY-MM-DD'));
const diaDate = ref<string>(dayjs(new Date()).format('YYYY-M-D')); const diaDate = ref<string>(dayjs(new Date()).format('YYYY-M-D'));
@ -228,11 +220,7 @@ const ranks = ref<Record<string, any>[]>([
money: '沙盘名称', money: '沙盘名称',
}, },
]); ]);
//
const getLevel = async () => {
const { data } = await checkPointList(1);
levels.value = data;
};
// //
const selectRole = (id: number) => { const selectRole = (id: number) => {
let path = `/product/bank?type=0&i=1&role=${id}`; let path = `/product/bank?type=0&i=1&role=${id}`;

@ -4,54 +4,37 @@
<dl> <dl>
<dt>担保方式</dt> <dt>担保方式</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in methods" <dd v-for="(item, i) in methods" :key="i" :class="{ active: method === item.id }" @click="filterClick(item, 'method')">{{ item.name }}</dd>
:key="i"
:class="{ active: method === item.id }"
@click="filterClick(item, 'method')">{{ item.name }}</dd>
</div> </div>
</dl> </dl>
<dl> <dl>
<dt>产品进度</dt> <dt>产品进度</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in methods" <dd v-for="(item, i) in methods" :key="i" :class="{ active: method === item.id }" @click="filterClick(item, 'method')">{{ item.name }}</dd>
:key="i"
:class="{ active: method === item.id }"
@click="filterClick(item, 'method')">{{ item.name }}</dd>
</div> </div>
</dl> </dl>
</div> </div>
<div class="block mt-3"> <div class="block mt-3">
<div class="search"> <div class="search">
<input type="text" <input type="text" placeholder="搜索" maxlength="20" />
placeholder="搜索" <img src="@/assets/images/search.png" alt="" class="icon" />
maxlength="20" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
</div> </div>
<el-table ref="table" <el-table ref="table" v-loading="loading" :data="data" @selection-change="(rows) => (selection = rows)" @sort-change="handleSort">
v-loading="loading" <el-table-column type="selection" :selectable="deletable" width="50"></el-table-column>
:data="data" <el-table-column property="id" label="ID" width="64" sortable="custom"></el-table-column>
@selection-change="(rows) => (selection = rows)"
@sort-change="handleSort">
<el-table-column type="selection"
:selectable="deletable"
width="50"></el-table-column>
<el-table-column property="id"
label="ID"
width="64"
sortable="custom"></el-table-column>
</el-table> </el-table>
<el-pagination v-model:currentPage="currentPage" <el-pagination
v-model:pageSize="pageSize" v-model:currentPage="currentPage"
:total="total" v-model:pageSize="pageSize"
:page-sizes="pageSizes" :total="total"
:layout="pageLayout" :page-sizes="pageSizes"
@size-change="fetchData()" :layout="pageLayout"
@current-change="fetchData()" @size-change="fetchData()"
small @current-change="fetchData()"
background small
class="px-3 py-2 justify-end"></el-pagination> background
class="px-3 py-2 justify-end"
></el-pagination>
</div> </div>
</div> </div>
</template> </template>

@ -1,30 +1,18 @@
<template> <template>
<div class="block"> <div class="block">
<div class="flex justify-between items-center mb-5"> <div class="flex justify-between items-center mb-5">
<search v-model="params.customsPassName" <search v-model="params.customsPassName" @change="getList"></search>
@change="getList"></search>
<div class="filter"> <div class="filter">
<div class="select"> <div class="select">
<el-select v-model="params.isEnable" <el-select v-model="params.isEnable" placeholder="启用状态" size="large" clearable>
placeholder="启用状态" <el-option v-for="item in enables" :key="item.id" :label="item.name" :value="item.id" />
size="large"
clearable>
<el-option v-for="item in enables"
:key="item.id"
:label="item.name"
:value="item.id" />
</el-select> </el-select>
<img src="@/assets/images/7.png" <img src="@/assets/images/7.png" alt="" class="icon" />
alt=""
class="icon" />
</div> </div>
<el-popconfirm :title="delTitle" <el-popconfirm :title="delTitle" :disabled="!multipleSelection.length" @confirm.stop="delAll">
:disabled="!multipleSelection.length"
@confirm.stop="delAll">
<template #reference> <template #reference>
<div :class="['add-btn mr-2', {'cursor-not-allowed': !multipleSelection.length}]"> <div :class="['add-btn mr-2', { 'cursor-not-allowed': !multipleSelection.length }]">
<el-icon :size="24" <el-icon :size="24" color="#fff">
color="#fff">
<Delete /> <Delete />
</el-icon> </el-icon>
删除关卡 删除关卡
@ -32,120 +20,73 @@
</template> </template>
</el-popconfirm> </el-popconfirm>
<div class="add-btn" <div class="add-btn" @click="toAdd">
@click="toAdd"> <img src="@/assets/images/plus.png" alt="" class="icon" />
<img src="@/assets/images/plus.png"
alt=""
class="icon" />
新增关卡 新增关卡
</div> </div>
</div> </div>
</div> </div>
<div class="h-[calc(100vh-310px)] overflow-auto" <div class="h-[calc(100vh-310px)] overflow-auto" id="tableWrap">
id="tableWrap"> <el-table v-loading="loading" :data="list" @sort-change="handleSort" @selection-change="handleSelectionChange">
<el-table v-loading="loading" <el-table-column label="移动" width="80">
:data="list"
@sort-change="handleSort"
@selection-change="handleSelectionChange">
<el-table-column label="移动"
width="80">
<template #default="{ row, $index }"> <template #default="{ row, $index }">
<el-popover placement="right" <el-popover placement="right" trigger="hover">
trigger="hover">
<template #reference> <template #reference>
<el-icon class="rotate-90 cursor-pointer" <el-icon class="rotate-90 cursor-pointer" :size="16" color="#877c7c">
:size="16"
color="#877c7c">
<MoreFilled /> <MoreFilled />
</el-icon> </el-icon>
</template> </template>
<div class="flex items-center mb-2"> <div class="flex items-center mb-2">
<el-input class="w-[80px]" <el-input class="w-[80px]" placeholder="请输入" v-model.number="row.serial"></el-input>
placeholder="请输入" <el-icon class="ml-2 cursor-pointer" :size="16" color="#877c7c" @click.stop="submitSerial(row, $index, row.serial)">
v-model.number="row.serial"></el-input>
<el-icon class="ml-2 cursor-pointer"
:size="16"
color="#877c7c"
@click.stop="submitSerial(row, $index, row.serial)">
<Check /> <Check />
</el-icon> </el-icon>
</div> </div>
<p class="my-2 cursor-pointer" <p class="my-2 cursor-pointer" @click="submitSerial(row, $index, 1)">置顶</p>
@click="submitSerial(row, $index, 1)">置顶</p> <p class="cursor-pointer" @click="submitSerial(row, $index, list.length)">置底</p>
<p class="cursor-pointer"
@click="submitSerial(row, $index, list.length)">置底</p>
</el-popover> </el-popover>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column type="selection" <el-table-column type="selection" width="55" />
width="55" /> <el-table-column label="序号" width="80" align="center">
<el-table-column label="序号"
width="80"
align="center">
<template #default="{ row, $index }"> <template #default="{ row, $index }">
{{ $index + 1 }} {{ $index + 1 }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="customsPassName" <el-table-column prop="customsPassName" min-width="200" label="关卡名称">
min-width="200"
label="关卡名称">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center"> <div class="flex items-center">
<el-input v-if="row.editing" <el-input v-if="row.editing" class="w-[250px]" placeholder="请输入关卡名称" v-model="row.customsPassName"></el-input>
class="w-[250px]"
placeholder="请输入关卡名称"
v-model="row.customsPassName"></el-input>
<span v-else>{{ row.customsPassName }}</span> <span v-else>{{ row.customsPassName }}</span>
<el-icon v-if="!row.editing" <el-icon v-if="!row.editing" class="mx-2 cursor-pointer" :size="16" color="#877c7c" @click="edit(row)">
class="mx-2 cursor-pointer"
:size="16"
color="#877c7c"
@click="edit(row)">
<Edit /> <Edit />
</el-icon> </el-icon>
<el-icon v-if="row.editing" <el-icon v-if="row.editing" class="ml-2 cursor-pointer" :size="16" color="#877c7c" @click="cancel(row)">
class="ml-2 cursor-pointer"
:size="16"
color="#877c7c"
@click="cancel(row)">
<Close /> <Close />
</el-icon> </el-icon>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="creator" <el-table-column prop="creator" min-width="170" label="创建人"></el-table-column>
min-width="170" <el-table-column prop="createTime" label="创建时间" width="180" sortable="custom"></el-table-column>
label="创建人"></el-table-column> <el-table-column label="启用关卡" width="140" align="center">
<el-table-column prop="createTime"
label="创建时间"
width="180"
sortable="custom"></el-table-column>
<el-table-column label="启用关卡"
width="140"
align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-popconfirm v-if="row.checkpointId" <el-popconfirm
:title="row.isEnable ? '禁用关卡后,已关联该关卡的判分点将被禁用,确定禁用吗?' : '启用关卡后,已关联该关卡的判分点将被启用,确定启用吗?'" v-if="row.checkpointId"
@confirm.stop="enableSubmit(row)"> :title="row.isEnable ? '禁用关卡后,已关联该关卡的判分点将被禁用,确定禁用吗?' : '启用关卡后,已关联该关卡的判分点将被启用,确定启用吗?'"
@confirm.stop="enableSubmit(row)"
>
<template #reference> <template #reference>
<el-switch v-if="row.checkpointId" <el-switch v-if="row.checkpointId" v-model="row.isEnable" :active-value="1" :inactive-value="0" @change="enableChange(row)" />
v-model="row.isEnable"
:active-value="1"
:inactive-value="0"
@change="enableChange(row)" />
</template> </template>
</el-popconfirm> </el-popconfirm>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" <el-table-column label="操作" width="120">
width="120">
<template #default="{ row }"> <template #default="{ row }">
<el-popconfirm v-if="row.checkpointId" <el-popconfirm v-if="row.checkpointId" :title="delTitle" @confirm.stop="handleDelete([row])">
:title="delTitle"
@confirm.stop="handleDelete([row])">
<template #reference> <template #reference>
<el-button type="text" <el-button type="text" size="small">删除</el-button>
size="small">删除</el-button>
</template> </template>
</el-popconfirm> </el-popconfirm>
</template> </template>
@ -153,11 +94,7 @@
</el-table> </el-table>
</div> </div>
<div class="filter flex justify-end mt-3"> <div class="filter flex justify-end mt-3">
<div :class="['add-btn', {'not-allow': !hadChange}]" <div :class="['add-btn', { 'not-allow': !hadChange }]" @click="save" v-loading="saveLoading">保存</div>
@click="save"
v-loading="saveLoading">
保存
</div>
</div> </div>
</div> </div>
</template> </template>
@ -176,7 +113,7 @@ const route = useRoute();
const projectId = +Cookies.get('sand-projectId'); const projectId = +Cookies.get('sand-projectId');
const levelId = +Cookies.get('sand-level'); const levelId = +Cookies.get('sand-level');
const hadChange = ref<number>(0); const hadChange = ref<number>(0);
const delTitle: string = '删除关卡后,已关联该关卡的判分点将被禁用,确定删除吗?'; const delTitle = '删除关卡后,已关联该关卡的判分点将被禁用,确定删除吗?';
const params = reactive({ const params = reactive({
createDateSort: '', createDateSort: '',
platformId: 3, platformId: 3,

@ -1,123 +1,71 @@
<template> <template>
<div class="max-h-[calc(100vh-290px)] overflow-auto"> <div class="max-h-[calc(100vh-290px)] overflow-auto">
<h6 class="title">城市人口及年龄参数</h6> <h6 class="title">城市人口及年龄参数</h6>
<el-table class="c-table" <el-table class="c-table" :data="form.ageAduRatioList" :span-method="ageSpan" border>
:data="form.ageAduRatioList" <el-table-column prop="productName" label="城市总人口 (人)" align="center">
:span-method="ageSpan"
border>
<el-table-column prop="productName"
label="城市总人口 (人)"
align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-input v-model.number="row.totalPopulation" <el-input v-model.number="row.totalPopulation" placeholder="请输入" type="number" min="0"></el-input>
placeholder="请输入"
type="number"
min="0"></el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="ageStage" <el-table-column prop="ageStage" label="年龄 (岁)" align="center"></el-table-column>
label="年龄 (岁)" <el-table-column prop="ageRatio" label="年龄占比 (%)" align="center">
align="center"></el-table-column>
<el-table-column prop="ageRatio"
label="年龄占比 (%)"
align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-input v-model="row.ageRatio" <el-input v-model="row.ageRatio" placeholder="请输入"></el-input>
placeholder="请输入"></el-input>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<h6 class="title mt-7">学历参数</h6> <h6 class="title mt-7">学历参数</h6>
<el-table class="c-table" <el-table class="c-table" :data="edus" :span-method="eduSpan" border>
:data="edus" <el-table-column prop="ageStage" label="年龄 (岁)" align="center"> </el-table-column>
:span-method="eduSpan" <el-table-column prop="education" label="学历" align="center"></el-table-column>
border> <el-table-column prop="parentIds" label="学历占比 (%)" align="center">
<el-table-column prop="ageStage"
label="年龄 (岁)"
align="center"> </el-table-column>
<el-table-column prop="education"
label="学历"
align="center"></el-table-column>
<el-table-column prop="parentIds"
label="学历占比 (%)"
align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-input v-model="row.eduRatio" <el-input v-model="row.eduRatio" placeholder="请输入"></el-input>
placeholder="请输入"></el-input>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<h6 class="title mt-7">企业数量配置</h6> <h6 class="title mt-7">企业数量配置</h6>
<el-table class="c-table" <el-table class="c-table" :data="form.enterpriseNumList" border>
:data="form.enterpriseNumList" <el-table-column prop="productName" label="企业类型" align="center">
border>
<el-table-column prop="productName"
label="企业类型"
align="center">
<template #default="{ row }"> <template #default="{ row }">
{{ row.enterpriseType == 1 ? '小微企业' : '创业企业' }} {{ row.enterpriseType == 1 ? '小微企业' : '创业企业' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="parentIds" <el-table-column prop="parentIds" label="企业数量(家)" align="center">
label="企业数量(家)"
align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-input v-model.number="row.number" <el-input v-model.number="row.number" placeholder="请输入" maxlength="3" type="number" min="0"></el-input>
placeholder="请输入"
maxlength="3"
type="number"
min="0"></el-input>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<h6 class="title mt-7">单个商品每日需求量</h6> <h6 class="title mt-7">单个商品每日需求量</h6>
<el-table class="c-table" <el-table class="c-table" :data="form.commodityDemandList" border>
:data="form.commodityDemandList" <el-table-column prop="typeName" label="买家类型" min-width="100" align="center"> </el-table-column>
border> <el-table-column prop="parentIds" label="买家总占比 (%)" min-width="100" align="center">
<el-table-column prop="typeName"
label="买家类型"
min-width="100"
align="center"> </el-table-column>
<el-table-column prop="parentIds"
label="买家总占比 (%)"
min-width="100"
align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-input v-model="row.buyerRatio" <el-input v-model="row.buyerRatio" placeholder="请输入"></el-input>
placeholder="请输入"></el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="parentIds" <el-table-column prop="parentIds" label="每次需求人数占比 (%)" min-width="130" align="center">
label="每次需求人数占比 (%)"
min-width="130"
align="center">
<template #default="{ row }"> <template #default="{ row }">
<el-input v-model="row.peopleNumRatio" <el-input v-model="row.peopleNumRatio" placeholder="请输入"></el-input>
placeholder="请输入"></el-input>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="parentIds" <el-table-column prop="parentIds" label="单个买家单次需求" min-width="200" align="center">
label="单个买家单次需求"
min-width="200"
align="center">
<template #default="{ row }"> <template #default="{ row }">
<div class="flex items-center"> <div class="flex items-center">
<template v-if="row.typeId == 7 || row.typeId == 8"> <template v-if="row.typeId == 7 || row.typeId == 8">
<span class="mr-2 whitespace-nowrap">一个保险产品一次最多购买</span> <span class="mr-2 whitespace-nowrap">一个保险产品一次最多购买</span>
<el-input v-model="row.buyerSingleDemand" <el-input v-model="row.buyerSingleDemand" placeholder="请输入"></el-input>
placeholder="请输入"></el-input>
<span class="ml-2"></span> <span class="ml-2"></span>
</template> </template>
<template v-else> <template v-else>
<span class="mr-2 whitespace-nowrap">{{ row.typeId == 9 ? '投入' : '贷款' }}</span> <span class="mr-2 whitespace-nowrap">{{ row.typeId == 9 ? '投入' : '贷款' }}</span>
<el-input v-model="row.buyerSingleDemandMin" <el-input v-model="row.buyerSingleDemandMin" placeholder="请输入"></el-input>
placeholder="请输入"></el-input>
<span class="mx-2">~</span> <span class="mx-2">~</span>
<el-input v-model="row.buyerSingleDemandMax" <el-input v-model="row.buyerSingleDemandMax" placeholder="请输入"></el-input>
placeholder="请输入"></el-input>
<span class="ml-2 whitespace-nowrap">万元</span> <span class="ml-2 whitespace-nowrap">万元</span>
</template> </template>
</div> </div>
@ -126,10 +74,7 @@
</el-table> </el-table>
<h6 class="title mt-7">系统账户起始金额</h6> <h6 class="title mt-7">系统账户起始金额</h6>
<el-form v-if="form.moneyAllocationList.length" <el-form v-if="form.moneyAllocationList.length" class="w-[300px]" label-width="120px" label-suffix=":">
class="w-[300px]"
label-width="120px"
label-suffix=":">
<el-form-item label="银行账户"> <el-form-item label="银行账户">
<el-input v-model="form.moneyAllocationList[0].startingAmount"> <el-input v-model="form.moneyAllocationList[0].startingAmount">
<template #suffix> 万元 </template> <template #suffix> 万元 </template>
@ -149,8 +94,7 @@
</div> </div>
<div class="flex justify-end"> <div class="flex justify-end">
<div class="submit" <div class="submit" @click="submit">保存修改</div>
@click="submit">保存修改</div>
</div> </div>
</template> </template>

@ -1,24 +1,19 @@
<template> <template>
<div class="max-h-[calc(100vh-290px)] overflow-auto"> <div class="max-h-[calc(100vh-290px)] overflow-auto">
<el-form ref="formRef" <el-form ref="formRef" label-width="100px" label-suffix="" class="form" status-icon>
label-width="100px"
label-suffix=":"
class="form"
status-icon>
<h6 class="title">单个银行账户</h6> <h6 class="title">单个银行账户</h6>
<el-form-item label="收益计算"> <el-form-item label="收益计算">
<div> <div>
<p class="text leading-[32px] ">收入 = 收回的本金 + 利息</p> <p class="text leading-[32px]">收入 = 收回的本金 + 利息</p>
<p class="text leading-[32px] ">成本 = 贷出去未收回的本金 + 购买渠道金额</p> <p class="text leading-[32px]">成本 = 贷出去未收回的本金 + 购买渠道金额</p>
<p class="text leading-[32px] ">收益 = 收入 - 成本</p> <p class="text leading-[32px]">收益 = 收入 - 成本</p>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="银行资产"> <el-form-item label="银行资产">
<div class="flex-1"> <div class="flex-1">
<div class="flex items-center"> <div class="flex items-center">
<span class="text">起始金额</span> <span class="text">起始金额</span>
<el-input class="w-[140px] mx-2" <el-input class="w-[140px] mx-2" v-model="form[0].startingAmount"></el-input>
v-model="form[0].startingAmount"></el-input>
<span class="text">万元</span> <span class="text">万元</span>
</div> </div>
<p class="text mt-4">银行账户金额 = 起始金额 + 累计收益</p> <p class="text mt-4">银行账户金额 = 起始金额 + 累计收益</p>
@ -28,17 +23,16 @@
<h6 class="title">单个保险账户</h6> <h6 class="title">单个保险账户</h6>
<el-form-item label="收益计算"> <el-form-item label="收益计算">
<div> <div>
<p class="text leading-[32px] ">收入 = 收到的保费</p> <p class="text leading-[32px]">收入 = 收到的保费</p>
<p class="text leading-[32px] ">成本 = 赔偿金 + 购买渠道金额</p> <p class="text leading-[32px]">成本 = 赔偿金 + 购买渠道金额</p>
<p class="text leading-[32px] ">收益 = 收入 - 成本</p> <p class="text leading-[32px]">收益 = 收入 - 成本</p>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="保险资产"> <el-form-item label="保险资产">
<div class="flex-1"> <div class="flex-1">
<div class="flex items-center"> <div class="flex items-center">
<span class="text">起始金额</span> <span class="text">起始金额</span>
<el-input class="w-[140px] mx-2" <el-input class="w-[140px] mx-2" v-model="form[1].startingAmount"></el-input>
v-model="form[1].startingAmount"></el-input>
<span class="text">万元</span> <span class="text">万元</span>
</div> </div>
<p class="text mt-4">保险账户金额 = 起始金额 + 累计收益</p> <p class="text mt-4">保险账户金额 = 起始金额 + 累计收益</p>
@ -48,23 +42,22 @@
<h6 class="title">单个基金账户</h6> <h6 class="title">单个基金账户</h6>
<el-form-item label="冻结账户"> <el-form-item label="冻结账户">
<div> <div>
<p class="text leading-[32px] ">冻结账户金额 = 申购金额 + 赎回金额</p> <p class="text leading-[32px]">冻结账户金额 = 申购金额 + 赎回金额</p>
<p class="text leading-[32px] ">基金申购以及赎回确认份额期间</p> <p class="text leading-[32px]">基金申购以及赎回确认份额期间</p>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="收益计算"> <el-form-item label="收益计算">
<div> <div>
<p class="text leading-[32px] ">收入 = 申购费用 + 管理费用 + 托管费用 + 销售服务费用 + 赎回费用</p> <p class="text leading-[32px]">收入 = 申购费用 + 管理费用 + 托管费用 + 销售服务费用 + 赎回费用</p>
<p class="text leading-[32px] ">成本 = 购买渠道金额</p> <p class="text leading-[32px]">成本 = 购买渠道金额</p>
<p class="text leading-[32px] ">收益 = 申购费用 + 管理费用 + 托管费用 + 销售服务费用 + 赎回费用</p> <p class="text leading-[32px]">收益 = 申购费用 + 管理费用 + 托管费用 + 销售服务费用 + 赎回费用</p>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="基金资产:"> <el-form-item label="基金资产:">
<div class="flex-1"> <div class="flex-1">
<div class="flex items-center"> <div class="flex items-center">
<span class="text">起始金额</span> <span class="text">起始金额</span>
<el-input class="w-[140px] mx-2" <el-input class="w-[140px] mx-2" v-model="form[2].startingAmount"></el-input>
v-model="form[2].startingAmount"></el-input>
<span class="text">万元</span> <span class="text">万元</span>
</div> </div>
<p class="text mt-4">基金账户金额 = 所有基金资产净值+起始金额 + 累计收益 - 购买渠道金额</p> <p class="text mt-4">基金账户金额 = 所有基金资产净值+起始金额 + 累计收益 - 购买渠道金额</p>
@ -74,8 +67,7 @@
</div> </div>
<div class="flex justify-end"> <div class="flex justify-end">
<div class="submit" <div class="submit" @click="submit">保存修改</div>
@click="submit">保存修改</div>
</div> </div>
</template> </template>

@ -1,19 +1,14 @@
<template> <template>
<div class="block"> <div class="block">
<el-tabs v-model="curTab" <el-tabs v-model="curTab" @tab-click="tabChange">
@tab-click="tabChange"> <el-tab-pane label="系统买方" name="tab1">
<el-tab-pane label="系统买方"
name="tab1">
<buyer /> <buyer />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="金融市场" <el-tab-pane label="金融市场" name="tab2">
name="tab2">
<Financial /> <Financial />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="扫单配置" <el-tab-pane label="扫单配置" name="tab3"> </el-tab-pane>
name="tab3"> </el-tab-pane> <el-tab-pane label="渠道广告" name="tab4"> </el-tab-pane>
<el-tab-pane label="渠道广告"
name="tab4"> </el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
</template> </template>

@ -9,23 +9,17 @@
<li> <li>
<h6 class="title mb-[10px]">收入总额</h6> <h6 class="title mb-[10px]">收入总额</h6>
<p class="text-lg text-[#F08B14]">696,652,660,000.00</p> <p class="text-lg text-[#F08B14]">696,652,660,000.00</p>
<img src="@/assets/images/account/1.png" <img src="@/assets/images/account/1.png" alt="" class="bg" />
alt=""
class="bg" />
</li> </li>
<li> <li>
<h6 class="title mb-[10px]">支出总额</h6> <h6 class="title mb-[10px]">支出总额</h6>
<p class="text-lg text-[#4488F4]">696,652,660,000.00</p> <p class="text-lg text-[#4488F4]">696,652,660,000.00</p>
<img src="@/assets/images/account/2.png" <img src="@/assets/images/account/2.png" alt="" class="bg" />
alt=""
class="bg" />
</li> </li>
<li> <li>
<h6 class="title mb-[10px]">累计收益</h6> <h6 class="title mb-[10px]">累计收益</h6>
<p class="text-lg text-[#FE4953]">696,652,660,000.00</p> <p class="text-lg text-[#FE4953]">696,652,660,000.00</p>
<img src="@/assets/images/account/3.png" <img src="@/assets/images/account/3.png" alt="" class="bg" />
alt=""
class="bg" />
</li> </li>
</ul> </ul>
</div> </div>
@ -40,8 +34,7 @@
<div> <div>
<div class="flex items-center mb-[75px]"> <div class="flex items-center mb-[75px]">
<div class="icon mr-2"> <div class="icon mr-2">
<img src="@/assets/images/account/6.png" <img src="@/assets/images/account/6.png" alt="" />
alt="" />
</div> </div>
<div class=""> <div class="">
<h6 class="mb-2 text-base text-[#333]">银行账户</h6> <h6 class="mb-2 text-base text-[#333]">银行账户</h6>
@ -50,8 +43,7 @@
</div> </div>
<div class="flex items-center mb-[75px]"> <div class="flex items-center mb-[75px]">
<div class="icon mr-2"> <div class="icon mr-2">
<img src="@/assets/images/account/7.png" <img src="@/assets/images/account/7.png" alt="" />
alt="" />
</div> </div>
<div class=""> <div class="">
@ -61,8 +53,7 @@
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
<div class="icon mr-2"> <div class="icon mr-2">
<img src="@/assets/images/account/8.png" <img src="@/assets/images/account/8.png" alt="" />
alt="" />
</div> </div>
<div class=""> <div class="">
<h6 class="mb-2 text-base text-[#333]">基金账户</h6> <h6 class="mb-2 text-base text-[#333]">基金账户</h6>
@ -81,8 +72,7 @@
<p class="text-[#448ACA] font-semibold">3656631.00</p> <p class="text-[#448ACA] font-semibold">3656631.00</p>
</div> </div>
<div class="icon blue ml-2"> <div class="icon blue ml-2">
<img src="@/assets/images/account/9.png" <img src="@/assets/images/account/9.png" alt="" />
alt="" />
</div> </div>
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
@ -91,8 +81,7 @@
<p class="text-[#448ACA] font-semibold">3656631.00</p> <p class="text-[#448ACA] font-semibold">3656631.00</p>
</div> </div>
<div class="icon blue ml-2"> <div class="icon blue ml-2">
<img src="@/assets/images/account/10.png" <img src="@/assets/images/account/10.png" alt="" />
alt="" />
</div> </div>
</div> </div>
</div> </div>

@ -5,77 +5,42 @@
<dl> <dl>
<dt>担保方式</dt> <dt>担保方式</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in productTypes" <dd v-for="(item, i) in productTypes" :key="i" :class="{ active: params.productType === item.id }" @click="filterClick(item, 'productType')">{{ item.name }}</dd>
:key="i"
:class="{ active: params.productType === item.id }"
@click="filterClick(item, 'productType')">{{ item.name }}</dd>
</div> </div>
</dl> </dl>
<dl> <dl>
<dt>担保方式</dt> <dt>担保方式</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in guarantees" <dd v-for="(item, i) in guarantees" :key="i" :class="{ active: params.guarantyStyleId === item.id }" @click="filterClick(item, 'guarantyStyleId')">{{ item.name }}</dd>
:key="i"
:class="{ active: params.guarantyStyleId === item.id }"
@click="filterClick(item, 'guarantyStyleId')">{{ item.name }}</dd>
</div> </div>
</dl> </dl>
<dl> <dl>
<dt>贷款期限</dt> <dt>贷款期限</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in times" <dd v-for="(item, i) in times" :key="i" :class="{ active: params.loanPeriod === item.name }" @click="filterClick(item, 'loanPeriod')">{{ item.name }}</dd>
:key="i"
:class="{ active: params.loanPeriod === item.name }"
@click="filterClick(item, 'loanPeriod')">{{ item.name }}</dd>
</div> </div>
</dl> </dl>
<dl> <dl>
<dt>贷款额度</dt> <dt>贷款额度</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in moneys" <dd v-for="(item, i) in moneys" :key="i" :class="{ active: params.loanLimit === item.name }" @click="filterClick(item, 'loanLimit')">{{ item.name }}</dd>
:key="i"
:class="{ active: params.loanLimit === item.name }"
@click="filterClick(item, 'loanLimit')">{{ item.name }}</dd>
</div> </div>
</dl> </dl>
</div> </div>
<div class="block mt-3"> <div class="block mt-3">
<div class="search mb-2"> <div class="search mb-2">
<input type="text" <input type="text" v-model="params.keyWord" placeholder="搜索" maxlength="20" />
v-model="params.keyWord" <img src="@/assets/images/search.png" alt="" class="icon" />
placeholder="搜索"
maxlength="20" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
</div> </div>
<el-table ref="table" <el-table ref="table" v-loading="loading" :data="list">
v-loading="loading" <el-table-column prop="productName" label="贷款名称" min-width="110"></el-table-column>
:data="list"> <el-table-column prop="productTypeText" label="贷款对象" min-width="80"></el-table-column>
<el-table-column prop="productName" <el-table-column prop="guarantyStyle" label="担保方式" min-width="80"></el-table-column>
label="贷款名称" <el-table-column prop="loanPeriod" label="贷款期限" min-width="80"></el-table-column>
min-width="110"></el-table-column> <el-table-column prop="loanLimit" label="贷款额度" min-width="80"></el-table-column>
<el-table-column prop="productTypeText" <el-table-column prop="rateStandard" label="参考利率范围" min-width="80"></el-table-column>
label="贷款对象" <el-table-column prop="userName" label="产品经理" min-width="80"></el-table-column>
min-width="80"></el-table-column> <el-table-column prop="operationTime" label="发布日期" min-width="80"></el-table-column>
<el-table-column prop="guarantyStyle"
label="担保方式"
min-width="80"></el-table-column>
<el-table-column prop="loanPeriod"
label="贷款期限"
min-width="80"></el-table-column>
<el-table-column prop="loanLimit"
label="贷款额度"
min-width="80"></el-table-column>
<el-table-column prop="rateStandard"
label="参考利率范围"
min-width="80"></el-table-column>
<el-table-column prop="userName"
label="产品经理"
min-width="80"></el-table-column>
<el-table-column prop="operationTime"
label="发布日期"
min-width="80"></el-table-column>
<!-- <el-table-column prop="id" <!-- <el-table-column prop="id"
label="操作" label="操作"
width="100"> width="100">
@ -85,16 +50,18 @@
@click="toDetail(row)">查看详情</el-button> @click="toDetail(row)">查看详情</el-button>
</template></el-table-column> --> </template></el-table-column> -->
</el-table> </el-table>
<el-pagination v-model:currentPage="currentPage" <el-pagination
v-model:pageSize="pageSize" v-model:currentPage="currentPage"
:total="total" v-model:pageSize="pageSize"
:page-sizes="pageSizes" :total="total"
:layout="pageLayout" :page-sizes="pageSizes"
@size-change="getList()" :layout="pageLayout"
@current-change="getList()" @size-change="getList()"
small @current-change="getList()"
background small
class="px-3 py-2 justify-end"></el-pagination> background
class="px-3 py-2 justify-end"
></el-pagination>
</div> </div>
</div> </div>
</template> </template>

@ -49,19 +49,21 @@
</div> </div>
<div class="line"> <div class="line">
<span class="label">贷款用途</span> <span class="label">贷款用途</span>
<div class="val">{{ <div class="val">
info.loanPurpose === '购房' {{
? '可用于住房按揭贷款、二手房住房按揭贷款。' info.loanPurpose === '购房'
: info.loanPurpose === '消费' ? '可用于住房按揭贷款、二手房住房按揭贷款。'
? '贷款用途可用于除购房之外的合法个人消费支出,不得用于投资经营,不得用于无指定用途的个人支出。' : info.loanPurpose === '消费'
: info.loanPurpose === '经营' && !info.productType ? '贷款用途可用于除购房之外的合法个人消费支出,不得用于投资经营,不得用于无指定用途的个人支出。'
? '可用于个人或其企业生产和经营活动中临时性、季节性等流动资金周转以及购置、安装或修理小型设备和装潢经营性场所所需的人民币贷款业务。' : info.loanPurpose === '经营' && !info.productType
: info.loanPurpose === '创业' ? '可用于个人或其企业生产和经营活动中临时性、季节性等流动资金周转以及购置、安装或修理小型设备和装潢经营性场所所需的人民币贷款业务。'
? '用于创业或再创业过程中的资金需求。' : info.loanPurpose === '创业'
: info.loanPurpose === '经营' && info.productType ? '用于创业或再创业过程中的资金需求。'
? '用于短期生产经营周转的可循环的人民币信用贷款业务。' : info.loanPurpose === '经营' && info.productType
: info.otherPurposesOfLoan ? '用于短期生产经营周转的可循环的人民币信用贷款业务。'
}}</div> : info.otherPurposesOfLoan
}}
</div>
</div> </div>
<div class="line"> <div class="line">
<span class="label">还款方式</span> <span class="label">还款方式</span>
@ -81,71 +83,43 @@
<span class="label">材料要求</span> <span class="label">材料要求</span>
<div class="val"> <div class="val">
<p class="text">办理账户-提供材料{{ riskInfo?.accountMaterials }}</p> <p class="text">办理账户-提供材料{{ riskInfo?.accountMaterials }}</p>
<p v-if="riskInfo?.sendingAccount" <p v-if="riskInfo?.sendingAccount" class="text">办理账户-发放账户借记卡或放款专户</p>
class="text">办理账户-发放账户借记卡或放款专户</p> <p v-if="riskInfo?.loanApplicationMethod" class="text">贷款申请-申请方式{{ riskInfo?.loanApplicationMethod }}</p>
<p v-if="riskInfo?.loanApplicationMethod" <p v-if="riskInfo?.borrowerMaterial" class="text">贷款申请-提供材料-借款人材料{{ riskInfo?.borrowerMaterial }}</p>
class="text">贷款申请-申请方式{{ riskInfo?.loanApplicationMethod }}</p>
<p v-if="riskInfo?.borrowerMaterial"
class="text">贷款申请-提供材料-借款人材料{{ riskInfo?.borrowerMaterial }}</p>
<template v-if="info.productType"> <template v-if="info.productType">
<p v-if="riskInfo?.enterpriseMaterial" <p v-if="riskInfo?.enterpriseMaterial" class="text">贷款申请-提供材料-企业材料{{ riskInfo?.enterpriseMaterial }}</p>
class="text">贷款申请-提供材料-企业材料{{ riskInfo?.enterpriseMaterial }}</p> <p v-if="riskInfo?.collateral" class="text">贷款申请-提供材料-抵押物{{ riskInfo?.collateral }}</p>
<p v-if="riskInfo?.collateral"
class="text">贷款申请-提供材料-抵押物{{ riskInfo?.collateral }}</p>
</template> </template>
<template v-else> <template v-else>
<p v-if="riskInfo?.mateMaterial" <p v-if="riskInfo?.mateMaterial" class="text">贷款申请-提供材料-配偶材料{{ riskInfo?.mateMaterial }}</p>
class="text">贷款申请-提供材料-配偶材料{{ riskInfo?.mateMaterial }}</p> <p v-if="riskInfo?.businessMaterials" class="text">贷款申请-提供材料-经营类材料{{ riskInfo?.businessMaterials }}</p>
<p v-if="riskInfo?.businessMaterials"
class="text">贷款申请-提供材料-经营类材料{{ riskInfo?.businessMaterials }}</p>
</template> </template>
<p v-if="riskInfo?.supplementaryMaterials" <p v-if="riskInfo?.supplementaryMaterials" class="text">贷款申请-提供材料-补充材料{{ riskInfo?.supplementaryMaterials }}</p>
class="text">贷款申请-提供材料-补充材料{{ riskInfo?.supplementaryMaterials }}</p> <p v-if="riskInfo?.runBatchObject" class="text">系统跑批准入风控策略-跑批对象{{ riskInfo?.runBatchObject }}</p>
<p v-if="riskInfo?.runBatchObject" <p v-if="riskInfo?.accessStrategy" class="text">系统跑批准入风控策略-准入策略{{ riskInfo?.accessStrategy }}</p>
class="text">系统跑批准入风控策略-跑批对象{{ riskInfo?.runBatchObject }}</p> <p v-if="riskInfo?.personalCreditScoringStrategies" class="text">系统跑批准入风控策略-信用评分策略{{ riskInfo?.personalCreditScoringStrategies }}</p>
<p v-if="riskInfo?.accessStrategy" <p v-if="riskInfo?.riskDegreeStrategy" class="text">系统跑批准入风控策略-风险度策略{{ riskInfo?.riskDegreeStrategy }}</p>
class="text">系统跑批准入风控策略-准入策略{{ riskInfo?.accessStrategy }}</p> <p v-if="riskInfo?.interestRatePricingModel" class="text">系统跑批准入风控策略-利率定价模型-个人额度模型{{ riskInfo?.interestRatePricingModel }}</p>
<p v-if="riskInfo?.personalCreditScoringStrategies" <p v-if="riskInfo?.individualInterestRateModel" class="text">系统跑批准入风控策略-利率定价模型-个人利率模型</p>
class="text">系统跑批准入风控策略-信用评分策略{{ riskInfo?.personalCreditScoringStrategies }}</p> <p v-if="riskInfo?.dueDiligenceMode" class="text">尽职调查-尽调方式{{ riskInfo?.dueDiligenceMode }}</p>
<p v-if="riskInfo?.riskDegreeStrategy" <p v-if="riskInfo?.dueDiligenceContent" class="text">尽职调查-尽调内容{{ riskInfo?.dueDiligenceContent }}</p>
class="text">系统跑批准入风控策略-风险度策略{{ riskInfo?.riskDegreeStrategy }}</p> <p v-if="riskInfo?.reviewContent" class="text">贷款审查-审查内容{{ riskInfo?.reviewContent }}</p>
<p v-if="riskInfo?.interestRatePricingModel" <p v-if="riskInfo?.reviewSignature" class="text">贷款审查-审查签字{{ riskInfo?.reviewSignature }}</p>
class="text">系统跑批准入风控策略-利率定价模型-个人额度模型{{ riskInfo?.interestRatePricingModel }}</p> <p v-if="riskInfo?.reviewApproveContent" class="text">贷款审批-审批内容{{ riskInfo?.reviewApproveContent }}</p>
<p v-if="riskInfo?.individualInterestRateModel" <p v-if="riskInfo?.approvalSignature" class="text">贷款审批-审批签字{{ riskInfo?.approvalSignature }}</p>
class="text">系统跑批准入风控策略-利率定价模型-个人利率模型</p> <p v-if="riskInfo?.contractMaterials" class="text">签订合同-提供的材料{{ riskInfo?.contractMaterials }}</p>
<p v-if="riskInfo?.dueDiligenceMode" <p v-if="riskInfo?.loanContract" class="text">签订合同-合同模板-借贷合同{{ riskInfo?.loanContract }}</p>
class="text">尽职调查-尽调方式{{ riskInfo?.dueDiligenceMode }}</p> <p v-if="riskInfo?.mortgageContract" class="text">签订合同-合同模板-抵押合同{{ riskInfo?.mortgageContract }}</p>
<p v-if="riskInfo?.dueDiligenceContent" <p v-if="riskInfo?.pledgeContract" class="text">签订合同-合同模板-质押合同{{ riskInfo?.pledgeContract }}</p>
class="text">尽职调查-尽调内容{{ riskInfo?.dueDiligenceContent }}</p> <p v-if="riskInfo?.guaranteeContract" class="text">签订合同-合同模板-担保合同{{ riskInfo?.guaranteeContract }}</p>
<p v-if="riskInfo?.reviewContent" <p v-if="riskInfo?.selectionStrategy" class="text">贷后管理-选择策略{{ riskInfo?.selectionStrategy }}</p>
class="text">贷款审查-审查内容{{ riskInfo?.reviewContent }}</p>
<p v-if="riskInfo?.reviewSignature"
class="text">贷款审查-审查签字{{ riskInfo?.reviewSignature }}</p>
<p v-if="riskInfo?.reviewApproveContent"
class="text">贷款审批-审批内容{{ riskInfo?.reviewApproveContent }}</p>
<p v-if="riskInfo?.approvalSignature"
class="text">贷款审批-审批签字{{ riskInfo?.approvalSignature }}</p>
<p v-if="riskInfo?.contractMaterials"
class="text">签订合同-提供的材料{{ riskInfo?.contractMaterials }}</p>
<p v-if="riskInfo?.loanContract"
class="text">签订合同-合同模板-借贷合同{{ riskInfo?.loanContract }}</p>
<p v-if="riskInfo?.mortgageContract"
class="text">签订合同-合同模板-抵押合同{{ riskInfo?.mortgageContract }}</p>
<p v-if="riskInfo?.pledgeContract"
class="text">签订合同-合同模板-质押合同{{ riskInfo?.pledgeContract }}</p>
<p v-if="riskInfo?.guaranteeContract"
class="text">签订合同-合同模板-担保合同{{ riskInfo?.guaranteeContract }}</p>
<p v-if="riskInfo?.selectionStrategy"
class="text">贷后管理-选择策略{{ riskInfo?.selectionStrategy }}</p>
</div> </div>
</div> </div>
</div> </div>
<div class="user m-4"> <div class="user m-4">
<h6 class="mb-4 text-lg font-semibold text-[#01305B]">产品经理</h6> <h6 class="mb-4 text-lg font-semibold text-[#01305B]">产品经理</h6>
<div class="text-center"> <div class="text-center">
<img src="@/assets/images/bankDetail/4.png" <img src="@/assets/images/bankDetail/4.png" alt="" class="mx-auto" />
alt=""
class="mx-auto" />
<p class="mt-2 font-semibold text-[#114575]">{{ userName }}</p> <p class="mt-2 font-semibold text-[#114575]">{{ userName }}</p>
</div> </div>
<p class="mt-2 text-[#114575]">财经学院 金融2班</p> <p class="mt-2 text-[#114575]">财经学院 金融2班</p>
@ -157,7 +131,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'; import { ref, computed, watch, onMounted } from 'vue';
import { findById } from '@/api/bank'; import { findById } from '@/api/bank';
import { getTheCurrentUserName } from '@/api/config';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import Back from '@/components/Back.vue'; import Back from '@/components/Back.vue';
@ -179,14 +152,8 @@ const getDetail = async () => {
} }
} }
}; };
//
const getName = async () => {
const res = await getTheCurrentUserName();
userName.value = res.userName;
};
onMounted(() => { onMounted(() => {
getDetail(); getDetail();
getName();
}); });
</script> </script>

@ -5,77 +5,41 @@
<dl> <dl>
<dt>申购费率</dt> <dt>申购费率</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in rates" <dd v-for="(item, i) in rates" :key="i" :class="{ active: params.subscriptionRate === item.id }" @click="filterClick(item, 'subscriptionRate')">{{ item.name }}</dd>
:key="i"
:class="{ active: params.subscriptionRate === item.id }"
@click="filterClick(item, 'subscriptionRate')">{{ item.name }}</dd>
</div> </div>
</dl> </dl>
<dl> <dl>
<dt>成立年限</dt> <dt>成立年限</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in times" <dd v-for="(item, i) in times" :key="i" :class="{ active: params.establishmentPeriod === item.name }" @click="filterClick(item, 'establishmentPeriod')">
:key="i" {{ item.name }}
:class="{ active: params.establishmentPeriod === item.name }" </dd>
@click="filterClick(item, 'establishmentPeriod')">{{ item.name }}</dd>
</div> </div>
</dl> </dl>
<dl> <dl>
<dt>基金规模</dt> <dt>基金规模</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in scales" <dd v-for="(item, i) in scales" :key="i" :class="{ active: params.fundraisingScale === item.name }" @click="filterClick(item, 'fundraisingScale')">{{ item.name }}</dd>
:key="i"
:class="{ active: params.fundraisingScale === item.name }"
@click="filterClick(item, 'fundraisingScale')">{{ item.name }}</dd>
</div> </div>
</dl> </dl>
</div> </div>
<div class="block mt-3"> <div class="block mt-3">
<div class="search mb-2"> <div class="search mb-2">
<input type="text" <input type="text" v-model="params.fundName" placeholder="搜索" maxlength="20" />
v-model="params.fundName" <img src="@/assets/images/search.png" alt="" class="icon" />
placeholder="搜索"
maxlength="20" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
</div> </div>
<el-table ref="table" <el-table ref="table" v-loading="loading" :data="list">
v-loading="loading" <el-table-column prop="fundCode" label="基金代码" min-width="80"></el-table-column>
:data="list"> <el-table-column prop="fundName" label="基金名称" min-width="110"></el-table-column>
<el-table-column prop="fundCode" <el-table-column prop="dailyNetAssetValue" label="最新单位净值" min-width="80"></el-table-column>
label="基金代码" <el-table-column prop="dailyGrowthRate" label="日增长率(%)" min-width="80"></el-table-column>
min-width="80"></el-table-column> <el-table-column prop="weeklyGrowthRate" label="近1周(%)" min-width="80"></el-table-column>
<el-table-column prop="fundName" <el-table-column prop="monthlyGrowthRate" label="近1月(%)" min-width="80"></el-table-column>
label="基金名称" <el-table-column prop="growthRateInRecentMarch" label="近3月(%)" min-width="80"></el-table-column>
min-width="110"></el-table-column> <el-table-column prop="growthRateSinceInception" label="成立来(%)" min-width="80"></el-table-column>
<el-table-column prop="dailyNetAssetValue" <el-table-column prop="fundraisingScale" label="基金规模(万元)" min-width="80"></el-table-column>
label="最新单位净值" <el-table-column prop="userName" label="产品经理" min-width="80"></el-table-column>
min-width="80"></el-table-column> <el-table-column prop="operationTime" label="发布日期" min-width="80"></el-table-column>
<el-table-column prop="dailyGrowthRate"
label="日增长率(%)"
min-width="80"></el-table-column>
<el-table-column prop="weeklyGrowthRate"
label="近1周(%)"
min-width="80"></el-table-column>
<el-table-column prop="monthlyGrowthRate"
label="近1月(%)"
min-width="80"></el-table-column>
<el-table-column prop="growthRateInRecentMarch"
label="近3月(%)"
min-width="80"></el-table-column>
<el-table-column prop="growthRateSinceInception"
label="成立来(%)"
min-width="80"></el-table-column>
<el-table-column prop="fundraisingScale"
label="基金规模(万元)"
min-width="80"></el-table-column>
<el-table-column prop="userName"
label="产品经理"
min-width="80"></el-table-column>
<el-table-column prop="operationTime"
label="发布日期"
min-width="80"></el-table-column>
<!-- <el-table-column prop="id" <!-- <el-table-column prop="id"
label="操作" label="操作"
width="100"> width="100">
@ -85,16 +49,18 @@
@click="toDetail(row)">查看详情</el-button> @click="toDetail(row)">查看详情</el-button>
</template></el-table-column> --> </template></el-table-column> -->
</el-table> </el-table>
<el-pagination v-model:currentPage="currentPage" <el-pagination
v-model:pageSize="pageSize" v-model:currentPage="currentPage"
:total="total" v-model:pageSize="pageSize"
:page-sizes="pageSizes" :total="total"
:layout="pageLayout" :page-sizes="pageSizes"
@size-change="getList()" :layout="pageLayout"
@current-change="getList()" @size-change="getList()"
small @current-change="getList()"
background small
class="px-3 py-2 justify-end"></el-pagination> background
class="px-3 py-2 justify-end"
></el-pagination>
</div> </div>
</div> </div>
</template> </template>

@ -5,71 +5,39 @@
<dl> <dl>
<dt>险种分类</dt> <dt>险种分类</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in insuranceTypes" <dd v-for="(item, i) in insuranceTypes" :key="i" :class="{ active: params.insuranceType === item.id }" @click="filterClick(item, 'insuranceType')">{{ item.name }}</dd>
:key="i"
:class="{ active: params.insuranceType === item.id }"
@click="filterClick(item, 'insuranceType')">{{ item.name }}</dd>
</div> </div>
</dl> </dl>
<dl v-if="params.insuranceType !== 311"> <dl v-if="params.insuranceType !== 311">
<dt>承保年龄</dt> <dt>承保年龄</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in ages" <dd v-for="(item, i) in ages" :key="i" :class="{ active: params.coverageAge === item.id }" @click="filterClick(item, 'coverageAge')">{{ item.id }}</dd>
:key="i"
:class="{ active: params.coverageAge === item.id }"
@click="filterClick(item, 'coverageAge')">{{ item.id }}</dd>
</div> </div>
</dl> </dl>
<dl> <dl>
<dt>保险期限</dt> <dt>保险期限</dt>
<div class="vals"> <div class="vals">
<dd v-for="(item, i) in times" <dd v-for="(item, i) in times" :key="i" :class="{ active: params.protectionPeriod === item.id }" @click="filterClick(item, 'protectionPeriod')">{{ item.id }}</dd>
:key="i"
:class="{ active: params.protectionPeriod === item.id }"
@click="filterClick(item, 'protectionPeriod')">{{ item.id }}</dd>
</div> </div>
</dl> </dl>
</div> </div>
<div class="block mt-3"> <div class="block mt-3">
<div class="search mb-2"> <div class="search mb-2">
<input type="text" <input type="text" v-model="params.insuranceName" placeholder="搜索" maxlength="20" />
v-model="params.insuranceName" <img src="@/assets/images/search.png" alt="" class="icon" />
placeholder="搜索"
maxlength="20" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
</div> </div>
<el-table ref="table" <el-table ref="table" v-loading="loading" :data="list">
v-loading="loading" <el-table-column prop="insuranceName" label="保险名称" min-width="110"></el-table-column>
:data="list"> <el-table-column prop="insuranceTypeText" label="险种分类" min-width="80"></el-table-column>
<el-table-column prop="insuranceName" <el-table-column v-if="params.insuranceType !== 311" prop="guarantyStyle" label="承保年龄" min-width="80">
label="保险名称"
min-width="110"></el-table-column>
<el-table-column prop="insuranceTypeText"
label="险种分类"
min-width="80"></el-table-column>
<el-table-column v-if="params.insuranceType !== 311"
prop="guarantyStyle"
label="承保年龄"
min-width="80">
<template #default="{ row }"> <template #default="{ row }">
{{ row.minimumAge ? row.minimumAge + '-' + row.maximumAge + '周岁' : '-' }} {{ row.minimumAge ? row.minimumAge + '-' + row.maximumAge + '周岁' : '-' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="insuranceDeadline" <el-table-column prop="insuranceDeadline" label="保险期限" min-width="80"></el-table-column>
label="保险期限" <el-table-column prop="premiumAmount" label="保费(元)" min-width="80"></el-table-column>
min-width="80"></el-table-column> <el-table-column prop="userName" label="产品经理" min-width="80"></el-table-column>
<el-table-column prop="premiumAmount" <el-table-column prop="operationTime" label="发布日期" min-width="80"></el-table-column>
label="保费(元)"
min-width="80"></el-table-column>
<el-table-column prop="userName"
label="产品经理"
min-width="80"></el-table-column>
<el-table-column prop="operationTime"
label="发布日期"
min-width="80"></el-table-column>
<!-- <el-table-column prop="id" <!-- <el-table-column prop="id"
label="操作" label="操作"
width="100"> width="100">
@ -79,16 +47,18 @@
@click="toDetail(row)">查看详情</el-button> @click="toDetail(row)">查看详情</el-button>
</template></el-table-column> --> </template></el-table-column> -->
</el-table> </el-table>
<el-pagination v-model:currentPage="currentPage" <el-pagination
v-model:pageSize="pageSize" v-model:currentPage="currentPage"
:total="total" v-model:pageSize="pageSize"
:page-sizes="pageSizes" :total="total"
:layout="pageLayout" :page-sizes="pageSizes"
@size-change="getList()" :layout="pageLayout"
@current-change="getList()" @size-change="getList()"
small @current-change="getList()"
background small
class="px-3 py-2 justify-end"></el-pagination> background
class="px-3 py-2 justify-end"
></el-pagination>
</div> </div>
</div> </div>
</template> </template>

@ -8,55 +8,37 @@
<h6 class="title mb-5">订单列表</h6> <h6 class="title mb-5">订单列表</h6>
<div class="flex justify-between mb-5"> <div class="flex justify-between mb-5">
<div class="search"> <div class="search">
<input type="text" <input type="text" placeholder="搜索" maxlength="20" />
placeholder="搜索" <img src="@/assets/images/search.png" alt="" class="icon" />
maxlength="20" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
</div> </div>
<div> <div>
<el-select v-model="form.status" <el-select v-model="form.status" placeholder="订单类型" size="large">
placeholder="订单类型" <el-option v-for="item in paces" :key="item.id" :label="item.name" :value="item.id" />
size="large">
<el-option v-for="item in paces"
:key="item.id"
:label="item.name"
:value="item.id" />
</el-select> </el-select>
</div> </div>
</div> </div>
<el-table ref="table" <el-table ref="table" v-loading="loading" :data="data">
v-loading="loading" <el-table-column type="selection" :selectable="deletable" width="50"></el-table-column>
:data="data"> <el-table-column prop="parentIds" label="订单号"></el-table-column>
<el-table-column type="selection" <el-table-column prop="parentIds" label="产品名称"></el-table-column>
:selectable="deletable" <el-table-column prop="parentIds" label="订单类型"></el-table-column>
width="50"></el-table-column> <el-table-column prop="parentIds" label="成交情况"></el-table-column>
<el-table-column prop="parentIds" <el-table-column prop="parentIds" label="成交日期"></el-table-column>
label="订单号"></el-table-column> <el-table-column prop="parentIds" label="订单情况 "></el-table-column>
<el-table-column prop="parentIds" <el-table-column prop="parentIds" label="备注"></el-table-column>
label="产品名称"></el-table-column>
<el-table-column prop="parentIds"
label="订单类型"></el-table-column>
<el-table-column prop="parentIds"
label="成交情况"></el-table-column>
<el-table-column prop="parentIds"
label="成交日期"></el-table-column>
<el-table-column prop="parentIds"
label="订单情况 "></el-table-column>
<el-table-column prop="parentIds"
label="备注"></el-table-column>
</el-table> </el-table>
<el-pagination v-model:currentPage="currentPage" <el-pagination
v-model:pageSize="pageSize" v-model:currentPage="currentPage"
:total="total" v-model:pageSize="pageSize"
:page-sizes="pageSizes" :total="total"
:layout="pageLayout" :page-sizes="pageSizes"
@size-change="fetchData()" :layout="pageLayout"
@current-change="fetchData()" @size-change="fetchData()"
small @current-change="fetchData()"
background small
class="px-3 py-2 justify-end"></el-pagination> background
class="px-3 py-2 justify-end"
></el-pagination>
</div> </div>
</div> </div>
</template> </template>

@ -6,34 +6,25 @@
<div class="line"> <div class="line">
<label class="label">产品类型</label> <label class="label">产品类型</label>
<div class="fields"> <div class="fields">
<el-input value="银行产品" <el-input value="银行产品" disabled></el-input>
disabled></el-input>
</div> </div>
</div> </div>
<div class="line"> <div class="line">
<label class="label">选择产品</label> <label class="label">选择产品</label>
<div class="fields flex items-center"> <div class="fields flex items-center">
<el-input class="mr-5" <el-input class="mr-5" placeholder="点击选择需要发布的产品"></el-input>
placeholder="点击选择需要发布的产品"></el-input> <div class="btn" @click="showProduct">新增</div>
<div class="btn"
@click="showProduct">新增</div>
</div> </div>
</div> </div>
<div class="line"> <div class="line">
<label class="label">产品图标</label> <label class="label">产品图标</label>
<div class="fields"> <div class="fields">
<p class="tips">上传产品LOGO图片</p> <p class="tips">上传产品LOGO图片</p>
<div class="avatar-uploader" <div class="avatar-uploader" action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15" :show-file-list="false">
action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15" <img v-if="imageUrl" :src="imageUrl" class="avatar" />
:show-file-list="false"> <div v-else class="upload">
<img v-if="imageUrl"
:src="imageUrl"
class="avatar" />
<div v-else
class="upload">
<el-icon :size="20"> <el-icon :size="20">
<Plus :size="20" <Plus :size="20" color="#DFE9F8" />
color="#DFE9F8" />
</el-icon> </el-icon>
</div> </div>
</div> </div>
@ -52,15 +43,11 @@
<p class="tips">选择需要购买的投放渠道</p> <p class="tips">选择需要购买的投放渠道</p>
<div class="route"> <div class="route">
<p class="text">{百度广告类型}单次广告价格为{}适用于{}次扫单</p> <p class="text">{百度广告类型}单次广告价格为{}适用于{}次扫单</p>
<el-input-number v-model="num" <el-input-number v-model="num" :min="1" :max="10" />
:min="1"
:max="10" />
</div> </div>
<div class="route"> <div class="route">
<p class="text">{百度广告类型}单次广告价格为{}适用于{}次扫单</p> <p class="text">{百度广告类型}单次广告价格为{}适用于{}次扫单</p>
<el-input-number v-model="num" <el-input-number v-model="num" :min="1" :max="10" />
:min="1"
:max="10" />
</div> </div>
</div> </div>
</div> </div>
@ -77,50 +64,37 @@
</div> </div>
</div> </div>
<el-dialog v-model="productVisible" <el-dialog v-model="productVisible" title="选择需要发布的银行产品" width="1000px" center>
title="选择需要发布的银行产品"
width="1000px"
center>
<div class="flex justify-between mb-4"> <div class="flex justify-between mb-4">
<search v-model="keyword"></search> <search v-model="keyword"></search>
<el-checkbox label="仅查看未发布的产品" /> <el-checkbox label="仅查看未发布的产品" />
</div> </div>
<el-table ref="table" <el-table ref="table" v-loading="loading" :data="list">
v-loading="loading" <el-table-column prop="productNumber" label="产品名称"></el-table-column>
:data="list"> <el-table-column prop="productNumber" label="产品编号"></el-table-column>
<el-table-column prop="productNumber" <el-table-column prop="productNumber" label="产品对象"></el-table-column>
label="产品名称"></el-table-column> <el-table-column prop="parentIds" label="担保方式"></el-table-column>
<el-table-column prop="productNumber" <el-table-column prop="parentIds" label="贷款用途"></el-table-column>
label="产品编号"></el-table-column> <el-table-column prop="loanCeiling" label="最高额度/年利率/期限"></el-table-column>
<el-table-column prop="productNumber" <el-table-column prop="createTime" label="创建日期"></el-table-column>
label="产品对象"></el-table-column> <el-table-column prop="status" label="状态"></el-table-column>
<el-table-column prop="parentIds"
label="担保方式"></el-table-column>
<el-table-column prop="parentIds"
label="贷款用途"></el-table-column>
<el-table-column prop="loanCeiling"
label="最高额度/年利率/期限"></el-table-column>
<el-table-column prop="createTime"
label="创建日期"></el-table-column>
<el-table-column prop="status"
label="状态"></el-table-column>
</el-table> </el-table>
<el-pagination v-model:currentPage="currentPage" <el-pagination
v-model:pageSize="pageSize" v-model:currentPage="currentPage"
:total="total" v-model:pageSize="pageSize"
:page-sizes="pageSizes" :total="total"
:layout="pageLayout" :page-sizes="pageSizes"
@size-change="fetchData()" :layout="pageLayout"
@current-change="fetchData()" @size-change="fetchData()"
small @current-change="fetchData()"
background small
class="px-3 py-2 justify-end"></el-pagination> background
class="px-3 py-2 justify-end"
></el-pagination>
<template #footer> <template #footer>
<span class="flex justify-center"> <span class="flex justify-center">
<div class="dia-btn mr-3 cancel" <div class="dia-btn cancel" @click="productVisible = false">取消</div>
@click="productVisible = false">取消</div> <div class="dia-btn" @click="productVisible = false">确定</div>
<div class="dia-btn"
@click="productVisible = false">确定</div>
</span> </span>
</template> </template>
</el-dialog> </el-dialog>

@ -1,173 +0,0 @@
<template>
<!-- 五级分类 -->
<el-table class="c-table"
:data="form"
:span-method="span"
:cell-style="{background:'#fff'}"
border>
<el-table-column prop="recordName"
label="产品类别"
min-width="150"
align="center">
</el-table-column>
<el-table-column label="逾期时间"
align="center">
<el-table-column label="未逾期"
align="center">
<template #default="{ row }">
<el-select clearable
v-model="row.notOverdue">
<el-option v-for="item in row.recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</template>
</el-table-column>
<el-table-column label="1~30天"
align="center">
<template #default="{ row }">
<el-select clearable
v-model="row.thirtyDays">
<el-option v-for="item in row.recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</template></el-table-column>
<el-table-column label="31~90天"
align="center">
<template #default="{ row }">
<el-select clearable
v-model="row.ninetyDays">
<el-option v-for="item in row.recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</template></el-table-column>
<el-table-column label="91~180天"
align="center">
<template #default="{ row }">
<el-select clearable
v-model="row.oneHundredAndEightyDays">
<el-option v-for="item in row.recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</template></el-table-column>
<el-table-column label="181~360天"
align="center">
<template #default="{ row }">
<el-select clearable
v-model="row.threeHundredAndSixtyDays">
<el-option v-for="item in row.recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</template></el-table-column>
<el-table-column label="360天以上"
align="center">
<template #default="{ row }">
<el-select clearable
v-model="row.threeHundredAndSixtyDaysAbove">
<el-option v-for="item in row.recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</template></el-table-column>
</el-table-column>
</el-table>
<div class="flex justify-end">
<div class="submit"
@click="submit">确认完成配置</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { fiveLevelClassificationDetails, fiveLevelClassificationSave } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import { handleId, getIds } from '@/utils/common';
import Cookies from 'js-cookie';
const projectId = +Cookies.get('sand-projectId');
const levelId = +Cookies.get('sand-level');
const form = ref<Record<string, any>[]>([]);
const info = ref<Record<string, any>[]>([]);
//
const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(1029);
const result = [];
process.map((e, i) => {
const cur = info.value.length ? info.value[i] : {};
result.push({
...getIds(),
recordName: e.name,
recordChildren: e.recordChildren,
ninetyDays: +cur.ninetyDays || '',
notOverdue: +cur.notOverdue || '',
oneHundredAndEightyDays: +cur.oneHundredAndEightyDays || '',
thirtyDays: +cur.thirtyDays || '',
threeHundredAndSixtyDays: +cur.threeHundredAndSixtyDays || '',
threeHundredAndSixtyDaysAbove: +cur.threeHundredAndSixtyDaysAbove || '',
id: cur.id || '',
stRecordId: e.id,
});
});
form.value = result;
};
//
const getDetail = async () => {
try {
const { data } = await fiveLevelClassificationDetails();
info.value = data;
getConfig();
} finally {
}
};
const fieldKeys = ['notOverdue', 'thirtyDays', 'ninetyDays', 'oneHundredAndEightyDays', 'threeHundredAndSixtyDays', 'threeHundredAndSixtyDaysAbove'];
//
const addRecord = async (data: Record<string, any>) => {
const preIds = `1,${levelId},42,69,1029`; // 1id
const rule = [];
data.map((e) => {
e.recordChildren.forEach((n, i) => {
e[fieldKeys[i]] && rule.push(handleId(n.id, n.subjectId, e[fieldKeys[i]], `${preIds},${e.stRecordId},${n.id}`, 1));
});
});
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: rule,
});
};
//
const submit = async () => {
let param = JSON.parse(JSON.stringify(form.value));
const recordParam = JSON.parse(JSON.stringify(param));
param.map((e) => {
delete e.recordChildren;
});
await fiveLevelClassificationSave({ fiveLevelClassificationList: param });
addRecord(recordParam);
getDetail();
ElMessage.success('提交成功!');
};
onMounted(() => {
getDetail();
});
</script>
<style lang="scss" scoped>
@import url(../../../styles/form.scss);
</style>

@ -0,0 +1,194 @@
<template>
<!-- 五级分类 -->
<el-form label-width="90px" label-suffix="" class="form" :disabled="disabled" v-loading="loading">
<el-form-item label="策略名称">
<div>
<el-input class="w-[320px]" placeholder="请输入20以内字符" maxlength="20" clearable v-model="strategyName" />
<p v-if="bankIds.length" class="text-danger">不同步已关联产品请修改策略名称</p>
</div>
</el-form-item>
<el-form-item label="策略规则">
<el-table class="c-table" :data="form" :cell-style="{ background: '#fff' }" border>
<el-table-column prop="recordName" label="产品类别" min-width="150" align="center"> </el-table-column>
<el-table-column label="逾期时间" align="center">
<el-table-column label="未逾期" align="center">
<template #default="{ row }">
<el-select clearable v-model="row.notOverdue">
<el-option v-for="item in row.recordChildren[0].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
</template>
</el-table-column>
<el-table-column label="1~30天" align="center">
<template #default="{ row }">
<el-select clearable v-model="row.thirtyDays">
<el-option v-for="item in row.recordChildren[0].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select> </template
></el-table-column>
<el-table-column label="31~90天" align="center">
<template #default="{ row }">
<el-select clearable v-model="row.ninetyDays">
<el-option v-for="item in row.recordChildren[0].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select> </template
></el-table-column>
<el-table-column label="91~180天" align="center">
<template #default="{ row }">
<el-select clearable v-model="row.oneHundredAndEightyDays">
<el-option v-for="item in row.recordChildren[0].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select> </template
></el-table-column>
<el-table-column label="181~360天" align="center">
<template #default="{ row }">
<el-select clearable v-model="row.threeHundredAndSixtyDays">
<el-option v-for="item in row.recordChildren[0].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select> </template
></el-table-column>
<el-table-column label="360天以上" align="center">
<template #default="{ row }">
<el-select clearable v-model="row.threeHundredAndSixtyDaysAbove">
<el-option v-for="item in row.recordChildren[0].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select> </template
></el-table-column>
</el-table-column>
</el-table>
</el-form-item>
<div v-if="!disabled" class="flex justify-end mt-3">
<div class="dia-btn cancel" @click="emit('close')">取消</div>
<div class="dia-btn" @click="confirmSubmit">确定</div>
</div>
</el-form>
<Confirm v-model="syncVisible" @submit="submit" />
</template>
<script setup lang="ts">
import { ref, defineAsyncComponent, onMounted, toRefs } from 'vue';
import { ElMessage } from 'element-plus';
import { fiveLevelClassificationDetails, fiveLevelClassificationSave, isTheStrategyRelatedToTheProduct } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import { handleId, getIds } from '@/utils/common';
import Cookies from 'js-cookie';
import { getStat } from '@/store/useProduct';
const Confirm = defineAsyncComponent(() => import('@/components/StrategyConfirm.vue'));
const props = defineProps({
disabled: { type: Boolean, default: false },
row: { type: Object },
});
const emit = defineEmits(['close']);
const { strategyId, strategyName } = toRefs(props.row);
const form = ref<Record<string, any>[]>([]);
const info = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const syncVisible = ref<boolean>(false);
const bankIds = ref<Record<string, any>[]>([]);
//
const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(1029);
const result = [];
process.slice(1).map((e, i) => {
const cur = info.value.length ? info.value[i] : {};
result.push({
...getIds(),
recordName: e.name,
recordChildren: e.recordChildren,
ninetyDays: +cur.ninetyDays || '',
notOverdue: +cur.notOverdue || '',
oneHundredAndEightyDays: +cur.oneHundredAndEightyDays || '',
thirtyDays: +cur.thirtyDays || '',
threeHundredAndSixtyDays: +cur.threeHundredAndSixtyDays || '',
threeHundredAndSixtyDaysAbove: +cur.threeHundredAndSixtyDaysAbove || '',
id: cur.id || '',
stRecordId: e.id,
});
});
form.value = result;
loading.value = false;
};
//
const getDetail = async () => {
loading.value = true;
try {
if (strategyId.value) {
const { data } = await fiveLevelClassificationDetails({
strategyId: strategyId.value,
});
info.value = data;
}
getConfig();
//
if (strategyId.value && !props.disabled) {
const res = await isTheStrategyRelatedToTheProduct({
tacticsId: strategyId.value,
strategyType: 14,
});
if (res.isRelated) bankIds.value = res.bankIds;
}
} finally {
}
};
onMounted(getDetail);
const fieldKeys = ['notOverdue', 'thirtyDays', 'ninetyDays', 'oneHundredAndEightyDays', 'threeHundredAndSixtyDays', 'threeHundredAndSixtyDaysAbove'];
//
const addRecord = async (data: Record<string, any>) => {
const preIds = `1,${Cookies.get('sand-level')},42,69,1029`; // 1id
const rule = [handleId(140, 28, strategyName.value, `${preIds},140`, 3)];
data.map((e) => {
e.recordChildren.forEach((n, i) => {
e[fieldKeys[i]] && rule.push(handleId(n.id, n.subjectId, e[fieldKeys[i]], `${preIds},${e.stRecordId},${n.id}`, 1));
});
});
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: rule,
});
loading.value = false;
ElMessage.success('提交成功!');
syncVisible.value = false;
emit('close', 1);
};
//
const submit = async (synchronizeUpdate?: number) => {
loading.value = true;
try {
const param = JSON.parse(JSON.stringify(form.value));
const recordParam = JSON.parse(JSON.stringify(param));
param.map((e) => {
delete e.recordChildren;
});
await fiveLevelClassificationSave({
...getIds(),
strategyId: strategyId.value,
strategyName: strategyName.value,
synchronizeUpdate,
fiveLevelClassificationList: param,
bankIds: bankIds.value,
});
getStat(295);
addRecord(recordParam);
} catch (e) {
loading.value = false;
}
};
const confirmSubmit = async () => {
if (!strategyName.value) return ElMessage.error('请输入策略名称!');
//
if (bankIds.value.length) {
syncVisible.value = true;
} else {
submit();
}
};
</script>
<style lang="scss" scoped>
@import url(../../../../styles/form.scss);
</style>

@ -0,0 +1,157 @@
<template>
<div class="block">
<div class="flex justify-between items-center mb-5">
<search v-model="keyWord" @change="initList"></search>
<div class="filter">
<el-popconfirm title="确定删除选中策略吗?" :disabled="!multipleSelection.length" @confirm.stop="delAll">
<template #reference>
<div :class="['add-btn mr-2', { 'cursor-not-allowed': !multipleSelection.length }]">
<el-icon :size="24" color="#fff">
<Delete />
</el-icon>
批量删除
</div>
</template>
</el-popconfirm>
<div class="add-btn" @click="toAdd">
<img src="@/assets/images/plus.png" alt="" class="icon" />
新增
</div>
</div>
</div>
<el-table ref="table" v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" :selectable="handleDisable" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column prop="strategyName" label="五级分类策略名称" min-width="180" />
<el-table-column prop="createTime" label="新增日期" min-width="140" />
<el-table-column label="操作" width="140">
<template #default="{ row }">
<el-button type="primary" link @click="toDetail(row, true)" size="small">查看</el-button>
<template v-if="!row.builtIn">
<el-button type="primary" link @click="toDetail(row)" size="small">编辑</el-button>
<el-popconfirm title="确定删除这条策略吗?" @confirm.stop="handleDelete([row.strategyId])">
<template #reference>
<el-button type="primary" link size="small">删除</el-button>
</template>
</el-popconfirm>
</template>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:total="total"
:page-sizes="pageSizes"
:layout="pageLayout"
@size-change="getList()"
@current-change="getList()"
small
background
class="px-3 py-2 justify-end"
></el-pagination>
<el-drawer v-model="visible" :title="(isDetail ? '查看' : curRow.strategyId ? '编辑' : '新增') + '五级分类策略'" size="100%" :z-index="10" class="model-drawer">
<Detail v-model:row="curRow" :disabled="isDetail" :key="i" @close="closeDrawer" />
</el-drawer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, watch, defineAsyncComponent } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Delete } from '@element-plus/icons-vue';
import { pageSizes, pageLayout } from '@/utils/common';
import { fiveLevelClassification, fiveLevelClassificationDel } from '@/api/model';
import Search from '@/components/Search.vue';
const Detail = defineAsyncComponent(() => import('./Detail.vue'));
const keyWord = ref<string>();
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);
const total = ref<number>(0);
const table = ref<any>();
const multipleSelection = ref<Record<string, any>[]>([]);
const list = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const visible = ref<boolean>(false);
const curRow = ref<Record<string, any>>({
strategyId: '',
strategyName: '',
});
const isDetail = ref<boolean>(false);
const i = ref<number>(0);
//
const getList = async () => {
loading.value = true;
try {
const { page } = await fiveLevelClassification({ pageNum: currentPage.value, pageSize: pageSize.value, keyWord: keyWord.value });
list.value = page.records;
total.value = page.total;
} finally {
loading.value = false;
}
};
//
const initList = async () => {
currentPage.value = 1;
getList();
};
watch(keyWord, initList);
onMounted(getList);
//
const handleDisable = (row: Record<string, any>) => {
//
if (row.builtIn) return false;
return true;
};
//
const handleSelectionChange = (val: Record<string, any>[]) => {
multipleSelection.value = val;
};
const handleDelete = async (ids: number[]) => {
try {
const res = await fiveLevelClassificationDel({ ids });
//
if (res.tip) {
ElMessageBox.alert(res.message, '提示', {
confirmButtonText: '确定',
});
} else {
getList();
ElMessage.success('删除成功!');
}
} catch (e) {}
};
//
const delAll = async () => {
handleDelete(multipleSelection.value.map((e) => e.strategyId));
};
//
const toAdd = () => {
i.value++;
isDetail.value = false;
curRow.value = {
strategyId: '',
strategyName: '',
};
visible.value = true;
};
//
const toDetail = async (row: Record<string, any>, detail = false) => {
i.value++;
isDetail.value = detail;
curRow.value = row;
visible.value = true;
};
//
const closeDrawer = (refresh?: number) => {
visible.value = false;
refresh && initList();
};
</script>

@ -1,186 +0,0 @@
<template>
<!-- 贷后检查 -->
<div class="c-auto">
<el-table class="c-table"
:data="form"
:cell-style="{background:'#fff'}"
border>
<el-table-column prop="name"
label="选用"
width="100"
align="center">
<template #default="{ row }">
<el-checkbox v-model="row.isChoose"></el-checkbox>
</template>
</el-table-column>
<el-table-column prop="recordName"
label="检查方式"
min-width="150"
align="center"></el-table-column>
<el-table-column label="检查对象"
min-width="200"
align="center">
<template #default="{ row }">
<el-select v-if="row.recordChildren"
clearable
v-model="row.checkObject">
<el-option v-for="item in row?.recordChildren[1].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</template>
</el-table-column>
<el-table-column label="检查时间"
min-width="270"
align="center">
<template #default="{ row, $index }">
<span v-if="$index === 4">点击后触发</span>
<div v-else
class="flex items-center">
<el-select v-if="row.recordChildren"
clearable
v-model="row.checkTimeType">
<el-option v-for="item in row?.recordChildren[2].recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
<el-input class="w-[100px] mx-2"
placeholder="请输入"
v-model="row.timeDays"></el-input>
</div>
</template>
</el-table-column>
<el-table-column label="检查内容"
min-width="230"
align="center">
<template #default="{ row }">
<el-checkbox v-model="row.governmentData">政务数据</el-checkbox>
<el-checkbox v-model="row.creditData">征信数据</el-checkbox>
</template>
</el-table-column>
</el-table>
</div>
<div class="flex justify-end">
<div class="submit"
@click="submit">确认完成配置</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { postLoanInspectionDetails, postLoanInspectionSave } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import type { TableColumnCtx } from 'element-plus';
import { handleId, getIds } from '@/utils/common';
import Cookies from 'js-cookie';
const form = ref<Record<string, any>[]>([]);
const info = ref<Record<string, any>[]>([]);
//
const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(1030);
const result = [];
process.map((e, i) => {
const cur = info.value.length ? info.value[i] : {};
let temp = {
...getIds(),
recordName: e.name,
recordChildren: e.recordChildren,
checkObject: +cur.checkObject || '',
checkTimeType: +cur.checkTimeType || '',
creditData: info.value.length ? !!cur.creditData : false,
governmentData: info.value.length ? !!cur.governmentData : false,
isChoose: info.value.length ? !!cur.isChoose : false,
timeDays: cur.timeDays || '',
id: cur.id || '',
stRecordId: e.id,
};
result.push(temp);
});
form.value = result;
};
//
const getDetail = async () => {
try {
const { data } = await postLoanInspectionDetails();
info.value = data;
getConfig();
} finally {
}
};
interface SpanMethodProps {
row: Record<string, any>;
column: TableColumnCtx<Record<string, any>>;
rowIndex: number;
columnIndex: number;
}
//
const span = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
if (columnIndex < 2) {
if (rowIndex === 1) {
return {
rowspan: 2,
colspan: 1,
};
} else if (rowIndex === 2) {
return {
rowspan: 0,
colspan: 0,
};
}
}
};
//
const addRecord = async (data: Record<string, any>) => {
console.log('🚀 ~ addRecord ~ data:', data);
const preIds = `1,${Cookies.get('sand-level')},42,69,1030`; // 1id
const rule = [];
data.forEach((e, i) => {
e.isChoose && rule.push(handleId(1052, '', '', preIds + ',' + e.stRecordId + ',1052', ''));
e.checkObject && rule.push(handleId(1053, 282, e.checkObject, preIds + ',' + e.stRecordId + ',1053', 1));
i !== 4 && e.checkTimeType && rule.push(handleId(1054, 283, e.checkTimeType, preIds + ',' + e.stRecordId + ',1054,1056', 1));
e.timeDays && rule.push(handleId(1057, 284, e.timeDays, preIds + ',' + e.stRecordId + ',1054,1057', 3));
const ids = [];
e.governmentData && ids.push(778);
e.creditData && ids.push(793);
e.governmentData && rule.push(handleId(1055, 323, ids.join(), preIds + ',' + e.stRecordId + ',1055', 1));
});
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: rule,
});
};
//
const submit = async () => {
let param = JSON.parse(JSON.stringify(form.value));
param.map((e, i) => {
e.creditData = +e.creditData;
e.governmentData = +e.governmentData;
e.isChoose = +e.isChoose;
});
const recordParam = JSON.parse(JSON.stringify(param));
param.map((e) => {
delete e.recordChildren;
});
await postLoanInspectionSave({ postLoanInspectionList: param });
addRecord(recordParam);
getDetail();
ElMessage.success('提交成功!');
};
onMounted(() => {
getDetail();
});
</script>
<style lang="scss" scoped>
@import url(../../../styles/form.scss);
</style>

@ -0,0 +1,219 @@
<template>
<!-- 贷后检查 -->
<el-form label-width="90px" label-suffix="" class="form" :disabled="disabled" v-loading="loading">
<el-form-item label="策略名称">
<div>
<el-input class="w-[320px]" placeholder="请输入20以内字符" maxlength="20" clearable v-model="strategyName" />
<p v-if="bankIds.length" class="text-danger">不同步已关联产品请修改策略名称</p>
</div>
</el-form-item>
<el-form-item label="策略规则">
<el-table class="c-table" :data="form" :cell-style="{ background: '#fff' }" border>
<el-table-column prop="name" label="选用" width="130" align="center">
<template #default="{ row }">
<el-radio-group v-model="row.isChoose">
<el-radio v-for="(item, i) in opt1" :key="i" :label="item.id">{{ item.name }}</el-radio>
</el-radio-group>
</template>
</el-table-column>
<el-table-column prop="recordName" label="检查方式" min-width="150" align="center"></el-table-column>
<el-table-column label="检查对象" min-width="200" align="center">
<template #default="{ row }">
<el-select v-if="row.recordChildren" clearable v-model="row.checkObject">
<el-option v-for="item in row?.recordChildren[1].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
</template>
</el-table-column>
<el-table-column label="检查时间" min-width="270" align="center">
<template #default="{ row, $index }">
<span v-if="$index === 4">点击后触发</span>
<div v-else class="flex items-center">
<el-select v-if="row.recordChildren" clearable v-model="row.checkTimeType">
<el-option v-for="item in row?.recordChildren[2].recordChildren[0].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
<el-input class="w-[100px] mx-2" placeholder="请输入" v-model="row.timeDays"></el-input>
</div>
</template>
</el-table-column>
<el-table-column label="检查内容" min-width="230" align="center">
<template #default="{ row }">
<el-checkbox v-model="row.governmentData">政务数据</el-checkbox>
<el-checkbox v-model="row.creditData">征信数据</el-checkbox>
</template>
</el-table-column>
</el-table>
</el-form-item>
<div v-if="!disabled" class="flex justify-end mt-3">
<div class="dia-btn cancel" @click="emit('close')">取消</div>
<div class="dia-btn" @click="confirmSubmit">确定</div>
</div>
</el-form>
<Confirm v-model="syncVisible" @submit="submit" />
</template>
<script setup lang="ts">
import { ref, defineAsyncComponent, onMounted, toRefs } from 'vue';
import { ElMessage } from 'element-plus';
import { postLoanInspectionDetails, postLoanInspectionSave, isTheStrategyRelatedToTheProduct } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import type { TableColumnCtx } from 'element-plus';
import { handleId, getIds, opt1 } from '@/utils/common';
import Cookies from 'js-cookie';
import { getStat } from '@/store/useProduct';
const Confirm = defineAsyncComponent(() => import('@/components/StrategyConfirm.vue'));
const props = defineProps({
disabled: { type: Boolean, default: false },
row: { type: Object },
});
const emit = defineEmits(['close']);
const { strategyId, strategyName } = toRefs(props.row);
const form = ref<Record<string, any>[]>([]);
const info = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const syncVisible = ref<boolean>(false);
const bankIds = ref<Record<string, any>[]>([]);
//
const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(1030);
const result = [];
process.slice(1).map((e, i) => {
const cur = info.value.length ? info.value[i] : {};
const temp = {
...getIds(),
recordName: e.name,
recordChildren: e.recordChildren,
checkObject: +cur.checkObject || '',
checkTimeType: +cur.checkTimeType || '',
creditData: info.value.length ? !!cur.creditData : false,
governmentData: info.value.length ? !!cur.governmentData : false,
isChoose: info.value.length ? cur.isChoose : '',
timeDays: cur.timeDays || '',
id: cur.id || '',
stRecordId: e.id,
};
result.push(temp);
});
form.value = result;
loading.value = false;
};
//
const getDetail = async () => {
loading.value = true;
try {
if (strategyId.value) {
const { data } = await postLoanInspectionDetails({
strategyId: strategyId.value,
});
info.value = data;
}
getConfig();
//
if (strategyId.value && !props.disabled) {
const res = await isTheStrategyRelatedToTheProduct({
tacticsId: strategyId.value,
strategyType: 15,
});
if (res.isRelated) bankIds.value = res.bankIds;
}
} finally {
}
};
onMounted(getDetail);
interface SpanMethodProps {
row: Record<string, any>;
column: TableColumnCtx<Record<string, any>>;
rowIndex: number;
columnIndex: number;
}
//
const span = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
if (columnIndex < 2) {
if (rowIndex === 1) {
return {
rowspan: 2,
colspan: 1,
};
}
if (rowIndex === 2) {
return {
rowspan: 0,
colspan: 0,
};
}
}
};
//
const addRecord = async (data: Record<string, any>) => {
const preIds = `1,${Cookies.get('sand-level')},42,69,1030`; // 1id
const rule = [handleId(140, 28, strategyName.value, `${preIds},140`, 3)];
data.forEach((e, i) => {
e.isChoose && rule.push(handleId(1052, 140, e.isChoose, `${preIds},${e.stRecordId},1052`, 1));
e.checkObject && rule.push(handleId(1053, 282, e.checkObject, `${preIds},${e.stRecordId},1053`, 1));
i !== 4 && e.checkTimeType && rule.push(handleId(1054, 283, e.checkTimeType, `${preIds},${e.stRecordId},1054,1056`, 1));
e.timeDays && rule.push(handleId(1057, 284, e.timeDays, `${preIds},${e.stRecordId},1054,1057`, 3));
const ids = [];
e.governmentData && ids.push(778);
e.creditData && ids.push(793);
e.governmentData && rule.push(handleId(1055, 323, ids.join(), `${preIds},${e.stRecordId},1055`, 1));
});
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: rule,
});
loading.value = false;
ElMessage.success('提交成功!');
syncVisible.value = false;
emit('close', 1);
};
//
const submit = async (synchronizeUpdate?: number) => {
loading.value = true;
try {
const param = JSON.parse(JSON.stringify(form.value));
param.map((e, i) => {
e.creditData = +e.creditData;
e.governmentData = +e.governmentData;
});
const recordParam = JSON.parse(JSON.stringify(param));
param.map((e) => {
delete e.recordChildren;
});
await postLoanInspectionSave({
...getIds(),
strategyId: strategyId.value,
strategyName: strategyName.value,
synchronizeUpdate,
postLoanInspectionList: param,
bankIds: bankIds.value,
});
getStat(295);
addRecord(recordParam);
} catch (e) {
loading.value = false;
}
};
const confirmSubmit = async () => {
if (!strategyName.value) return ElMessage.error('请输入策略名称!');
//
if (bankIds.value.length) {
syncVisible.value = true;
} else {
submit();
}
};
</script>
<style lang="scss" scoped>
@import url(../../../../styles/form.scss);
</style>

@ -0,0 +1,157 @@
<template>
<div class="block">
<div class="flex justify-between items-center mb-5">
<search v-model="keyWord" @change="initList"></search>
<div class="filter">
<el-popconfirm title="确定删除选中策略吗?" :disabled="!multipleSelection.length" @confirm.stop="delAll">
<template #reference>
<div :class="['add-btn mr-2', { 'cursor-not-allowed': !multipleSelection.length }]">
<el-icon :size="24" color="#fff">
<Delete />
</el-icon>
批量删除
</div>
</template>
</el-popconfirm>
<div class="add-btn" @click="toAdd">
<img src="@/assets/images/plus.png" alt="" class="icon" />
新增
</div>
</div>
</div>
<el-table ref="table" v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" :selectable="handleDisable" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column prop="strategyName" label="贷后检查策略名称" min-width="180" />
<el-table-column prop="createTime" label="新增日期" min-width="140" />
<el-table-column label="操作" width="140">
<template #default="{ row }">
<el-button type="primary" link @click="toDetail(row, true)" size="small">查看</el-button>
<template v-if="!row.builtIn">
<el-button type="primary" link @click="toDetail(row)" size="small">编辑</el-button>
<el-popconfirm title="确定删除这条策略吗?" @confirm.stop="handleDelete([row.strategyId])">
<template #reference>
<el-button type="primary" link size="small">删除</el-button>
</template>
</el-popconfirm>
</template>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:total="total"
:page-sizes="pageSizes"
:layout="pageLayout"
@size-change="getList()"
@current-change="getList()"
small
background
class="px-3 py-2 justify-end"
></el-pagination>
<el-drawer v-model="visible" :title="(isDetail ? '查看' : curRow.strategyId ? '编辑' : '新增') + '贷后检查策略'" size="100%" :z-index="10" class="model-drawer">
<Detail v-model:row="curRow" :disabled="isDetail" :key="i" @close="closeDrawer" />
</el-drawer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, watch, defineAsyncComponent } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Delete } from '@element-plus/icons-vue';
import { pageSizes, pageLayout } from '@/utils/common';
import { postLoanInspection, postLoanInspectionDel } from '@/api/model';
import Search from '@/components/Search.vue';
const Detail = defineAsyncComponent(() => import('./Detail.vue'));
const keyWord = ref<string>();
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);
const total = ref<number>(0);
const table = ref<any>();
const multipleSelection = ref<Record<string, any>[]>([]);
const list = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const visible = ref<boolean>(false);
const curRow = ref<Record<string, any>>({
strategyId: '',
strategyName: '',
});
const isDetail = ref<boolean>(false);
const i = ref<number>(0);
//
const getList = async () => {
loading.value = true;
try {
const { page } = await postLoanInspection({ pageNum: currentPage.value, pageSize: pageSize.value, keyWord: keyWord.value });
list.value = page.records;
total.value = page.total;
} finally {
loading.value = false;
}
};
//
const initList = async () => {
currentPage.value = 1;
getList();
};
watch(keyWord, initList);
onMounted(getList);
//
const handleDisable = (row: Record<string, any>) => {
//
if (row.builtIn) return false;
return true;
};
//
const handleSelectionChange = (val: Record<string, any>[]) => {
multipleSelection.value = val;
};
const handleDelete = async (ids: number[]) => {
try {
const res = await postLoanInspectionDel({ ids });
//
if (res.tip) {
ElMessageBox.alert(res.message, '提示', {
confirmButtonText: '确定',
});
} else {
getList();
ElMessage.success('删除成功!');
}
} catch (e) {}
};
//
const delAll = async () => {
handleDelete(multipleSelection.value.map((e) => e.strategyId));
};
//
const toAdd = () => {
i.value++;
isDetail.value = false;
curRow.value = {
strategyId: '',
strategyName: '',
};
visible.value = true;
};
//
const toDetail = async (row: Record<string, any>, detail = false) => {
i.value++;
isDetail.value = detail;
curRow.value = row;
visible.value = true;
};
//
const closeDrawer = (refresh?: number) => {
visible.value = false;
refresh && initList();
};
</script>

@ -1,344 +0,0 @@
<template>
<!-- 贷后评分 -->
<el-table class="c-table"
:data="form"
:span-method="span"
:cell-style="{background:'#fff'}"
border>
<el-table-column prop="recordName"
label="指标"
min-width="80"
align="center"></el-table-column>
<el-table-column prop="recordName"
label="公式/取值"
min-width="200"
align="center">
<template #default="{ row, $index }">
<div class="flex items-center">
<template v-if="$index === 1">
存贷比 =
<div class="inline-flex flex-col justify-center mx-2">
<el-select v-if="row.recordChildren"
class="w-[140px]"
clearable
v-model="row.formulaOne">
<el-option v-for="item in row?.recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
<p class="h-[1px] my-2 bg-[#cdcdcd]"></p>
<el-select v-if="row.recordChildren"
class="w-[140px]"
clearable
v-model="row.formulaTwo">
<el-option v-for="item in row?.recordChildren[1].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</div>
x 100%
</template>
<template v-if="$index === 6">
房屋净值 =
<el-select v-if="row.recordChildren"
class="w-[140px] mx-2"
clearable
v-model="row.formulaOne">
<el-option v-for="item in row?.recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
-
<el-select v-if="row.recordChildren"
class="w-[140px] ml-2"
clearable
v-model="row.formulaTwo">
<el-option v-for="item in row?.recordChildren[1].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</template>
<template v-if="$index === 9">
<el-input class="w-[80px] mx-2"
placeholder="请输入"
v-model="row.formulaOne"></el-input>
<el-select v-if="row.recordChildren"
class="w-[140px] mr-2"
clearable
v-model="row.formulaTwo">
<el-option v-for="item in row?.recordChildren[1].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
内逾期次数
</template>
<template v-if="$index === 12">
<el-select v-if="row.recordChildren"
class="w-[140px] mx-2"
clearable
v-model="row.formulaOne">
<el-option v-for="item in row?.recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
开始算还款当天不计算利息
</template>
<template v-if="$index === 15">当前尚未偿还的贷款总额</template>
<template v-if="$index === 18">
平均额度使用率 =
<div class="inline-flex flex-col justify-center mx-2">
<el-select v-if="row.recordChildren"
class="w-[140px]"
clearable
v-model="row.formulaOne">
<el-option v-for="item in row?.recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
<p class="h-[1px] my-2 bg-[#cdcdcd]"></p>
<el-select v-if="row.recordChildren"
class="w-[140px]"
clearable
v-model="row.formulaTwo">
<el-option v-for="item in row?.recordChildren[1].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</div>
x 100%
</template>
<template v-if="$index === 22">
最大用信率 =
<div class="inline-flex flex-col justify-center mx-2">
<el-select v-if="row.recordChildren"
class="w-[140px]"
clearable
v-model="row.formulaOne">
<el-option v-for="item in row?.recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
<p class="h-[1px] my-2 bg-[#cdcdcd]"></p>
<el-select v-if="row.recordChildren"
class="w-[140px]"
clearable
v-model="row.formulaTwo">
<el-option v-for="item in row?.recordChildren[1].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</div>
x 100%
</template>
<template v-if="$index === 26">到目前为止使用额度的次数</template>
<template v-if="$index === 30">到目前为止客户可以使用的最大额度</template>
<template v-if="$index === 35">客户贷记卡已经逾期的总月数</template>
<template v-if="$index === 37">客户在行所有贷款已经逾期的总月数</template>
</div>
</template>
</el-table-column>
<el-table-column prop="ruleName"
label="取值"
min-width="100"
align="center"></el-table-column>
<el-table-column label="分数"
min-width="80"
align="center">
<template #default="{ row }">
<el-select v-if="row.subject"
clearable
v-model="row.score">
<el-option v-for="item in row.subject.itemList.sort((a, b) => +a.options - +b.options)"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
<span v-else>600</span>
</template>
</el-table-column>
</el-table>
<div class="flex justify-end">
<div class="submit"
@click="submit">确认完成配置</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { postCreditScoreDetails, postCreditScoreSave } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import type { TableColumnCtx } from 'element-plus';
import { handleId, getIds } from '@/utils/common';
import Cookies from 'js-cookie';
const form = ref<Record<string, any>[]>([]);
const info = ref<Record<string, any>[]>([]);
//
const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(1031);
const result = [
{
recordName: '基准分',
},
];
process.map((e, i) => {
let temp = {
...getIds(),
recordName: e.name,
recordChildren: e.recordChildren,
formulaOne: '',
formulaTwo: '',
score: '',
id: '',
stRecordId: e.id,
middleId: e.recordChildren[e.recordChildren.length - 1]?.id,
};
//
e.recordChildren[e.recordChildren.length - 1]?.recordChildren?.map((n, j) => {
temp = JSON.parse(JSON.stringify(temp));
temp.index = j;
temp.ruleName = n.name;
temp.subject = n.subject;
temp.ruleId = n.id;
result.push(temp);
});
});
if (info.value.length) {
result.forEach((e, i) => {
if (i) {
e.formulaOne = info.value[i - 1].formulaOne ? +info.value[i - 1].formulaOne : '';
e.indexId = info.value[i - 1].indexId;
e.formulaTwo = info.value[i - 1].formulaTwo ? +info.value[i - 1].formulaTwo : '';
e.score = info.value[i - 1].score ? +info.value[i - 1].score : '';
}
});
}
form.value = result;
console.log('🚀 ~ file: 1031.vue:83 ~ getConfig ~ result:', result);
};
//
const getDetail = async () => {
try {
const { data } = await postCreditScoreDetails();
info.value = data;
getConfig();
} finally {
}
};
interface SpanMethodProps {
row: Record<string, any>;
column: TableColumnCtx<Record<string, any>>;
rowIndex: number;
columnIndex: number;
}
const rowMerge1 = [1, 30];
const rowMerge2 = [6, 9, 12, 15];
const rowMerge3 = [9, 18, 22, 26];
const rowMerge4 = [35, 37];
//
const span = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
if (!rowIndex) {
if (!columnIndex) {
return {
rowspan: 1,
colspan: 3,
};
} else if (columnIndex === 3) {
return {
rowspan: 1,
colspan: 1,
};
} else {
return {
rowspan: 0,
colspan: 0,
};
}
}
if (columnIndex < 2) {
if (rowMerge1.includes(rowIndex)) {
return {
rowspan: 5,
colspan: 1,
};
} else if (rowMerge2.includes(rowIndex)) {
return {
rowspan: 3,
colspan: 1,
};
} else if (rowMerge3.includes(rowIndex)) {
return {
rowspan: 4,
colspan: 1,
};
} else if (rowMerge4.includes(rowIndex)) {
return {
rowspan: 2,
colspan: 1,
};
} else {
return {
rowspan: 0,
colspan: 0,
};
}
}
};
//
const addRecord = async (data: Record<string, any>) => {
const preIds = `1,${Cookies.get('sand-level')},42,69,1031`; // 1id
const rule = [];
data.forEach((e, i) => {
e.score && rule.push(handleId(e.ruleId, e.subject.subjectId, e.score, `${preIds},${e.stRecordId},${e.middleId},${e.ruleId}`, 1));
if (i === 1 || i === 6 || i === 18 || i === 22) {
e.formulaOne && rule.push(handleId(1061, 285, e.formulaOne, `${preIds},${e.stRecordId},1061`, 1));
e.formulaTwo && rule.push(handleId(1062, 285, e.formulaTwo, `${preIds},${e.stRecordId},1062`, 1));
}
});
data[9].formulaOne && rule.push(handleId(1075, 288, data[9].formulaOne, `${preIds},1074,1075`, 3));
data[9].formulaTwo && rule.push(handleId(1076, 289, data[9].formulaTwo, `${preIds},1074,1076`, 1));
data[12].formulaOne && rule.push(handleId(1083, 291, data[12].formulaOne, `${preIds},1082,1083`, 1));
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: rule,
});
};
//
const submit = async () => {
let param = JSON.parse(JSON.stringify(form.value));
const recordParam = JSON.parse(JSON.stringify(param));
param.map((e) => {
delete e.recordChildren;
});
await postCreditScoreSave({ postCreditScoreList: param });
addRecord(recordParam);
getDetail();
ElMessage.success('提交成功!');
};
onMounted(() => {
getDetail();
});
</script>
<style lang="scss" scoped>
@import url(../../../styles/form.scss);
</style>

@ -0,0 +1,336 @@
<template>
<!-- 贷后评分 -->
<el-form label-width="90px" label-suffix="" class="form" :disabled="disabled" v-loading="loading">
<el-form-item label="策略名称">
<div>
<el-input class="w-[320px]" placeholder="请输入20以内字符" maxlength="20" clearable v-model="strategyName" />
<p v-if="bankIds.length" class="text-danger">不同步已关联产品请修改策略名称</p>
</div>
</el-form-item>
<el-form-item label="策略规则">
<el-table class="c-table" :data="form" :span-method="span" :cell-style="{ background: '#fff' }" border>
<el-table-column prop="name" label="选用" width="130" align="center">
<template #default="{ row, $index }">
<el-radio-group v-if="$index" v-model="row.isChoose">
<el-radio v-for="(item, i) in opt1" :key="i" :label="item.id">{{ item.name }}</el-radio>
</el-radio-group>
<span v-else>基准分</span>
</template>
</el-table-column>
<el-table-column prop="recordName" label="指标" min-width="80" align="center"></el-table-column>
<el-table-column prop="recordName" label="公式/取值" min-width="200" align="center">
<template #default="{ row, $index }">
<div class="flex items-center">
<template v-if="$index === 1">
存贷比 =
<div class="inline-flex flex-col justify-center mx-2">
<el-select v-if="row.recordChildren" class="w-[140px]" clearable v-model="row.formulaOne" disabled>
<el-option v-for="item in row?.recordChildren[1].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
<p class="h-[1px] my-2 bg-[#cdcdcd]"></p>
<el-select v-if="row.recordChildren" class="w-[140px]" clearable v-model="row.formulaTwo" disabled>
<el-option v-for="item in row?.recordChildren[2].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
</div>
x 100%
</template>
<template v-if="$index === 6">
房屋净值 =
<el-select v-if="row.recordChildren" class="w-[140px] mx-2" clearable v-model="row.formulaOne" disabled>
<el-option v-for="item in row?.recordChildren[1].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
-
<el-select v-if="row.recordChildren" class="w-[140px] ml-2" clearable v-model="row.formulaTwo" disabled>
<el-option v-for="item in row?.recordChildren[2].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
</template>
<template v-if="$index === 9">
<el-input class="w-[80px] mx-2" placeholder="请输入" v-model="row.formulaOne" disabled></el-input>
<el-select v-if="row.recordChildren" class="w-[140px] mr-2" clearable v-model="row.formulaTwo" disabled>
<el-option v-for="item in row?.recordChildren[2].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
内逾期次数
</template>
<template v-if="$index === 12">
<el-select v-if="row.recordChildren" class="w-[140px] mx-2" clearable v-model="row.formulaOne" disabled>
<el-option v-for="item in row?.recordChildren[1].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
开始算还款当天不计算利息
</template>
<template v-if="$index === 15">当前尚未偿还的贷款总额</template>
<template v-if="$index === 18">
平均额度使用率 =
<div class="inline-flex flex-col justify-center mx-2">
<el-select v-if="row.recordChildren" class="w-[140px]" clearable v-model="row.formulaOne" disabled>
<el-option v-for="item in row?.recordChildren[1].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
<p class="h-[1px] my-2 bg-[#cdcdcd]"></p>
<el-select v-if="row.recordChildren" class="w-[140px]" clearable v-model="row.formulaTwo" disabled>
<el-option v-for="item in row?.recordChildren[2].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
</div>
x 100%
</template>
<template v-if="$index === 22">
最大用信率 =
<div class="inline-flex flex-col justify-center mx-2">
<el-select v-if="row.recordChildren" class="w-[140px]" clearable v-model="row.formulaOne" disabled>
<el-option v-for="item in row?.recordChildren[1].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
<p class="h-[1px] my-2 bg-[#cdcdcd]"></p>
<el-select v-if="row.recordChildren" class="w-[140px]" clearable v-model="row.formulaTwo" disabled>
<el-option v-for="item in row?.recordChildren[2].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
</div>
x 100%
</template>
<template v-if="$index === 26">到目前为止使用额度的次数</template>
<template v-if="$index === 30">到目前为止客户可以使用的最大额度</template>
<template v-if="$index === 35">客户贷记卡已经逾期的总月数</template>
<template v-if="$index === 37">客户在行所有贷款已经逾期的总月数</template>
</div>
</template>
</el-table-column>
<el-table-column prop="ruleName" label="取值" min-width="100" align="center"></el-table-column>
<el-table-column label="分数" min-width="80" align="center">
<template #default="{ row }">
<el-select v-if="row.subject" clearable v-model="row.score">
<el-option v-for="item in row.subject.itemList.sort((a, b) => +a.options - +b.options)" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
<span v-else>600</span>
</template>
</el-table-column>
</el-table>
</el-form-item>
<div v-if="!disabled" class="flex justify-end mt-3">
<div class="dia-btn cancel" @click="emit('close')">取消</div>
<div class="dia-btn" @click="confirmSubmit">确定</div>
</div>
</el-form>
<Confirm v-model="syncVisible" @submit="submit" />
</template>
<script setup lang="ts">
import { ref, defineAsyncComponent, onMounted, toRefs } from 'vue';
import { ElMessage } from 'element-plus';
import { postCreditScoreDetails, postCreditScoreSave, isTheStrategyRelatedToTheProduct } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import type { TableColumnCtx } from 'element-plus';
import { handleId, getIds, opt1 } from '@/utils/common';
import Cookies from 'js-cookie';
import { getStat } from '@/store/useProduct';
const Confirm = defineAsyncComponent(() => import('@/components/StrategyConfirm.vue'));
const props = defineProps({
disabled: { type: Boolean, default: false },
row: { type: Object },
});
const emit = defineEmits(['close']);
const { strategyId, strategyName } = toRefs(props.row);
const form = ref<Record<string, any>[]>([]);
const info = ref<Record<string, any>[]>([]);
//
const answer = [[697, 693], [698, 691], [1, 707], [716], [], [695, 696], [696, 694]];
const loading = ref<boolean>(false);
const syncVisible = ref<boolean>(false);
const bankIds = ref<Record<string, any>[]>([]);
//
const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(1031);
const result = [
{
recordName: '基准分',
},
];
process.slice(1).map((e, i) => {
let temp = {
...getIds(),
recordName: e.name,
recordChildren: e.recordChildren,
formulaOne: i < 7 ? answer[i][0] || '' : '',
formulaTwo: i < 7 ? answer[i][1] || '' : '',
score: '',
id: '',
stRecordId: e.id,
middleId: e.recordChildren[e.recordChildren.length - 1]?.id,
};
//
e.recordChildren[e.recordChildren.length - 1]?.recordChildren?.map((n, j) => {
temp = JSON.parse(JSON.stringify(temp));
temp.index = j;
temp.ruleName = n.name;
temp.subject = n.subject;
temp.ruleId = n.id;
temp.isChoose = '';
result.push(temp);
});
});
if (info.value.length) {
result.forEach((e, i) => {
if (i) {
e.indexId = info.value[i - 1].indexId;
e.isChoose = info.value[i - 1].isChoose;
e.score = info.value[i - 1].score ? +info.value[i - 1].score : '';
}
});
}
form.value = result;
loading.value = false;
};
//
const getDetail = async () => {
loading.value = true;
try {
if (strategyId.value) {
const { data } = await postCreditScoreDetails({
strategyId: strategyId.value,
});
info.value = data.slice(1);
}
getConfig();
//
if (strategyId.value && !props.disabled) {
const res = await isTheStrategyRelatedToTheProduct({
tacticsId: strategyId.value,
strategyType: 16,
});
if (res.isRelated) bankIds.value = res.bankIds;
}
} finally {
}
};
onMounted(getDetail);
interface SpanMethodProps {
row: Record<string, any>;
column: TableColumnCtx<Record<string, any>>;
rowIndex: number;
columnIndex: number;
}
const rowMerge1 = [1, 30];
const rowMerge2 = [6, 9, 12, 15];
const rowMerge3 = [9, 18, 22, 26];
const rowMerge4 = [35, 37];
//
const span = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
if (!rowIndex) {
if (!columnIndex) {
return {
rowspan: 1,
colspan: 4,
};
}
if (columnIndex === 4) {
return {
rowspan: 1,
colspan: 1,
};
}
return {
rowspan: 0,
colspan: 0,
};
}
if (columnIndex < 3) {
if (rowMerge1.includes(rowIndex)) {
return {
rowspan: 5,
colspan: 1,
};
}
if (rowMerge2.includes(rowIndex)) {
return {
rowspan: 3,
colspan: 1,
};
}
if (rowMerge3.includes(rowIndex)) {
return {
rowspan: 4,
colspan: 1,
};
}
if (rowMerge4.includes(rowIndex)) {
return {
rowspan: 2,
colspan: 1,
};
}
return {
rowspan: 0,
colspan: 0,
};
}
};
//
const addRecord = async (data: Record<string, any>) => {
const preIds = `1,${Cookies.get('sand-level')},42,69,1031`; // 1id
const rule = [handleId(140, 28, strategyName.value, `${preIds},140`, 3)];
data.forEach((e, i) => {
e.isChoose && rule.push(handleId(1052, 140, e.isChoose, `${preIds},${e.stRecordId},1052`, 1));
e.score && rule.push(handleId(e.ruleId, e.subject.subjectId, e.score, `${preIds},${e.stRecordId},${e.middleId},${e.ruleId}`, 1));
if (i === 1 || i === 6 || i === 18 || i === 22) {
e.formulaOne && rule.push(handleId(1061, 285, e.formulaOne, `${preIds},${e.stRecordId},1061`, 1));
e.formulaTwo && rule.push(handleId(1062, 285, e.formulaTwo, `${preIds},${e.stRecordId},1062`, 1));
}
});
data[9].formulaOne && rule.push(handleId(1075, 288, data[9].formulaOne, `${preIds},1074,1075`, 3));
data[9].formulaTwo && rule.push(handleId(1076, 289, data[9].formulaTwo, `${preIds},1074,1076`, 1));
data[12].formulaOne && rule.push(handleId(1083, 291, data[12].formulaOne, `${preIds},1082,1083`, 1));
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: rule,
});
loading.value = false;
ElMessage.success('提交成功!');
syncVisible.value = false;
emit('close', 1);
};
//
const submit = async (synchronizeUpdate?: number) => {
loading.value = true;
try {
const param = JSON.parse(JSON.stringify(form.value));
const recordParam = JSON.parse(JSON.stringify(param));
param.map((e) => {
delete e.recordChildren;
});
await postCreditScoreSave({
...getIds(),
strategyId: strategyId.value,
strategyName: strategyName.value,
synchronizeUpdate,
postCreditScoreList: param,
bankIds: bankIds.value,
});
getStat(295);
addRecord(recordParam);
} catch (e) {
loading.value = false;
}
};
const confirmSubmit = async () => {
if (!strategyName.value) return ElMessage.error('请输入策略名称!');
//
if (bankIds.value.length) {
syncVisible.value = true;
} else {
submit();
}
};
</script>
<style lang="scss" scoped>
@import url(../../../../styles/form.scss);
</style>

@ -0,0 +1,157 @@
<template>
<div class="block">
<div class="flex justify-between items-center mb-5">
<search v-model="keyWord" @change="initList"></search>
<div class="filter">
<el-popconfirm title="确定删除选中策略吗?" :disabled="!multipleSelection.length" @confirm.stop="delAll">
<template #reference>
<div :class="['add-btn mr-2', { 'cursor-not-allowed': !multipleSelection.length }]">
<el-icon :size="24" color="#fff">
<Delete />
</el-icon>
批量删除
</div>
</template>
</el-popconfirm>
<div class="add-btn" @click="toAdd">
<img src="@/assets/images/plus.png" alt="" class="icon" />
新增
</div>
</div>
</div>
<el-table ref="table" v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" :selectable="handleDisable" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column prop="strategyName" label="贷后评分策略名称" min-width="180" />
<el-table-column prop="createTime" label="新增日期" min-width="140" />
<el-table-column label="操作" width="140">
<template #default="{ row }">
<el-button type="primary" link @click="toDetail(row, true)" size="small">查看</el-button>
<template v-if="!row.builtIn">
<el-button type="primary" link @click="toDetail(row)" size="small">编辑</el-button>
<el-popconfirm title="确定删除这条策略吗?" @confirm.stop="handleDelete([row.strategyId])">
<template #reference>
<el-button type="primary" link size="small">删除</el-button>
</template>
</el-popconfirm>
</template>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:total="total"
:page-sizes="pageSizes"
:layout="pageLayout"
@size-change="getList()"
@current-change="getList()"
small
background
class="px-3 py-2 justify-end"
></el-pagination>
<el-drawer v-model="visible" :title="(isDetail ? '查看' : curRow.strategyId ? '编辑' : '新增') + '贷后评分策略'" size="100%" :z-index="10" class="model-drawer">
<Detail v-model:row="curRow" :disabled="isDetail" :key="i" @close="closeDrawer" />
</el-drawer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, watch, defineAsyncComponent } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Delete } from '@element-plus/icons-vue';
import { pageSizes, pageLayout } from '@/utils/common';
import { postCreditScore, postCreditScoreDel } from '@/api/model';
import Search from '@/components/Search.vue';
const Detail = defineAsyncComponent(() => import('./Detail.vue'));
const keyWord = ref<string>();
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);
const total = ref<number>(0);
const table = ref<any>();
const multipleSelection = ref<Record<string, any>[]>([]);
const list = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const visible = ref<boolean>(false);
const curRow = ref<Record<string, any>>({
strategyId: '',
strategyName: '',
});
const isDetail = ref<boolean>(false);
const i = ref<number>(0);
//
const getList = async () => {
loading.value = true;
try {
const { page } = await postCreditScore({ pageNum: currentPage.value, pageSize: pageSize.value, keyWord: keyWord.value });
list.value = page.records;
total.value = page.total;
} finally {
loading.value = false;
}
};
//
const initList = async () => {
currentPage.value = 1;
getList();
};
watch(keyWord, initList);
onMounted(getList);
//
const handleDisable = (row: Record<string, any>) => {
//
if (row.builtIn) return false;
return true;
};
//
const handleSelectionChange = (val: Record<string, any>[]) => {
multipleSelection.value = val;
};
const handleDelete = async (ids: number[]) => {
try {
const res = await postCreditScoreDel({ ids });
//
if (res.tip) {
ElMessageBox.alert(res.message, '提示', {
confirmButtonText: '确定',
});
} else {
getList();
ElMessage.success('删除成功!');
}
} catch (e) {}
};
//
const delAll = async () => {
handleDelete(multipleSelection.value.map((e) => e.strategyId));
};
//
const toAdd = () => {
i.value++;
isDetail.value = false;
curRow.value = {
strategyId: '',
strategyName: '',
};
visible.value = true;
};
//
const toDetail = async (row: Record<string, any>, detail = false) => {
i.value++;
isDetail.value = detail;
curRow.value = row;
visible.value = true;
};
//
const closeDrawer = (refresh?: number) => {
visible.value = false;
refresh && initList();
};
</script>

@ -1,130 +0,0 @@
<template>
<!-- 贷后预警 -->
<el-table class="c-table"
:data="form"
:cell-style="{background:'#fff'}"
border>
<el-table-column label="选用"
width="80"
align="center">
<template #default="{ row }">
<el-checkbox v-model="row.isChoose"></el-checkbox>
</template>
</el-table-column>
<el-table-column prop="recordName"
label="风险类型"
align="center"></el-table-column>
<el-table-column label="风险等级"
align="center">
<template #default="{ row }">
<div class="flex">
<el-select v-if="row.recordChildren"
class="mr-2"
clearable
v-model="row.riskGradeType">
<el-option v-for="item in row?.recordChildren[1].recordChildren[0].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
<el-select v-if="row.recordChildren"
clearable
v-model="row.riskGrade">
<el-option v-for="item in row?.recordChildren[1].recordChildren[1].subject.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select>
</div>
</template></el-table-column>
</el-table>
<div class="flex justify-end">
<div class="submit"
@click="submit">确认完成配置</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
import { postLoanWarningDetails, postLoanWarningSave } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import { handleId, getIds } from '@/utils/common';
import Cookies from 'js-cookie';
const projectId = +Cookies.get('sand-projectId');
const levelId = +Cookies.get('sand-level');
const form = ref<Record<string, any>[]>([]);
const info = ref<Record<string, any>[]>([]);
//
const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(1032);
const result = [];
process.map((e, i) => {
const cur = info.value.length ? info.value[i] : {};
result.push({
...getIds(),
recordName: e.name,
recordChildren: e.recordChildren,
riskGrade: +cur.riskGrade || '',
riskGradeType: +cur.riskGradeType || '',
isChoose: info.value.length ? !!cur.isChoose : false,
id: cur.id || '',
stRecordId: e.id,
});
});
form.value = result;
};
//
const getDetail = async () => {
try {
const { data } = await postLoanWarningDetails();
info.value = data;
getConfig();
} finally {
}
};
//
const addRecord = async (data: Record<string, any>) => {
const preIds = `1,${levelId},42,69,1032`; // 1id
const rule = [];
data.map((e) => {
e.isChoose && rule.push(handleId(1052, '', '', `${preIds},${e.stRecordId},1052`, ''));
e.riskGradeType && rule.push(handleId(1147, 299, e.riskGradeType, `${preIds},${e.stRecordId},1146,1147`, 1));
e.riskGrade && rule.push(handleId(1148, 300, e.riskGrade, `${preIds},${e.stRecordId},1146,1148`, 1));
});
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: rule,
});
};
//
const submit = async () => {
let param = JSON.parse(JSON.stringify(form.value));
param.forEach((e) => {
e.isChoose = +e.isChoose;
});
const recordParam = JSON.parse(JSON.stringify(param));
param.forEach((e) => {
delete e.recordChildren;
});
await postLoanWarningSave({ postLoanWarningList: param });
addRecord(recordParam);
getDetail();
ElMessage.success('提交成功!');
};
onMounted(() => {
getDetail();
});
</script>
<style lang="scss" scoped>
@import url(../../../styles/form.scss);
</style>

@ -0,0 +1,169 @@
<template>
<!-- 贷后预警 -->
<el-form label-width="90px" label-suffix="" class="form" :disabled="disabled" v-loading="loading">
<el-form-item label="策略名称">
<div>
<el-input class="w-[320px]" placeholder="请输入20以内字符" maxlength="20" clearable v-model="strategyName" />
<p v-if="bankIds.length" class="text-danger">不同步已关联产品请修改策略名称</p>
</div>
</el-form-item>
<el-form-item label="策略规则">
<el-table class="c-table" :data="form" :cell-style="{ background: '#fff' }" border>
<el-table-column label="选用" width="130" align="center">
<template #default="{ row }">
<el-radio-group v-model="row.isChoose">
<el-radio v-for="(item, i) in opt1" :key="i" :label="item.id">{{ item.name }}</el-radio>
</el-radio-group>
</template>
</el-table-column>
<el-table-column prop="recordName" label="风险类型" align="center"></el-table-column>
<el-table-column label="风险等级" align="center">
<template #default="{ row }">
<div class="flex">
<el-select v-if="row.recordChildren" class="mr-2" clearable v-model="row.riskGradeType">
<el-option v-for="item in row?.recordChildren[1].recordChildren[0].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
<el-select v-if="row.recordChildren" clearable v-model="row.riskGrade">
<el-option v-for="item in row?.recordChildren[1].recordChildren[1].subject.itemList" :key="item" :label="item.options" :value="item.itemId" />
</el-select>
</div> </template
></el-table-column>
</el-table>
</el-form-item>
<div v-if="!disabled" class="flex justify-end mt-3">
<div class="dia-btn cancel" @click="emit('close')">取消</div>
<div class="dia-btn" @click="confirmSubmit">确定</div>
</div>
</el-form>
<Confirm v-model="syncVisible" @submit="submit" />
</template>
<script setup lang="ts">
import { ref, defineAsyncComponent, onMounted, toRefs } from 'vue';
import { ElMessage } from 'element-plus';
import { postLoanWarningDetails, postLoanWarningSave, isTheStrategyRelatedToTheProduct } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import { handleId, getIds, opt1 } from '@/utils/common';
import Cookies from 'js-cookie';
import { getStat } from '@/store/useProduct';
const Confirm = defineAsyncComponent(() => import('@/components/StrategyConfirm.vue'));
const props = defineProps({
disabled: { type: Boolean, default: false },
row: { type: Object },
});
const emit = defineEmits(['close']);
const { strategyId, strategyName } = toRefs(props.row);
const form = ref<Record<string, any>[]>([]);
const info = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const syncVisible = ref<boolean>(false);
const bankIds = ref<Record<string, any>[]>([]);
//
const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(1032);
const result = [];
process.slice(1).map((e, i) => {
const cur = info.value.length ? info.value[i] : {};
result.push({
...getIds(),
recordName: e.name,
recordChildren: e.recordChildren,
riskGrade: +cur.riskGrade || '',
riskGradeType: +cur.riskGradeType || '',
isChoose: info.value.length ? cur.isChoose : '',
id: cur.id || '',
stRecordId: e.id,
});
});
form.value = result;
loading.value = false;
};
//
const getDetail = async () => {
loading.value = true;
try {
if (strategyId.value) {
const { data } = await postLoanWarningDetails({
strategyId: strategyId.value,
});
info.value = data;
}
getConfig();
//
if (strategyId.value && !props.disabled) {
const res = await isTheStrategyRelatedToTheProduct({
tacticsId: strategyId.value,
strategyType: 17,
});
if (res.isRelated) bankIds.value = res.bankIds;
}
} finally {
}
};
onMounted(getDetail);
//
const addRecord = async (data: Record<string, any>) => {
const preIds = `1,${Cookies.get('sand-level')},42,69,1032`; // 1id
const rule = [handleId(140, 28, strategyName.value, `${preIds},140`, 3)];
data.map((e) => {
e.isChoose && rule.push(handleId(1052, 140, e.isChoose, `${preIds},${e.stRecordId},1052`, 1));
e.riskGradeType && rule.push(handleId(1147, 299, e.riskGradeType, `${preIds},${e.stRecordId},1146,1147`, 1));
e.riskGrade && rule.push(handleId(1148, 300, e.riskGrade, `${preIds},${e.stRecordId},1146,1148`, 1));
});
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: rule,
});
loading.value = false;
ElMessage.success('提交成功!');
syncVisible.value = false;
emit('close', 1);
};
//
const submit = async (synchronizeUpdate?: number) => {
loading.value = true;
try {
const param = JSON.parse(JSON.stringify(form.value));
param.forEach((e) => {
delete e.recordChildren;
});
await postLoanWarningSave({
...getIds(),
strategyId: strategyId.value,
strategyName: strategyName.value,
synchronizeUpdate,
postLoanWarningList: param,
bankIds: bankIds.value,
});
getStat(295);
addRecord(param);
} catch (e) {
loading.value = false;
}
};
const confirmSubmit = async () => {
if (!strategyName.value) return ElMessage.error('请输入策略名称!');
//
if (bankIds.value.length) {
syncVisible.value = true;
} else {
submit();
}
};
</script>
<style lang="scss" scoped>
@import url(../../../../styles/form.scss);
</style>

@ -0,0 +1,157 @@
<template>
<div class="block">
<div class="flex justify-between items-center mb-5">
<search v-model="keyWord" @change="initList"></search>
<div class="filter">
<el-popconfirm title="确定删除选中策略吗?" :disabled="!multipleSelection.length" @confirm.stop="delAll">
<template #reference>
<div :class="['add-btn mr-2', { 'cursor-not-allowed': !multipleSelection.length }]">
<el-icon :size="24" color="#fff">
<Delete />
</el-icon>
批量删除
</div>
</template>
</el-popconfirm>
<div class="add-btn" @click="toAdd">
<img src="@/assets/images/plus.png" alt="" class="icon" />
新增
</div>
</div>
</div>
<el-table ref="table" v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" :selectable="handleDisable" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column prop="strategyName" label="贷后预警策略名称" min-width="180" />
<el-table-column prop="createTime" label="新增日期" min-width="140" />
<el-table-column label="操作" width="140">
<template #default="{ row }">
<el-button type="primary" link @click="toDetail(row, true)" size="small">查看</el-button>
<template v-if="!row.builtIn">
<el-button type="primary" link @click="toDetail(row)" size="small">编辑</el-button>
<el-popconfirm title="确定删除这条策略吗?" @confirm.stop="handleDelete([row.strategyId])">
<template #reference>
<el-button type="primary" link size="small">删除</el-button>
</template>
</el-popconfirm>
</template>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:total="total"
:page-sizes="pageSizes"
:layout="pageLayout"
@size-change="getList()"
@current-change="getList()"
small
background
class="px-3 py-2 justify-end"
></el-pagination>
<el-drawer v-model="visible" :title="(isDetail ? '查看' : curRow.strategyId ? '编辑' : '新增') + '贷后预警策略'" size="100%" :z-index="10" class="model-drawer">
<Detail v-model:row="curRow" :disabled="isDetail" :key="i" @close="closeDrawer" />
</el-drawer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, watch, defineAsyncComponent } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Delete } from '@element-plus/icons-vue';
import { pageSizes, pageLayout } from '@/utils/common';
import { postLoanWarning, postLoanWarningDel } from '@/api/model';
import Search from '@/components/Search.vue';
const Detail = defineAsyncComponent(() => import('./Detail.vue'));
const keyWord = ref<string>();
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);
const total = ref<number>(0);
const table = ref<any>();
const multipleSelection = ref<Record<string, any>[]>([]);
const list = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const visible = ref<boolean>(false);
const curRow = ref<Record<string, any>>({
strategyId: '',
strategyName: '',
});
const isDetail = ref<boolean>(false);
const i = ref<number>(0);
//
const getList = async () => {
loading.value = true;
try {
const { page } = await postLoanWarning({ pageNum: currentPage.value, pageSize: pageSize.value, keyWord: keyWord.value });
list.value = page.records;
total.value = page.total;
} finally {
loading.value = false;
}
};
//
const initList = async () => {
currentPage.value = 1;
getList();
};
watch(keyWord, initList);
onMounted(getList);
//
const handleDisable = (row: Record<string, any>) => {
//
if (row.builtIn) return false;
return true;
};
//
const handleSelectionChange = (val: Record<string, any>[]) => {
multipleSelection.value = val;
};
const handleDelete = async (ids: number[]) => {
try {
const res = await postLoanWarningDel({ ids });
//
if (res.tip) {
ElMessageBox.alert(res.message, '提示', {
confirmButtonText: '确定',
});
} else {
getList();
ElMessage.success('删除成功!');
}
} catch (e) {}
};
//
const delAll = async () => {
handleDelete(multipleSelection.value.map((e) => e.strategyId));
};
//
const toAdd = () => {
i.value++;
isDetail.value = false;
curRow.value = {
strategyId: '',
strategyName: '',
};
visible.value = true;
};
//
const toDetail = async (row: Record<string, any>, detail = false) => {
i.value++;
isDetail.value = detail;
curRow.value = row;
visible.value = true;
};
//
const closeDrawer = (refresh?: number) => {
visible.value = false;
refresh && initList();
};
</script>

@ -1,195 +0,0 @@
<template>
<!-- 贷后催收 -->
<el-table class="c-table"
:data="form"
:span-method="span"
:cell-style="{background:'#fff'}"
border>
<el-table-column prop="recordName"
label="逾期时长"
width="150"
align="center">
</el-table-column>
<el-table-column label="选择催收方式"
width="440"
align="center">
<template #default="{ row }">
<el-checkbox v-model="row.shortMessageCollection">短信催收</el-checkbox>
<el-checkbox v-model="row.appCollection">APP催收</el-checkbox>
<el-checkbox v-model="row.automaticOutboundCall">自动外呼</el-checkbox>
<el-checkbox v-model="row.manualCollection">人工催收</el-checkbox>
</template>
</el-table-column>
<el-table-column label="短信/APP/自动外呼 话术"
min-width="310"
align="center">
<template #default="{ row }">
<p v-if="row.recordChildren && row.verbalTrick">{{ row?.recordChildren[0]?.subject?.itemList.find(e => e.itemId === row.verbalTrick)?.options }}</p>
<el-button type="primary"
:icon="Plus"
@click="showDia(row)">选择</el-button>
<!-- <el-select v-if="row.recordChildren"
class="w-full type-select"
v-model="row.verbalTrick">
<el-option v-for="item in row?.recordChildren[0]?.subject?.itemList"
:key="item"
:label="item.options"
:value="item.itemId">
<span>{{ item.options }}</span>
</el-option>
</el-select> -->
</template></el-table-column>
</el-table>
<div class="flex justify-end">
<div class="submit"
@click="submit">确认完成配置</div>
</div>
<el-dialog v-model="selectDia"
custom-class="select-dia">
<div class="selects"
v-if="curRow.recordChildren">
<div v-for="item in
curRow?.recordChildren[0]?.subject?.itemList"
:key="item"
class="line"
@click="curRow.verbalTrick = item.itemId">
<el-radio v-model="curRow.verbalTrick"
:label="item.itemId"></el-radio>
<span>{{ item.options }}</span>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button type="primary"
@click="selectDia = false">关闭</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { Plus } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { collectionAfterLoanDetails, collectionAfterLoanSave } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import { handleId, getIds } from '@/utils/common';
import Cookies from 'js-cookie';
const projectId = +Cookies.get('sand-projectId');
const levelId = +Cookies.get('sand-level');
const form = ref<Record<string, any>[]>([]);
const info = ref<Record<string, any>[]>([]);
const curRow = ref<Record<string, any>>({});
const selectDia = ref<boolean>(false);
//
const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(1033);
const result = [];
process[0].recordChildren.map((e, i) => {
const cur = info.value.length ? info.value[i] : {};
result.push({
...getIds(),
recordName: e.name,
recordChildren: e.recordChildren,
appCollection: info.value.length ? !!cur.appCollection : false,
automaticOutboundCall: info.value.length ? !!cur.automaticOutboundCall : false,
shortMessageCollection: info.value.length ? !!cur.shortMessageCollection : false,
manualCollection: info.value.length ? !!cur.manualCollection : false,
verbalTrick: cur.verbalTrick ? +cur.verbalTrick : '',
id: cur.id || '',
stRecordId: e.id,
});
});
form.value = result;
console.log('🚀 ~ getConfig ~ result:', result);
};
//
const getDetail = async () => {
try {
const { data } = await collectionAfterLoanDetails();
info.value = data;
getConfig();
} finally {
}
};
//
const showDia = (row: Record<string, any>) => {
selectDia.value = true;
curRow.value = row;
};
//
const addRecord = async (data: Record<string, any>) => {
const preIds = `1,${levelId},42,69,1033,1149`; // 1id
const rule = [];
data.map((e) => {
e.recordChildren.forEach((n, i) => {
if (i) {
const ids = [];
e.shortMessageCollection && ids.push(774);
e.appCollection && ids.push(775);
e.automaticOutboundCall && ids.push(776);
e.manualCollection && ids.push(777);
ids.length && rule.push(handleId(n.id, n.subjectId, ids.join(), `${preIds},${e.stRecordId},${n.id}`, 1));
} else {
e.verbalTrick && rule.push(handleId(n.id, n.subjectId, e.verbalTrick, `${preIds},${e.stRecordId},${n.id}`, 1));
}
});
});
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: rule,
});
};
//
const submit = async () => {
let param = JSON.parse(JSON.stringify(form.value));
param.map((e) => {
e.appCollection = +e.appCollection;
e.automaticOutboundCall = +e.automaticOutboundCall;
e.shortMessageCollection = +e.shortMessageCollection;
e.manualCollection = +e.manualCollection;
});
const recordParam = JSON.parse(JSON.stringify(param));
param.map((e) => {
delete e.recordChildren;
});
await collectionAfterLoanSave({ collectionAfterLoanList: param });
addRecord(recordParam);
getDetail();
ElMessage.success('提交成功!');
};
onMounted(() => {
getDetail();
});
</script>
<style lang="scss" scoped>
@import url(../../../styles/form.scss);
.select-dia {
.selects {
margin-top: 20px;
}
.line {
display: flex;
align-items: flex-start;
margin-bottom: 10px;
cursor: pointer;
}
background-color: #fff;
.el-radio {
height: 20px;
margin-right: 10px;
:deep(.el-radio__label) {
display: none;
}
}
}
</style>

@ -0,0 +1,229 @@
<template>
<!-- 贷后催收 -->
<el-form label-width="90px" label-suffix="" class="form" :disabled="disabled">
<el-form-item label="策略名称">
<div>
<el-input class="w-[320px]" placeholder="请输入20以内字符" maxlength="20" clearable v-model="strategyName" />
<p v-if="bankIds.length" class="text-danger">不同步已关联产品请修改策略名称</p>
</div>
</el-form-item>
<el-form-item label="策略规则">
<el-table class="c-table" :data="form" :span-method="span" :cell-style="{ background: '#fff' }" border>
<el-table-column prop="name" label="选用" width="130" align="center">
<template #default="{ row }">
<el-radio-group v-model="row.isChoose">
<el-radio v-for="(item, i) in opt1" :key="i" :label="item.id">{{ item.name }}</el-radio>
</el-radio-group>
</template>
</el-table-column>
<el-table-column prop="recordName" label="逾期时长" width="150" align="center"> </el-table-column>
<el-table-column label="选择催收方式" width="440" align="center">
<template #default="{ row }">
<el-checkbox v-model="row.shortMessageCollection">短信催收</el-checkbox>
<el-checkbox v-model="row.appCollection">APP催收</el-checkbox>
<el-checkbox v-model="row.automaticOutboundCall">自动外呼</el-checkbox>
<el-checkbox v-model="row.manualCollection">人工催收</el-checkbox>
</template>
</el-table-column>
<el-table-column label="短信/APP/自动外呼 话术" min-width="310" align="center">
<template #default="{ row }">
<p v-if="row.recordChildren && row.verbalTrick">{{ row?.recordChildren[1]?.subject?.itemList.find((e) => e.itemId === row.verbalTrick)?.options }}</p>
<el-button type="primary" :icon="Plus" @click="showDia(row)">选择</el-button>
</template></el-table-column
>
</el-table>
</el-form-item>
</el-form>
<div v-if="!disabled" class="flex justify-end mt-3">
<div class="dia-btn cancel" @click="emit('close')">取消</div>
<div class="dia-btn" @click="confirmSubmit">确定</div>
</div>
<Confirm v-model="syncVisible" @submit="submit" />
<el-dialog v-model="selectDia" custom-class="select-dia">
<div class="selects" v-if="curRow.recordChildren">
<div v-for="item in curRow?.recordChildren[1]?.subject?.itemList" :key="item" class="line" @click="curRow.verbalTrick = item.itemId">
<el-radio v-model="curRow.verbalTrick" :label="item.itemId"></el-radio>
<span>{{ item.options }}</span>
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="selectDia = false">关闭</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, defineAsyncComponent, onMounted, toRefs } from 'vue';
import { Plus } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { collectionAfterLoanDetails, collectionAfterLoanSave, isTheStrategyRelatedToTheProduct } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import { handleId, getIds, opt1 } from '@/utils/common';
import Cookies from 'js-cookie';
import { getStat } from '@/store/useProduct';
const Confirm = defineAsyncComponent(() => import('@/components/StrategyConfirm.vue'));
const props = defineProps({
disabled: { type: Boolean, default: false },
row: { type: Object },
});
const emit = defineEmits(['close']);
const { strategyId, strategyName } = toRefs(props.row);
const form = ref<Record<string, any>[]>([]);
const info = ref<Record<string, any>[]>([]);
const curRow = ref<Record<string, any>>({});
const selectDia = ref<boolean>(false);
const syncVisible = ref<boolean>(false);
const bankIds = ref<Record<string, any>[]>([]);
//
const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(1033);
const result = [];
process[1].recordChildren.map((e, i) => {
const cur = info.value.length ? info.value[i] : {};
result.push({
...getIds(),
recordName: e.name,
recordChildren: e.recordChildren,
isChoose: info.value.length ? cur.isChoose : '',
appCollection: info.value.length ? !!cur.appCollection : false,
automaticOutboundCall: info.value.length ? !!cur.automaticOutboundCall : false,
shortMessageCollection: info.value.length ? !!cur.shortMessageCollection : false,
manualCollection: info.value.length ? !!cur.manualCollection : false,
verbalTrick: cur.verbalTrick ? +cur.verbalTrick : '',
id: cur.id || '',
stRecordId: e.id,
});
});
form.value = result;
};
//
const getDetail = async () => {
try {
if (strategyId.value) {
const { data } = await collectionAfterLoanDetails({
strategyId: strategyId.value,
});
info.value = data;
}
getConfig();
//
if (strategyId.value && !props.disabled) {
const res = await isTheStrategyRelatedToTheProduct({
tacticsId: strategyId.value,
strategyType: 18,
});
if (res.isRelated) bankIds.value = res.bankIds;
}
} finally {
}
};
onMounted(getDetail);
//
const showDia = (row: Record<string, any>) => {
selectDia.value = true;
curRow.value = row;
};
//
const addRecord = async (data: Record<string, any>) => {
let preIds = `1,${Cookies.get('sand-level')},42,69,1033`; // 1id
const rule = [handleId(140, 28, strategyName.value, `${preIds},140`, 3)];
preIds += ',1149';
data.map((e) => {
e.recordChildren.forEach((n, i) => {
if (i === 2) {
//
const ids = [];
e.shortMessageCollection && ids.push(774);
e.appCollection && ids.push(775);
e.automaticOutboundCall && ids.push(776);
e.manualCollection && ids.push(777);
ids.length && rule.push(handleId(n.id, n.subjectId, ids.join(), `${preIds},${e.stRecordId},${n.id}`, 1));
} else if (i === 1) {
//
e.verbalTrick && rule.push(handleId(n.id, n.subjectId, e.verbalTrick, `${preIds},${e.stRecordId},${n.id}`, 1));
} else {
//
e.isChoose && rule.push(handleId(1052, 140, e.isChoose, `${preIds},${e.stRecordId},1052`, 1));
}
});
});
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: rule,
});
ElMessage.success('提交成功!');
syncVisible.value = false;
emit('close', 1);
};
//
const submit = async (synchronizeUpdate?: number) => {
try {
const param = JSON.parse(JSON.stringify(form.value));
param.map((e) => {
e.appCollection = +e.appCollection;
e.automaticOutboundCall = +e.automaticOutboundCall;
e.shortMessageCollection = +e.shortMessageCollection;
e.manualCollection = +e.manualCollection;
});
const recordParam = JSON.parse(JSON.stringify(param));
param.map((e) => {
delete e.recordChildren;
});
await collectionAfterLoanSave({
...getIds(),
strategyId: strategyId.value,
strategyName: strategyName.value,
synchronizeUpdate,
collectionAfterLoanList: param,
bankIds: bankIds.value,
});
getStat(295);
addRecord(recordParam);
} catch (e) {}
};
const confirmSubmit = async () => {
if (!strategyName.value) return ElMessage.error('请输入策略名称!');
//
if (bankIds.value.length) {
syncVisible.value = true;
} else {
submit();
}
};
</script>
<style lang="scss" scoped>
@import url(../../../../styles/form.scss);
.select-dia {
.selects {
margin-top: 20px;
}
.line {
display: flex;
align-items: flex-start;
margin-bottom: 10px;
cursor: pointer;
}
background-color: #fff;
.el-radio {
height: 20px;
margin-right: 10px;
:deep(.el-radio__label) {
display: none;
}
}
}
</style>

@ -0,0 +1,157 @@
<template>
<div class="block">
<div class="flex justify-between items-center mb-5">
<search v-model="keyWord" @change="initList"></search>
<div class="filter">
<el-popconfirm title="确定删除选中策略吗?" :disabled="!multipleSelection.length" @confirm.stop="delAll">
<template #reference>
<div :class="['add-btn mr-2', { 'cursor-not-allowed': !multipleSelection.length }]">
<el-icon :size="24" color="#fff">
<Delete />
</el-icon>
批量删除
</div>
</template>
</el-popconfirm>
<div class="add-btn" @click="toAdd">
<img src="@/assets/images/plus.png" alt="" class="icon" />
新增
</div>
</div>
</div>
<el-table ref="table" v-loading="loading" :data="list" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" :selectable="handleDisable" />
<el-table-column label="序号" type="index" width="60" align="center" />
<el-table-column prop="strategyName" label="贷后催收策略名称" min-width="180" />
<el-table-column prop="createTime" label="新增日期" min-width="140" />
<el-table-column label="操作" width="140">
<template #default="{ row }">
<el-button type="primary" link @click="toDetail(row, true)" size="small">查看</el-button>
<template v-if="!row.builtIn">
<el-button type="primary" link @click="toDetail(row)" size="small">编辑</el-button>
<el-popconfirm title="确定删除这条策略吗?" @confirm.stop="handleDelete([row.strategyId])">
<template #reference>
<el-button type="primary" link size="small">删除</el-button>
</template>
</el-popconfirm>
</template>
</template>
</el-table-column>
</el-table>
<el-pagination
v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:total="total"
:page-sizes="pageSizes"
:layout="pageLayout"
@size-change="getList()"
@current-change="getList()"
small
background
class="px-3 py-2 justify-end"
></el-pagination>
<el-drawer v-model="visible" :title="(isDetail ? '查看' : curRow.strategyId ? '编辑' : '新增') + '贷后催收策略'" size="100%" :z-index="10" class="model-drawer">
<Detail v-model:row="curRow" :disabled="isDetail" :key="i" @close="closeDrawer" />
</el-drawer>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, watch, defineAsyncComponent } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Delete } from '@element-plus/icons-vue';
import { pageSizes, pageLayout } from '@/utils/common';
import { collectionAfterLoan, collectionAfterLoanDel } from '@/api/model';
import Search from '@/components/Search.vue';
const Detail = defineAsyncComponent(() => import('./Detail.vue'));
const keyWord = ref<string>();
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);
const total = ref<number>(0);
const table = ref<any>();
const multipleSelection = ref<Record<string, any>[]>([]);
const list = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false);
const visible = ref<boolean>(false);
const curRow = ref<Record<string, any>>({
strategyId: '',
strategyName: '',
});
const isDetail = ref<boolean>(false);
const i = ref<number>(0);
//
const getList = async () => {
loading.value = true;
try {
const { page } = await collectionAfterLoan({ pageNum: currentPage.value, pageSize: pageSize.value, keyWord: keyWord.value });
list.value = page.records;
total.value = page.total;
} finally {
loading.value = false;
}
};
//
const initList = async () => {
currentPage.value = 1;
getList();
};
watch(keyWord, initList);
onMounted(getList);
//
const handleDisable = (row: Record<string, any>) => {
//
if (row.builtIn) return false;
return true;
};
//
const handleSelectionChange = (val: Record<string, any>[]) => {
multipleSelection.value = val;
};
const handleDelete = async (ids: number[]) => {
try {
const res = await collectionAfterLoanDel({ ids });
//
if (res.tip) {
ElMessageBox.alert(res.message, '提示', {
confirmButtonText: '确定',
});
} else {
getList();
ElMessage.success('删除成功!');
}
} catch (e) {}
};
//
const delAll = async () => {
handleDelete(multipleSelection.value.map((e) => e.strategyId));
};
//
const toAdd = () => {
i.value++;
isDetail.value = false;
curRow.value = {
strategyId: '',
strategyName: '',
};
visible.value = true;
};
//
const toDetail = async (row: Record<string, any>, detail = false) => {
i.value++;
isDetail.value = detail;
curRow.value = row;
visible.value = true;
};
//
const closeDrawer = (refresh?: number) => {
visible.value = false;
refresh && initList();
};
</script>

@ -1,64 +1,71 @@
<template> <template>
<div class="block card-list flex py-0"> <div v-if="list.length">
<div class="left"> <div class="menu-card">
<ul class="products"> <el-menu class="left" :default-active="curMenu" @select="handleSelect">
<li v-for="(item, i) in list" <el-menu-item v-for="(item, i) in list" :key="i" :index="String(item.id)">{{ item.name }}</el-menu-item>
:key="i" </el-menu>
:class="{ active: item.id === id }" <div class="right">
@click="switchProduct(item.id)"> <component v-if="loadedComponents[activeComponent]" :is="loadedComponents[activeComponent]" />
<h6>{{ item.name }}</h6> </div>
<p class="meta">{{ item.remark }}</p>
</li>
</ul>
</div>
<div class="right">
<Com1 v-if="id == 1029" />
<Com2 v-else-if="id == 1030" />
<Com3 v-else-if="id == 1031" />
<Com4 v-else-if="id == 1032" />
<Com5 v-else-if="id == 1033" />
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, ref } from 'vue'; import { computed, onMounted, ref, defineAsyncComponent, markRaw } from 'vue';
import { getProcessInformationBasedOnRoles } from '@/api/judgment'; import { getProcessInformationBasedOnRoles } from '@/api/judgment';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import Cookies from 'js-cookie';
import Com1 from './1029.vue';
import Com2 from './1030.vue';
import Com3 from './1031.vue';
import Com4 from './1032.vue';
import Com5 from './1033.vue';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const projectId = +Cookies.get('sand-projectId');
const levelId = +Cookies.get('sand-level');
const list = ref<Array<Record<string, any>>>([]); const list = ref<Array<Record<string, any>>>([]);
const id = computed(() => +route.query.id); const curMenu = computed({
get() {
return route.query.id;
},
set() {},
});
// const asyncComponents = {
const switchProduct = (productId: number | string) => { '1029': defineAsyncComponent(() => import('./1029/Index.vue')),
router.push(`/product/afterLoan?i=4&role=42&id=${productId}`); '1030': defineAsyncComponent(() => import('./1030/Index.vue')),
'1031': defineAsyncComponent(() => import('./1031/Index.vue')),
'1032': defineAsyncComponent(() => import('./1032/Index.vue')),
'1033': defineAsyncComponent(() => import('./1033/Index.vue')),
};
const loadedComponents = markRaw({});
const activeComponent = ref<string>('');
//
const loadComponent = async (componentName: string) => {
if (!loadedComponents[componentName]) {
try {
loadedComponents[componentName] = asyncComponents[componentName];
activeComponent.value = componentName;
} catch (error) {
console.error(`Failed to load component ${componentName}`, error);
}
} else {
activeComponent.value = componentName;
}
};
const handleSelect = async (key: string) => {
curMenu.value = key;
await loadComponent(key);
router.push(`/product/afterLoan?i=${route.query.i}&role=${route.query.role}&id=${key}`);
}; };
// //
const getList = async (refresh?: number) => { const getList = async () => {
const { process } = await getProcessInformationBasedOnRoles(69); const { process } = await getProcessInformationBasedOnRoles(69);
// eslint-disable-next-line no-unused-expressions
!id.value && switchProduct(process[0].id);
list.value = process; list.value = process;
handleSelect(curMenu.value || process[0].recordChildren[0].id);
}; };
onMounted(() => { onMounted(getList);
getList();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.card-list { .left {
.left { @apply w-[200px];
@apply max-h-[calc(100vh-120px)];
}
} }
</style> </style>

@ -1,61 +1,46 @@
<template> <template>
<div> <div>
<el-tabs v-model="curTab" <el-tabs v-model="curTab">
@tab-click="tabChange"> <el-tab-pane :label="id ? '配置要素' : '新增产品'" name="tab1">
<el-tab-pane :label="id ? '配置要素' : '新增产品'" <el-form ref="formRef" :model="form" :rules="rules" label-width="100px" label-suffix="" class="form" status-icon>
name="tab1">
<el-form ref="formRef"
:model="form"
:rules="rules"
label-width="100px"
label-suffix=":"
class="form"
status-icon>
<div class="h-[calc(100vh-230px)] pr-1 overflow-auto"> <div class="h-[calc(100vh-230px)] pr-1 overflow-auto">
<el-form-item label="产品定义" <el-form-item label="产品定义" prop="productDefinition">
prop="productDefinition"> <el-input
<el-input type="textarea" type="textarea"
placeholder="用一段话简单介绍一下这个产品或者描述产品的设计理念。例如:本产品根据个人客户的信用状况,为其提供的一种短期融资便利产品,借款人可在额度金额内可循环周转使用贷款。" placeholder="用一段话简单介绍一下这个产品或者描述产品的设计理念。例如:本产品根据个人客户的信用状况,为其提供的一种短期融资便利产品,借款人可在额度金额内可循环周转使用贷款。"
maxlength="200" maxlength="200"
v-model="form.productDefinition"></el-input> v-model="form.productDefinition"
></el-input>
</el-form-item> </el-form-item>
<el-form-item label="产品名称" <el-form-item label="产品名称" prop="productName">
prop="productName"> <el-input placeholder="取个有吸引力的产品名,限20字。" maxlength="20" v-model="form.productName"></el-input>
<el-input placeholder="取个有吸引力的产品名,限20字。"
maxlength="20"
v-model="form.productName"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="产品币种" <el-form-item label="产品币种" prop="productCurrency">
prop="productCurrency"> <el-select v-model="form.productCurrency" placeholder="请选择">
<el-select v-model="form.productCurrency" <el-option label="人民币" :value="1" />
placeholder="请选择">
<el-option label="人民币"
:value="1" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="贷款对象" <el-form-item label="贷款对象" required>
required>
<div class="flex-1"> <div class="flex-1">
<!-- 企业 --> <!-- 企业 -->
<template v-if="form.productType"> <template v-if="productType">
<div class="flex items-center"> <div class="flex items-center">
<span class="mr-3 text-[#333] text-sm">企业类型</span> <span class="mr-3 text-[#333] text-sm">企业类型</span>
<el-select v-model="form.productObject" <el-select v-model="form.productObject" placeholder="请选择">
placeholder="请选择"> <el-option
<el-option v-for="(item, i) in config.find((e) => e.name === '企业产品-贷款对象')?.recordChildren[0]?.subject?.itemList" v-for="(item, i) in config.find((e) => e.name === '企业产品-贷款对象')?.recordChildren[0]?.subject?.itemList"
:key="i" :key="i"
:label="item.options" :label="item.options"
:value="item.itemId" /> :value="item.itemId"
/>
</el-select> </el-select>
</div> </div>
<div class="flex items-center mt-4"> <div class="flex items-center mt-4">
<span class="mr-3 text-[#333] text-sm">借款人年龄</span> <span class="mr-3 text-[#333] text-sm">借款人年龄</span>
<div class="num-inputs ml-7"> <div class="num-inputs ml-7">
<el-input placeholder="最小年龄" <el-input placeholder="最小年龄" v-model.number="form.minimumAge"></el-input>
v-model.number="form.minimumAge"></el-input>
<span class="split">-</span> <span class="split">-</span>
<el-input placeholder="最大年龄" <el-input placeholder="最大年龄" v-model.number="form.maximumAge"></el-input>
v-model.number="form.maximumAge"></el-input>
<span class="unit">周岁</span> <span class="unit">周岁</span>
</div> </div>
</div> </div>
@ -68,19 +53,14 @@
<span class="label">1年龄</span> <span class="label">1年龄</span>
<span class="whether">是否启用</span> <span class="whether">是否启用</span>
<el-radio-group v-model="form.ageSelectedState"> <el-radio-group v-model="form.ageSelectedState">
<el-radio v-for="(item, i) in whethers" <el-radio v-for="(item, i) in whethers" :key="i" :label="item.id">{{ item.name }}</el-radio>
:key="i"
:label="item.id">{{ item.name }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<div v-if="form.ageSelectedState === 795" <div v-if="form.ageSelectedState === 795" class="num-inputs ml-7">
class="num-inputs ml-7"> <el-input placeholder="最小年龄" v-model.number="form.minimumAge"></el-input>
<el-input placeholder="最小年龄"
v-model.number="form.minimumAge"></el-input>
<span class="split">-</span> <span class="split">-</span>
<el-input placeholder="最大年龄" <el-input placeholder="最大年龄" v-model.number="form.maximumAge"></el-input>
v-model.number="form.maximumAge"></el-input>
</div> </div>
</div> </div>
<div class="flex items-center h-[47px] mb-2"> <div class="flex items-center h-[47px] mb-2">
@ -88,18 +68,17 @@
<span class="label">2学历要求</span> <span class="label">2学历要求</span>
<span class="whether">是否启用</span> <span class="whether">是否启用</span>
<el-radio-group v-model="form.degreeSelectedStatus"> <el-radio-group v-model="form.degreeSelectedStatus">
<el-radio v-for="(item, i) in whethers" <el-radio v-for="(item, i) in whethers" :key="i" :label="item.id">{{ item.name }}</el-radio>
:key="i"
:label="item.id">{{ item.name }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<el-checkbox-group v-if="form.degreeSelectedStatus === 795" <el-checkbox-group v-if="form.degreeSelectedStatus === 795" class="mt-2 ml-5" v-model="form.educationalRequirements">
class="mt-2 ml-5" <el-checkbox
v-model="form.educationalRequirements"> v-for="(item, i) in config.find((e) => e.name === '个人产品-贷款对象')?.recordChildren[1]?.recordChildren[1]?.subject?.itemList"
<el-checkbox v-for="(item, i) in config.find((e) => e.name === '个人产品-贷款对象')?.recordChildren[1]?.recordChildren[1]?.subject?.itemList" :key="i"
:key="i" :label="item.itemId"
:label="item.itemId">{{ item.options }}</el-checkbox> >{{ item.options }}</el-checkbox
>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
@ -108,18 +87,17 @@
<span class="label">3工作年限</span> <span class="label">3工作年限</span>
<span class="whether">是否启用</span> <span class="whether">是否启用</span>
<el-radio-group v-model="form.workingLifeSelectedState"> <el-radio-group v-model="form.workingLifeSelectedState">
<el-radio v-for="(item, i) in whethers" <el-radio v-for="(item, i) in whethers" :key="i" :label="item.id">{{ item.name }}</el-radio>
:key="i"
:label="item.id">{{ item.name }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<el-checkbox-group v-if="form.workingLifeSelectedState === 795" <el-checkbox-group v-if="form.workingLifeSelectedState === 795" class="mt-2 ml-5" v-model="form.currentWorkingLife">
class="mt-2 ml-5" <el-checkbox
v-model="form.currentWorkingLife"> v-for="(item, i) in config.find((e) => e.name === '个人产品-贷款对象')?.recordChildren[2]?.recordChildren[1]?.subject?.itemList"
<el-checkbox v-for="(item, i) in config.find((e) => e.name === '个人产品-贷款对象')?.recordChildren[2]?.recordChildren[1]?.subject?.itemList" :key="i"
:key="i" :label="item.itemId"
:label="item.itemId">{{ item.options }}</el-checkbox> >{{ item.options }}</el-checkbox
>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
@ -127,179 +105,152 @@
<span class="label">4公积金/社保</span> <span class="label">4公积金/社保</span>
<span class="whether">是否启用</span> <span class="whether">是否启用</span>
<el-radio-group v-model="form.providentFundAndSocialSecurity"> <el-radio-group v-model="form.providentFundAndSocialSecurity">
<el-radio v-for="(item, i) in whethers" <el-radio v-for="(item, i) in whethers" :key="i" :label="item.id">{{ item.name }}</el-radio>
:key="i"
:label="item.id">{{ item.name }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
</template> </template>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="贷款用途" <el-form-item
prop="loanPurpose" label="贷款用途"
:rules="[ prop="loanPurpose"
{ required: true, message: '请选择贷款用途', trigger: 'change' }, :rules="[
{ { required: true, message: '请选择贷款用途', trigger: 'change' },
asyncValidator: async (rule, value, callback) => { {
if (value === 107 && !form.otherPurposesOfLoan) { asyncValidator: async (rule, value, callback) => {
callback('请输入其他贷款用途') if (value === 107 && !form.otherPurposesOfLoan) {
} else { callback('请输入其他贷款用途');
callback() } else {
} callback();
}
},
}, },
}, ]"
]"> >
<div class="flex-1"> <div class="flex-1">
<p class="field-name">选择本产品贷款资金的用途</p> <p class="field-name">选择本产品贷款资金的用途</p>
<el-radio-group v-model="form.loanPurpose"> <el-radio-group v-model="form.loanPurpose">
<template v-if="form.productType"> <template v-if="productType">
<el-radio v-for="(item, i) in config.find((e) => e.name === '企业产品-贷款用途')?.subject?.itemList" <el-radio v-for="(item, i) in config.find((e) => e.name === '企业产品-贷款用途')?.subject?.itemList" :key="i" :label="item.itemId">{{ item.options }}</el-radio>
:key="i"
:label="item.itemId">{{ item.options }}</el-radio>
</template> </template>
<template v-else> <template v-else>
<el-radio v-for="(item, i) in config.find(e => e.name === '个人产品-贷款用途')?.recordChildren[0]?.subject?.itemList" <el-radio v-for="(item, i) in config.find((e) => e.name === '个人产品-贷款用途')?.recordChildren[0]?.subject?.itemList" :key="i" :label="item.itemId">{{
:key="i" item.options
:label="item.itemId">{{ item.options }}</el-radio> }}</el-radio>
</template> </template>
</el-radio-group> </el-radio-group>
<el-input v-if="form?.loanPurpose === 822" <el-input
class="w-[300px] ml-5" v-if="form?.loanPurpose === 822"
placeholder="请描述其他贷款用途可用于哪些方面。" class="w-[300px] ml-5"
maxlength="10" placeholder="请描述其他贷款用途可用于哪些方面。"
v-model="form.otherPurposesOfLoan"></el-input> maxlength="10"
v-model="form.otherPurposesOfLoan"
></el-input>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="担保方式" <el-form-item
prop="bankGuaranteeTypeIds" label="担保方式"
:rules="[ prop="bankGuaranteeTypeIds"
{ :rules="[
asyncValidator: async (rule, value, callback) => { {
if (form.mortgageSelectedStatus === 795 && !value.find(e => e > 22 && e < 33)) { asyncValidator: async (rule, value, callback) => {
callback('请选择抵押物') if (form.mortgageSelectedStatus === 795 && !value.find((e) => e > 22 && e < 33)) {
} else if (form.hypothecatedSelectedStatus === 795 && !value.find(e => e > 32 && e < 38)) { callback('请选择抵押物');
callback('请选择质押贷') } else if (form.hypothecatedSelectedStatus === 795 && !value.find((e) => e > 32 && e < 38)) {
} else { callback('请选择质押贷');
callback() } else {
} callback();
}
},
}, },
}, ]"
]"> >
<div class="flex-1"> <div class="flex-1">
<p class="field-name">选择本产品的担保种类</p> <p class="field-name">选择本产品的担保种类</p>
<div class="radio-wrap"> <div class="radio-wrap">
<span class="label">信用贷</span> <span class="label">信用贷</span>
<el-radio-group v-model="form.creditSelectedStatus"> <el-radio-group v-model="form.creditSelectedStatus">
<el-radio v-for="(item, i) in whethers" <el-radio v-for="(item, i) in whethers" :key="i" :label="item.id">{{ item.name }}</el-radio>
:key="i"
:label="item.id">{{ item.name }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<div class="radio-wrap my-1"> <div class="radio-wrap my-1">
<span class="label">保证贷</span> <span class="label">保证贷</span>
<el-radio-group v-model="form.guaranteeLoanSelectedStatus"> <el-radio-group v-model="form.guaranteeLoanSelectedStatus">
<el-radio v-for="(item, i) in whethers" <el-radio v-for="(item, i) in whethers" :key="i" :label="item.id">{{ item.name }}</el-radio>
:key="i"
:label="item.id">{{ item.name }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<div class="radio-wrap"> <div class="radio-wrap">
<span class="label">抵押贷</span> <span class="label">抵押贷</span>
<el-radio-group v-model="form.mortgageSelectedStatus"> <el-radio-group v-model="form.mortgageSelectedStatus">
<el-radio v-for="(item, i) in whethers" <el-radio v-for="(item, i) in whethers" :key="i" :label="item.id">{{ item.name }}</el-radio>
:key="i"
:label="item.id">{{ item.name }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<el-checkbox-group v-if="form.mortgageSelectedStatus === 795" <el-checkbox-group v-if="form.mortgageSelectedStatus === 795" v-model="form.bankGuaranteeTypeIds">
v-model="form.bankGuaranteeTypeIds"> <el-checkbox
<el-checkbox v-for="(child, j) in config.find((e) => e.name === '担保方式')?.recordChildren[2]?.recordChildren[0]?.subject?.itemList" v-for="(child, j) in config.find((e) => e.name === '担保方式')?.recordChildren[2]?.recordChildren[0]?.subject?.itemList"
:key="j" :key="j"
:label="child.itemId">{{ child.options }}</el-checkbox> :label="child.itemId"
>{{ child.options }}</el-checkbox
>
</el-checkbox-group> </el-checkbox-group>
<div class="radio-wrap mt-1"> <div class="radio-wrap mt-1">
<span class="label">质押贷</span> <span class="label">质押贷</span>
<el-radio-group v-model="form.hypothecatedSelectedStatus"> <el-radio-group v-model="form.hypothecatedSelectedStatus">
<el-radio v-for="(item, i) in whethers" <el-radio v-for="(item, i) in whethers" :key="i" :label="item.id">{{ item.name }}</el-radio>
:key="i"
:label="item.id">{{ item.name }}</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<el-checkbox-group v-if="form.hypothecatedSelectedStatus === 795" <el-checkbox-group v-if="form.hypothecatedSelectedStatus === 795" v-model="form.bankGuaranteeTypeIds">
v-model="form.bankGuaranteeTypeIds"> <el-checkbox
<el-checkbox v-for="(child, j) in config.find((e) => e.name === '担保方式')?.recordChildren[3]?.recordChildren[0]?.subject?.itemList" v-for="(child, j) in config.find((e) => e.name === '担保方式')?.recordChildren[3]?.recordChildren[0]?.subject?.itemList"
:key="j" :key="j"
:label="child.itemId">{{ child.options }}</el-checkbox> :label="child.itemId"
>{{ child.options }}</el-checkbox
>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="贷款额度" <el-form-item label="贷款额度" prop="minimumLoan" :rules="[{ required: true, message: '请输入贷款额度', trigger: 'blur' }]">
prop="minimumLoan"
:rules="[
{ required: true, message: '请输入贷款额度', trigger: 'blur' },
]">
<div class="flex-1"> <div class="flex-1">
<div class="num-inputs"> <div class="num-inputs">
<el-input placeholder="最小额度" <el-input placeholder="最小额度" v-model="form.minimumLoan"></el-input>
v-model="form.minimumLoan"></el-input>
<span class="split">-</span> <span class="split">-</span>
<el-input placeholder="最高额度" <el-input placeholder="最高额度" v-model="form.loanCeiling"></el-input>
v-model="form.loanCeiling"></el-input>
<span class="unit">万元</span> <span class="unit">万元</span>
</div> </div>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="贷款利率" <el-form-item label="贷款利率" prop="minimumAprOnLoan" :rules="[{ required: true, message: '请输入贷款利率', trigger: 'blur' }]">
prop="minimumAprOnLoan"
:rules="[
{ required: true, message: '请输入贷款利率', trigger: 'blur' },
]">
<div class="flex-1"> <div class="flex-1">
<div class="num-inputs"> <div class="num-inputs">
<el-input placeholder="最小年利率" <el-input placeholder="最小年利率" min="0" v-model="form.minimumAprOnLoan"></el-input>
min="0"
v-model="form.minimumAprOnLoan"></el-input>
<span class="split">-</span> <span class="split">-</span>
<el-input placeholder="最高年利率" <el-input placeholder="最高年利率" min="0" v-model="form.maximumAnnualInterestRate"></el-input>
min="0"
v-model="form.maximumAnnualInterestRate"></el-input>
<span class="unit">%</span> <span class="unit">%</span>
</div> </div>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="贷款期限" <el-form-item label="贷款期限" prop="minimumTermOfLoan" :rules="[{ required: true, message: '请输入贷款期限', trigger: 'blur' }]">
prop="minimumTermOfLoan"
:rules="[
{ required: true, message: '请输入贷款期限', trigger: 'blur' },
]">
<div class="flex-1"> <div class="flex-1">
<div class="num-inputs"> <div class="num-inputs">
<el-input placeholder="最小期限" <el-input placeholder="最小期限" v-model="form.minimumTermOfLoan"></el-input>
v-model="form.minimumTermOfLoan"></el-input>
<span class="split">-</span> <span class="split">-</span>
<el-input placeholder="最大期限" <el-input placeholder="最大期限" v-model="form.maximumTermOfLoan"></el-input>
v-model="form.maximumTermOfLoan"></el-input>
<span class="unit"></span> <span class="unit"></span>
</div> </div>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="还款方式" <el-form-item label="还款方式" prop="modeRepayment">
prop="modeRepayment">
<div class="flex-1"> <div class="flex-1">
<p class="field-name">选择本产品可以选择的还款方式</p> <p class="field-name">选择本产品可以选择的还款方式</p>
<el-checkbox-group v-model="form.modeRepayment"> <el-checkbox-group v-model="form.modeRepayment">
<el-checkbox v-for="(item, i) in config.find((e) => e.name === '还款方式')?.subject?.itemList" <el-checkbox v-for="(item, i) in config.find((e) => e.name === '还款方式')?.subject?.itemList" :key="i" :label="item.itemId">{{ item.options }}</el-checkbox>
:key="i"
:label="item.itemId">{{ item.options }}</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="提前还款" <el-form-item label="提前还款" prop="whetherToSupportEarlyRepayment">
prop="whetherToSupportEarlyRepayment">
<div class="flex-1 flex items-center"> <div class="flex-1 flex items-center">
<el-switch v-model="form.whetherToSupportEarlyRepayment" /> <el-switch v-model="form.whetherToSupportEarlyRepayment" />
<p class="tips ml-4">本产品是否支持提前还款</p> <p class="tips ml-4">本产品是否支持提前还款</p>
@ -307,16 +258,13 @@
</el-form-item> </el-form-item>
</div> </div>
<div class="flex justify-end"> <div class="flex justify-end">
<div class="submit" <div class="submit" @click="submit(formRef)">完成提交风控经理</div>
@click="submit(formRef)">完成提交风控经理</div>
</div> </div>
</el-form> </el-form>
</el-tab-pane> </el-tab-pane>
<el-tab-pane v-if="id" <el-tab-pane v-if="id" label="产品详情" name="tab2">
label="产品详情"
name="tab2">
<div class="h-[calc(100vh-170px)] pr-1 overflow-auto"> <div class="h-[calc(100vh-170px)] pr-1 overflow-auto">
<info v-model:tab="curTab" /> <info />
</div> </div>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
@ -326,14 +274,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, computed, watch, onMounted, defineEmits } from 'vue'; import { ref, reactive, computed, watch, onMounted, defineEmits } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import type { TabsPaneContext, FormInstance, FormRules } from 'element-plus'; import type { FormInstance, FormRules } from 'element-plus';
import { findById, save, update, elementDetail } from '@/api/bank'; import { findById, save, update, elementDetail } from '@/api/bank';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment'; import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { handleId, isIllegalNum, getIds, whethers, getUsername } from '@/utils/common'; import { handleId, isIllegalNum, getIds, whethers, getUsername } from '@/utils/common';
import { getStatus } from '@/store/useProduct';
import Info from './Info.vue';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { getStat } from '@/store/useProduct';
import Info from './Info.vue';
const emit = defineEmits(['getList']); const emit = defineEmits(['getList']);
interface RuleForm { interface RuleForm {
@ -358,7 +306,7 @@ interface RuleForm {
modeRepayment?: number[]; modeRepayment?: number[];
otherPurposesOfLoan: string; otherPurposesOfLoan: string;
productObject?: number; productObject?: number;
productType: number; productType?: number;
providentFundAndSocialSecurity: number | string; providentFundAndSocialSecurity: number | string;
whetherToSupportEarlyRepayment: boolean; whetherToSupportEarlyRepayment: boolean;
creditSelectedStatus?: number; creditSelectedStatus?: number;
@ -370,13 +318,15 @@ interface RuleForm {
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const id = computed(() => route.query.id); const id = computed(() => route.query.id);
const productType = +route.query.type;
const curTab = ref<string>(route.query.show ? 'tab2' : 'tab1'); const curTab = ref<string>(route.query.show ? 'tab2' : 'tab1');
const config = ref<any[]>([]); const config = ref<any[]>([]);
const info = ref<Record<string, any>>(null); const info = ref<Record<string, any>>(null);
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>();
const userName = ref<string>(); const userName = ref<string>();
let form = reactive<RuleForm>({
const form = reactive<RuleForm>({
...getIds(), ...getIds(),
productDefinition: '', productDefinition: '',
productName: '', productName: '',
@ -399,7 +349,7 @@ let form = reactive<RuleForm>({
modeRepayment: [], modeRepayment: [],
otherPurposesOfLoan: '', otherPurposesOfLoan: '',
productObject: '', productObject: '',
productType: computed(() => +route.query.type), productType: '',
providentFundAndSocialSecurity: '', providentFundAndSocialSecurity: '',
whetherToSupportEarlyRepayment: false, whetherToSupportEarlyRepayment: false,
creditSelectedStatus: '', creditSelectedStatus: '',
@ -414,56 +364,117 @@ const rules = reactive<FormRules<RuleForm>>({
modeRepayment: [{ required: true, message: '请选择还款方式', trigger: 'change' }], modeRepayment: [{ required: true, message: '请选择还款方式', trigger: 'change' }],
}); });
// tab
const tabChange = (tab: TabsPaneContext, event: Event) => {
console.log(tab, event);
};
// //
const getConfig = async () => { const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(form.productType === 1 ? 45 : 44); const { process } = await getProcessInformationBasedOnRoles(productType === 1 ? 45 : 44);
config.value = process; config.value = process;
}; };
// //
const getDetail = async () => { const getDetail = async () => {
if (!route.query.show) curTab.value = 'tab1'; if (!Cookies.get('sand-submit')) {
userName.value = await getUsername(); if (!route.query.show) curTab.value = 'tab1';
userName.value = await getUsername();
info.value = null;
if (id.value) { info.value = null;
try { if (id.value) {
// name try {
const { data } = await findById(id.value); // name
info.value = data; const { data } = await findById(id.value);
info.value = data;
// id
const res = await elementDetail(id.value); // id
if (res) { const res = await elementDetail(id.value);
const e = res.data.bankProducts; if (res) {
e.currentWorkingLife = e.currentWorkingLife.split(',').map((n) => +n); const e = res.data.bankProducts;
e.educationalRequirements = e.educationalRequirements.split(',').map((n) => +n); e.currentWorkingLife = e.currentWorkingLife.split(',').map((n) => +n);
e.modeRepayment = e.modeRepayment.split(',').map((n) => +n); e.educationalRequirements = e.educationalRequirements.split(',').map((n) => +n);
e.whetherToSupportEarlyRepayment = !!e.whetherToSupportEarlyRepayment; e.modeRepayment = e.modeRepayment.split(',').map((n) => +n);
e.bankGuaranteeTypeIds = []; e.whetherToSupportEarlyRepayment = !!e.whetherToSupportEarlyRepayment;
if (e.bankGuaranteeAllocationList) { e.bankGuaranteeTypeIds = [];
e.bankGuaranteeAllocationList.map((n) => { if (e.bankGuaranteeAllocationList) {
n.guaranteeTypeId && e.bankGuaranteeTypeIds.push(n.guaranteeTypeId); e.bankGuaranteeAllocationList.map((n) => {
}); n.guaranteeTypeId && e.bankGuaranteeTypeIds.push(n.guaranteeTypeId);
});
}
for (const i in e) {
if (e.hasOwnProperty(i)) {
form[i] = e[i];
}
}
} }
form = Object.assign(form, e); } finally {
} }
} finally {
} }
} }
}; };
watch( watch(
() => route.query, () => route.query,
() => { () => {
getDetail(); route.params.action === 'add' && getDetail();
}, },
{ {
immediate: true, immediate: true,
}, },
); );
//
const addRecord = async (data: Record<string, any>) => {
getStat(299);
const isEnterprise = productType === 1;
const preIds = `1,${Cookies.get('sand-level')},41,${productType ? 45 : 44}`; // 1id/44/45
const lcRule: Array<Record<string, any>> = [
handleId(48, 1, data.productDefinition, `${preIds},48`, 3),
handleId(49, 2, data.productName, `${preIds},49`, 3),
handleId(50, 3, 1, `${preIds},50`, 1),
];
//
if (isEnterprise) {
//
lcRule.push(
handleId(62, 7, data.productObject, `${preIds},61,62`, 1),
handleId(63, 8, `${data.minimumAge}~${data.maximumAge}`, `${preIds},61,63`, 5),
handleId(65, 19, data.loanPurpose, `${preIds},65`, 1),
);
} else {
//
data.ageSelectedState && lcRule.push(handleId(1235, 324, data.ageSelectedState, `${preIds},51,1234,1235`, 1));
data.ageSelectedState === 795 && lcRule.push(handleId(1236, 41, `${data.minimumAge}~${data.maximumAge}`, `${preIds},51,1234,1236`, 5));
data.degreeSelectedStatus && lcRule.push(handleId(1238, 324, data.degreeSelectedStatus, `${preIds},51,1237,1238`, 1));
data.degreeSelectedStatus === 795 && lcRule.push(handleId(1239, 42, data.educationalRequirements, `${preIds},51,1237,1239`, 1));
data.workingLifeSelectedState && lcRule.push(handleId(1241, 324, data.workingLifeSelectedState, `${preIds},51,1240,1241`, 1));
data.workingLifeSelectedState === 795 && lcRule.push(handleId(1242, 43, data.currentWorkingLife, `${preIds},51,1240,1242`, 1));
data.providentFundAndSocialSecurity && lcRule.push(handleId(1244, 324, data.providentFundAndSocialSecurity, `${preIds},51,1243,1244`, 1)); //
lcRule.push(handleId(1316, 328, data.loanPurpose, `${preIds},52,1316`, 1));
data.loanPurpose === 822 && lcRule.push(handleId(1317, 11, data.otherPurposesOfLoan, `${preIds},52,1317`, 3));
}
//
data.creditSelectedStatus && lcRule.push(handleId(108, 324, data.creditSelectedStatus, `${preIds},53,108`, 1));
data.guaranteeLoanSelectedStatus && lcRule.push(handleId(109, 324, data.guaranteeLoanSelectedStatus, `${preIds},53,109`, 1));
data.mortgageSelectedStatus && lcRule.push(handleId(1277, 324, data.mortgageSelectedStatus, `${preIds},53,110,1277`, 1));
data.hypothecatedSelectedStatus && lcRule.push(handleId(1278, 324, data.hypothecatedSelectedStatus, `${preIds},53,111,1278`, 1));
data.mortgageSelectedStatus === 795 && lcRule.push(handleId(1275, 13, data.bankGuaranteeTypeIds.filter((e: number) => e > 22 && e < 33).join(), `${preIds},53,110,1275`, 1));
data.hypothecatedSelectedStatus === 795 && lcRule.push(handleId(1276, 14, data.bankGuaranteeTypeIds.filter((e: number) => e > 32 && e < 38).join(), `${preIds},53,111,1276`, 1));
lcRule.push(
handleId(54, 15, `${data.minimumLoan}~${data.loanCeiling}`, `${preIds},54`, 5),
handleId(55, 16, `${data.minimumAprOnLoan}~${data.maximumAnnualInterestRate}`, `${preIds},55`, 5),
handleId(56, 17, `${data.minimumTermOfLoan}~${data.maximumTermOfLoan}`, `${preIds},56`, 5),
handleId(57, 18, data.modeRepayment, `${preIds},57`, 1),
);
lcRule.push(handleId(58, 140, data.whetherToSupportEarlyRepayment ? 345 : 346, `${preIds},58`, 1));
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: lcRule,
});
};
// //
const submit = async (formEl: FormInstance | undefined) => { const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return; if (!formEl) return;
@ -471,12 +482,11 @@ const submit = async (formEl: FormInstance | undefined) => {
if (valid) { if (valid) {
try { try {
const param = JSON.parse(JSON.stringify(form)); const param = JSON.parse(JSON.stringify(form));
// //
if (param.productType) { if (productType) {
if (!param.productObject) return ElMessage.error('请选择企业类型'); if (!param.productObject) return ElMessage.error('请选择企业类型');
} }
if ((!param.productType && param.ageSelectedState === 795) || param.productType) { if ((!param.productType && param.ageSelectedState === 795) || productType) {
if (!param.minimumAge) return ElMessage.error('请输入最小年龄'); if (!param.minimumAge) return ElMessage.error('请输入最小年龄');
if (!param.maximumAge) return ElMessage.error('请输入最大年龄'); if (!param.maximumAge) return ElMessage.error('请输入最大年龄');
if (isIllegalNum(param.minimumAge) || isIllegalNum(param.maximumAge)) return ElMessage.error('请输入合理的年龄'); if (isIllegalNum(param.minimumAge) || isIllegalNum(param.maximumAge)) return ElMessage.error('请输入合理的年龄');
@ -484,7 +494,7 @@ const submit = async (formEl: FormInstance | undefined) => {
} }
// //
if (!param.productType) { if (!productType) {
if (param.degreeSelectedStatus === 795 && !param.educationalRequirements.length) return ElMessage.error('请选择学历要求'); if (param.degreeSelectedStatus === 795 && !param.educationalRequirements.length) return ElMessage.error('请选择学历要求');
if (param.workingLifeSelectedState === 795 && !param.currentWorkingLife.length) return ElMessage.error('请选择工作年限'); if (param.workingLifeSelectedState === 795 && !param.currentWorkingLife.length) return ElMessage.error('请选择工作年限');
} }
@ -494,7 +504,7 @@ const submit = async (formEl: FormInstance | undefined) => {
if (isIllegalNum(param.minimumTermOfLoan) || isIllegalNum(param.maximumTermOfLoan) || +param.minimumTermOfLoan > +param.maximumTermOfLoan) if (isIllegalNum(param.minimumTermOfLoan) || isIllegalNum(param.maximumTermOfLoan) || +param.minimumTermOfLoan > +param.maximumTermOfLoan)
return ElMessage.error('请输入合理的贷款期限'); return ElMessage.error('请输入合理的贷款期限');
if (!param.productType && param.ageSelectedState !== 795) { if (!productType && param.ageSelectedState !== 795) {
param.minimumAge = ''; param.minimumAge = '';
param.maximumAge = ''; param.maximumAge = '';
} }
@ -537,6 +547,7 @@ const submit = async (formEl: FormInstance | undefined) => {
} }
}); });
param.addBankProductsGuarantyStyleReqList = graIds; param.addBankProductsGuarantyStyleReqList = graIds;
param.productType = productType;
let res; let res;
if (id.value) { if (id.value) {
param.id = id.value; param.id = id.value;
@ -558,63 +569,6 @@ const submit = async (formEl: FormInstance | undefined) => {
} }
}); });
}; };
//
const addRecord = async (data: Record<string, any>) => {
const isEnterprise = data.productType === 1;
const preIds = `1,${Cookies.get('sand-level')},41,${data.productType ? 45 : 44}`; // 1id/44/45
const lcRule: Array<Record<string, any>> = [
handleId(48, 1, data.productDefinition, preIds + ',48', 3),
handleId(49, 2, data.productName, preIds + ',49', 3),
handleId(50, 3, 1, preIds + ',50', 1),
];
//
if (isEnterprise) {
//
lcRule.push(
handleId(62, 7, data.productObject, preIds + ',61,62', 1),
handleId(63, 8, data.minimumAge + '~' + data.maximumAge + '', preIds + ',61,63', 5),
handleId(65, 19, data.loanPurpose, preIds + ',65', 1),
);
} else {
//
data.ageSelectedState && lcRule.push(handleId(1235, 324, data.ageSelectedState, preIds + ',51,1234,1235', 1));
data.ageSelectedState === 795 && lcRule.push(handleId(1236, 41, data.minimumAge + '~' + data.maximumAge, preIds + ',51,1234,1236', 5));
data.degreeSelectedStatus && lcRule.push(handleId(1238, 324, data.degreeSelectedStatus, preIds + ',51,1237,1238', 1));
data.degreeSelectedStatus === 795 && lcRule.push(handleId(1239, 42, data.educationalRequirements, preIds + ',51,1237,1239', 1));
data.workingLifeSelectedState && lcRule.push(handleId(1241, 324, data.workingLifeSelectedState, preIds + ',51,1240,1241', 1));
data.workingLifeSelectedState === 795 && lcRule.push(handleId(1242, 43, data.currentWorkingLife, preIds + ',51,1240,1242', 1));
data.providentFundAndSocialSecurity && lcRule.push(handleId(1244, 324, data.providentFundAndSocialSecurity, preIds + ',51,1243,1244', 1)); //
lcRule.push(handleId(1316, 328, data.loanPurpose, preIds + ',52,1316', 1));
data.loanPurpose === 822 && lcRule.push(handleId(1317, 11, data.otherPurposesOfLoan, preIds + ',52,1317', 3));
}
//
data.creditSelectedStatus && lcRule.push(handleId(108, 324, data.creditSelectedStatus, preIds + ',53,108', 1));
data.guaranteeLoanSelectedStatus && lcRule.push(handleId(109, 324, data.guaranteeLoanSelectedStatus, preIds + ',53,109', 1));
data.mortgageSelectedStatus && lcRule.push(handleId(1277, 324, data.mortgageSelectedStatus, preIds + ',53,110,1277', 1));
data.hypothecatedSelectedStatus && lcRule.push(handleId(1278, 324, data.hypothecatedSelectedStatus, preIds + ',53,111,1278', 1));
data.mortgageSelectedStatus === 795 && lcRule.push(handleId(1275, 13, data.bankGuaranteeTypeIds.filter((e: number) => e > 22 && e < 33).join(), preIds + ',53,110,1275', 1));
data.hypothecatedSelectedStatus === 795 && lcRule.push(handleId(1276, 14, data.bankGuaranteeTypeIds.filter((e: number) => e > 32 && e < 38).join(), preIds + ',53,111,1276', 1));
lcRule.push(
handleId(54, 15, data.minimumLoan + '~' + data.loanCeiling, preIds + ',54', 5),
handleId(55, 16, data.minimumAprOnLoan + '~' + data.maximumAnnualInterestRate, preIds + ',55', 5),
handleId(56, 17, data.minimumTermOfLoan + '~' + data.maximumTermOfLoan, preIds + ',56', 5),
handleId(57, 18, data.modeRepayment, preIds + ',57', 1),
);
lcRule.push(handleId(58, 140, data.whetherToSupportEarlyRepayment ? 345 : 346, preIds + ',58', 1));
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: lcRule,
});
};
onMounted(() => { onMounted(() => {
getConfig(); getConfig();
}); });

@ -1,34 +1,17 @@
<template> <template>
<div> <div>
<el-tabs v-model="curTab"> <el-tabs v-model="curTab">
<el-tab-pane label="审批" <el-tab-pane label="审批" name="tab1">
name="tab1">
<div class="h-[calc(100vh-170px)] pr-1 overflow-auto"> <div class="h-[calc(100vh-170px)] pr-1 overflow-auto">
<info ref="infoRef" <info ref="infoRef" @updateAudits="updateAudits" />
@updateAudits="updateAudits" /> <el-form ref="formRef" :model="form" :rules="rules" label-width="100px" label-suffix="" class="form pt-5 mt-5 border-t border-t-solid border-t-[#EDF1F5]" status-icon>
<el-form ref="formRef" <el-form-item label="审批意见" prop="status">
:model="form" <el-select v-model="form.status" placeholder="请选择">
:rules="rules" <el-option v-for="(item, i) in autids" :key="i" :label="item.name" :value="item.id" />
label-width="100px"
label-suffix=":"
class="form pt-5 mt-5 border-t border-t-solid border-t-[#EDF1F5]"
status-icon>
<el-form-item label="审批意见"
prop="status">
<el-select v-model="form.status"
placeholder="请选择">
<el-option v-for="(item, i) in autids"
:key="i"
:label="item.name"
:value="item.id" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="意见描述" <el-form-item label="意见描述" prop="opinionDescription">
prop="opinionDescription"> <el-input type="textarea" placeholder="审批意见500字以内。" maxlength="500" v-model="form.opinionDescription"></el-input>
<el-input type="textarea"
placeholder="审批意见500字以内。"
maxlength="500"
v-model="form.opinionDescription"></el-input>
</el-form-item> </el-form-item>
<div class="flex flex-col items-end"> <div class="flex flex-col items-end">
<div class="mb-[18px] text-sm leading-[1.6]"> <div class="mb-[18px] text-sm leading-[1.6]">
@ -37,16 +20,12 @@
</div> </div>
<div class="inline-flex items-center mb-[18px] text-sm leading-[1.6]"> <div class="inline-flex items-center mb-[18px] text-sm leading-[1.6]">
<span class="text-sm font-semibold">审批员</span> <span class="text-sm font-semibold">审批员</span>
<span v-if="signed" <span v-if="signed" class="text-lg text-[#f00]">{{ signed }}</span>
class="text-lg text-[#f00]">{{ signed }}</span> <span v-else class="py-2 px-5 ml-1 text-sm text-white bg-[#006BFF] cursor-pointer" @click="sign">签章</span>
<span v-else
class="py-2 px-5 ml-1 text-sm text-white bg-[#006BFF] cursor-pointer"
@click="sign">签章</span>
</div> </div>
</div> </div>
<div class="flex justify-end"> <div class="flex justify-end">
<div class="submit" <div class="submit" @click="submit(formRef)">审批</div>
@click="submit(formRef)">审批</div>
</div> </div>
</el-form> </el-form>
</div> </div>
@ -58,16 +37,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, reactive, onMounted, watch } from 'vue'; import { ref, computed, reactive, onMounted, watch } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import type { TabsPaneContext, FormInstance, FormRules } from 'element-plus'; import type { FormInstance, FormRules } from 'element-plus';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import Info from './Info.vue';
import { handleId, getIds, getNow, getUsername } from '@/utils/common'; import { handleId, getIds, getNow, getUsername } from '@/utils/common';
import { examineAndApprove } from '@/api/bank'; import { examineAndApprove } from '@/api/bank';
import { getOperationTime } from '@/api/config'; import { getOperationTime } from '@/api/config';
import { addOperation } from '@/api/judgment'; import { addOperation } from '@/api/judgment';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { productState } from '@/store/useProduct'; import { productState, getStat } from '@/store/useProduct';
import Info from './Info.vue';
const emit = defineEmits(['getList']); const emit = defineEmits(['getList']);
interface RuleForm { interface RuleForm {
@ -98,7 +77,7 @@ const signed = ref<string>();
// //
const updateAudits = (count: number) => { const updateAudits = (count: number) => {
if (count >= 2) { if (count >= 9) {
autids.value.pop(); autids.value.pop();
} }
}; };
@ -116,7 +95,7 @@ const sign = async () => {
}; };
// //
const addRecord = async (data: Record<string, any>) => { const addRecord = async (data: Record<string, any>) => {
const approved = !!infoRef.value.info.approvalTime; // id const approved = data.status !== 299; // id
const preIds = `1,${levelId},43,${approved ? 1219 : 1218}`; // 1id const preIds = `1,${levelId},43,${approved ? 1219 : 1218}`; // 1id
const lcRule = [ const lcRule = [
handleId(approved ? 1215 : 145, 69, data.status, `${preIds},${approved ? '1215' : '145'}`, 1), handleId(approved ? 1215 : 145, 69, data.status, `${preIds},${approved ? '1215' : '145'}`, 1),
@ -140,6 +119,7 @@ const submit = async (formEl: FormInstance | undefined) => {
await examineAndApprove(param.id, param.opinionDescription, param.status, param.approvalTime); await examineAndApprove(param.id, param.opinionDescription, param.status, param.approvalTime);
router.push(`/product/bank/detail?type=${route.query.type || ''}&i=${route.query.i}&role=${route.query.role}&id=${id.value}`); router.push(`/product/bank/detail?type=${route.query.type || ''}&i=${route.query.i}&role=${route.query.role}&id=${id.value}`);
getStat(296);
addRecord(param); addRecord(param);
ElMessage.success('提交成功!'); ElMessage.success('提交成功!');
emit('getList'); emit('getList');
@ -149,7 +129,6 @@ const submit = async (formEl: FormInstance | undefined) => {
}); });
}; };
onMounted(async () => { onMounted(async () => {
console.log(11);
date.value = dayjs(await getNow()).format('YYYY-MM-DD'); date.value = dayjs(await getNow()).format('YYYY-MM-DD');
}); });
watch( watch(

@ -1,34 +1,24 @@
<template> <template>
<div class="block card-list flex py-0"> <div class="block card-list flex py-0">
<div class="left"> <div class="left">
<div v-if="role == 41" <div
class="flex justify-center items-center py-2 mb-3 text-sm text-[#006BFF] bg-[rgba(0,107,255,0.1)] border border-solid border-[#006BFF] rounded-[10px] cursor-pointer" v-if="role == 41"
@click="toAdd"> class="flex justify-center items-center py-2 mb-3 text-sm text-[#006BFF] bg-[rgba(0,107,255,0.1)] border border-solid border-[#006BFF] rounded-[10px] cursor-pointer"
<el-icon class="mr-1" @click="toAdd"
:size="16" >
color="#006BFF"> <el-icon class="mr-1" :size="16" color="#006BFF">
<Plus /> <Plus />
</el-icon> </el-icon>
新增产品 新增产品
</div> </div>
<div class="flex justify-end mb-4"> <div class="flex justify-end mb-4">
<img src="@/assets/images/fold.png" <img src="@/assets/images/fold.png" alt="" class="cursor-pointer" @click="toList" />
alt=""
class="cursor-pointer"
@click="toList" />
</div> </div>
<ul class="products"> <ul class="products">
<li v-for="(item, i) in list" <li v-for="(item, i) in list" :key="i" :class="{ active: item.id === id }" @click="switchProduct(item)">
:key="i" <el-popconfirm v-if="role == 41" title="您确定删除吗?" @confirm="handleDelete(item.id)">
:class="{ active: item.id === id }"
@click="switchProduct(item)">
<el-popconfirm v-if="role == 41"
title="您确定删除吗?"
@confirm="handleDelete(item.id)">
<template #reference> <template #reference>
<img src="@/assets/images/trash.png" <img src="@/assets/images/trash.png" alt="" class="del" />
alt=""
class="del" />
</template> </template>
</el-popconfirm> </el-popconfirm>
@ -40,42 +30,32 @@
</ul> </ul>
</div> </div>
<div class="right"> <div class="right">
<!-- <component :is="currentSubApp" <config v-if="action === 'config'" :key="actionKey" @getList="getList"></config>
@getList="getList"></component> -->
<config v-if="action === 'config'"
:key="actionKey"
@getList="getList"></config>
<detail v-if="action === 'detail'"></detail> <detail v-if="action === 'detail'"></detail>
<add v-else-if="action === 'add'" <add v-else-if="action === 'add'" :key="actionKey" @getList="getList"></add>
:key="actionKey" <approve v-else-if="action === 'approve'" :key="actionKey" @getList="getList"></approve>
@getList="getList"></add>
<approve v-else-if="action === 'approve'"
:key="actionKey"
@getList="getList"></approve>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, ref, watch, defineAsyncComponent } from 'vue'; import { computed, onMounted, ref, watch } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { Plus } from '@element-plus/icons-vue'; import { Plus } from '@element-plus/icons-vue';
import { bankingProductsList, batchDeletion } from '@/api/bank'; import { bankingProductsList, batchDeletion } from '@/api/bank';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import { getStatus } from '@/store/useProduct'; import { getStatus } from '@/store/useProduct';
import { getIds } from '@/utils/common';
import Cookies from 'js-cookie';
import Config from './Config.vue'; import Config from './Config.vue';
import Detail from './Detail.vue'; import Detail from './Detail.vue';
import Add from './Add.vue'; import Add from './Add.vue';
import Approve from './Approve.vue'; import Approve from './Approve.vue';
import Cookies from 'js-cookie';
import { getIds } from '@/utils/common';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
const action = ref<any>(''); const action = ref<any>('');
// const modules: any = import.meta.glob('./*.vue');
// let currentSubApp = defineAsyncComponent(modules[`./${route.params.action}.vue`]);
const list = ref<Array<any>>([]); const list = ref<Array<any>>([]);
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
const productType = computed(() => route.query.type); // / const productType = computed(() => route.query.type); // /
@ -84,28 +64,28 @@ const id = computed(() => +route.query.id);
const actionKey = ref<number>(1); const actionKey = ref<number>(1);
// //
const getList = async (refresh?: number) => { const getList = async (refresh?: number) => {
loading.value = true; if (!Cookies.get('sand-submit')) {
try { loading.value = true;
const { data } = await bankingProductsList({ try {
...getIds(), const { data } = await bankingProductsList({
pageNum: 1, ...getIds(),
pageSize: 1000, pageNum: 1,
productType: productType.value, pageSize: 1000,
roleId: route.query.role, productType: productType.value,
keyWord: route.query.name ?? '', roleId: route.query.role,
createDateSort: route.query.createDateSort ?? '', keyWord: route.query.name ?? '',
guarantyStyleId: route.query.guarantyStyleId ?? '', createDateSort: route.query.createDateSort ?? '',
status: route.query.status ?? '', guarantyStyleId: route.query.guarantyStyleId ?? '',
}); status: route.query.status ?? '',
list.value = data.message.records; });
((route.path !== '/product/bank/add' && list.value.length && !id.value) || refresh) && switchProduct(list.value[0], refresh); list.value = data.message.records;
} finally { ((route.path !== '/product/bank/add' && list.value.length && !id.value) || refresh) && switchProduct(list.value[0], refresh);
loading.value = false; } finally {
loading.value = false;
}
} }
}; };
onMounted(() => { onMounted(getList);
getList();
});
watch( watch(
route, route,

File diff suppressed because it is too large Load Diff

@ -1,8 +1,7 @@
<template> <template>
<div> <div>
<el-tabs v-model="curTab"> <el-tabs v-model="curTab">
<el-tab-pane :label="status" <el-tab-pane :label="status" name="tab1">
name="tab1">
<div class="h-[calc(100vh-170px)] pr-1 overflow-auto"> <div class="h-[calc(100vh-170px)] pr-1 overflow-auto">
<info /> <info />
</div> </div>

@ -1,14 +1,12 @@
<template> <template>
<div class="info my-2"> <div class="info my-2">
<h1 v-if="riskInfo" <h1 v-if="riskInfo" class="mb-3 text-xl font-semibold text-center">{{ info.productName }}产品手册</h1>
class="mb-3 text-xl font-semibold text-center">{{ info.productName }}产品手册</h1>
<h6 class="step-name">{{ route.params.action !== 'config' ? '一、' : '' }}产品定义</h6> <h6 class="step-name">{{ route.params.action !== 'config' ? '一、' : '' }}产品定义</h6>
<p class="text">{{ info.productDefinition }}</p> <p class="text">{{ info.productDefinition }}</p>
<h6 class="step-name mt-5">{{ route.params.action !== 'config' ? '二、' : '' }}产品要素</h6> <h6 class="step-name mt-5">{{ route.params.action !== 'config' ? '二、' : '' }}产品要素</h6>
<p class="text">产品名称{{ info.productName }}</p> <p class="text">产品名称{{ info.productName }}</p>
<p class="text">贷款币种人民币</p> <p class="text">贷款币种人民币</p>
<p v-if="info.loanPurpose" <p v-if="info.loanPurpose" class="text">
class="text">
贷款用途{{ 贷款用途{{
info.loanPurpose === '购房' info.loanPurpose === '购房'
? '可用于住房按揭贷款、二手房住房按揭贷款。' ? '可用于住房按揭贷款、二手房住房按揭贷款。'
@ -23,11 +21,9 @@
: info.otherPurposesOfLoan : info.otherPurposesOfLoan
}} }}
</p> </p>
<div v-if="info.guarantyStyle" <div v-if="info.guarantyStyle" class="flex my-2">
class="flex my-2">
<p class="text whitespace-nowrap">担保方式</p> <p class="text whitespace-nowrap">担保方式</p>
<p v-html="info.guarantyStyle" <p v-html="info.guarantyStyle" class="text"></p>
class="text"></p>
</div> </div>
<p class="text">贷款期限{{ info.minimumTermOfLoan }} - {{ info.maximumTermOfLoan }}</p> <p class="text">贷款期限{{ info.minimumTermOfLoan }} - {{ info.maximumTermOfLoan }}</p>
@ -35,73 +31,88 @@
<p class="text">贷款利率{{ info.minimumAprOnLoan }}% - {{ info.maximumAnnualInterestRate }}%</p> <p class="text">贷款利率{{ info.minimumAprOnLoan }}% - {{ info.maximumAnnualInterestRate }}%</p>
<p class="text">还款方式{{ info.modeRepayment }}</p> <p class="text">还款方式{{ info.modeRepayment }}</p>
<div v-if="info.prospectiveBorrowerText" <div v-if="info.prospectiveBorrowerText" class="flex my-2">
class="flex my-2">
<p class="text whitespace-nowrap">适用条件</p> <p class="text whitespace-nowrap">适用条件</p>
<div class="text" <div class="text" v-html="info.prospectiveBorrowerText"></div>
v-html="info.prospectiveBorrowerText"></div>
</div> </div>
<template v-if="riskInfo"> <template v-if="riskInfo">
<h6 class="step-name mt-5">{{ route.params.action !== 'add' ? '三、' : '' }}材料要求</h6> <h6 class="step-name mt-5">{{ route.params.action !== 'add' ? '三、' : '' }}材料要求</h6>
<p v-if="riskInfo?.accountMaterials" <p v-if="riskInfo?.accountMaterials" class="text">办理账户-提供材料{{ riskInfo?.accountMaterials }}</p>
class="text">办理账户-提供材料{{ riskInfo?.accountMaterials }}</p> <p v-if="riskInfo?.sendingAccount" class="text">办理账户-发放账户借记卡或放款专户</p>
<p v-if="riskInfo?.sendingAccount" <p v-if="riskInfo?.loanApplicationMethod" class="text">贷款申请-申请方式{{ riskInfo?.loanApplicationMethod }}</p>
class="text">办理账户-发放账户借记卡或放款专户</p> <p v-if="riskInfo?.borrowerMaterial" class="text">贷款申请-提供材料-借款人材料{{ riskInfo?.borrowerMaterial }}</p>
<p v-if="riskInfo?.loanApplicationMethod"
class="text">贷款申请-申请方式{{ riskInfo?.loanApplicationMethod }}</p>
<p v-if="riskInfo?.borrowerMaterial"
class="text">贷款申请-提供材料-借款人材料{{ riskInfo?.borrowerMaterial }}</p>
<template v-if="info.productType"> <template v-if="info.productType">
<p v-if="riskInfo?.enterpriseMaterial" <p v-if="riskInfo?.enterpriseMaterial" class="text">贷款申请-提供材料-企业材料{{ riskInfo?.enterpriseMaterial }}</p>
class="text">贷款申请-提供材料-企业材料{{ riskInfo?.enterpriseMaterial }}</p> <p v-if="riskInfo?.collateral" class="text">贷款申请-提供材料-抵押物{{ riskInfo?.collateral }}</p>
<p v-if="riskInfo?.collateral"
class="text">贷款申请-提供材料-抵押物{{ riskInfo?.collateral }}</p>
</template> </template>
<template v-else> <template v-else>
<p v-if="riskInfo?.mateMaterial" <p v-if="riskInfo?.mateMaterial" class="text">贷款申请-提供材料-配偶材料{{ riskInfo?.mateMaterial }}</p>
class="text">贷款申请-提供材料-配偶材料{{ riskInfo?.mateMaterial }}</p> <p v-if="riskInfo?.businessMaterials" class="text">贷款申请-提供材料-经营类材料{{ riskInfo?.businessMaterials }}</p>
<p v-if="riskInfo?.businessMaterials" </template>
class="text">贷款申请-提供材料-经营类材料{{ riskInfo?.businessMaterials }}</p> <p v-if="riskInfo?.supplementaryMaterials" class="text">贷款申请-提供材料-补充材料{{ riskInfo?.supplementaryMaterials }}</p>
<p v-if="riskInfo?.runBatchObject" class="text">系统跑批准入风控策略-跑批对象{{ riskInfo?.runBatchObject }}</p>
<template v-if="info.bankRiskControlAllocationTacticsList && info.bankRiskControlAllocationTacticsList.length">
<template v-for="(item, i) in info.bankRiskControlAllocationTacticsList">
<p v-if="item.tacticsSelectedStatus" :key="i" class="text flex">
系统跑批{{ item.pointName }}{{ item.tacticsName || '无需跑批' }}
<img v-if="item.tacticsName" src="@/assets/svgs/preview.svg" alt="" class="cursor-pointer ml-2" @click="preview(item, i)" />
</p>
</template>
</template>
<template v-if="info.creditScoringStrategyList && info.creditScoringStrategyList.length">
<template v-for="(item, i) in info.creditScoringStrategyList">
<p v-if="item.tacticsSelectedStatus" :key="i" class="text flex">
系统跑批{{ item.pointName }}{{ item.tacticsName || '无需跑批' }}
<img v-if="item.tacticsName" src="@/assets/svgs/preview.svg" alt="" class="cursor-pointer ml-2" @click="previewCredits(item, i)" />
</p>
</template>
</template>
<p v-if="info?.personalRiskDegreeStrategySelectedStatus === 803 || info?.enterpriseRiskDegreeStrategySelectedStatus === 803" class="text">
系统跑批风险度策略
{{ info?.personalRiskDegreeStrategySelectedStatus === 803 ? '个人风险度策略' : '' }}
{{ info?.personalRiskDegreeStrategySelectedStatus === 803 && info?.enterpriseRiskDegreeStrategySelectedStatus === 803 ? ',' : '' }}
{{ info?.enterpriseRiskDegreeStrategySelectedStatus === 803 ? '企业风险度策略' : '' }}
</p>
<template v-if="info.interestRatePricingModelList && info.interestRatePricingModelList.length">
<template v-for="(item, i) in info.interestRatePricingModelList">
<p v-if="item.tacticsSelectedStatus" :key="i" class="text flex">
系统跑批{{ item.pointName }}{{ item.tacticsName || '无需跑批' }}
<img v-if="item.tacticsName" src="@/assets/svgs/preview.svg" alt="" class="cursor-pointer ml-2" @click="previewRate(item, i)" />
</p>
</template>
</template>
<p v-if="info?.enterpriseQuotaModelStr" class="text">系统跑批企业额度模型{{ info?.enterpriseQuotaModelStr }}</p>
<p v-if="riskInfo?.dueDiligenceMode" class="text">尽职调查-尽调方式{{ riskInfo?.dueDiligenceMode }}</p>
<p v-if="riskInfo?.dueDiligenceContent" class="text">尽职调查-尽调内容{{ riskInfo?.dueDiligenceContent }}</p>
<p v-if="riskInfo?.reviewContent" class="text">贷款审查-审查内容{{ riskInfo?.reviewContent }}</p>
<p v-if="riskInfo?.reviewSignature" class="text">贷款审查-审查签字{{ riskInfo?.reviewSignature }}</p>
<p v-if="riskInfo?.reviewApproveContent" class="text">贷款审批-审批内容{{ riskInfo?.reviewApproveContent }}</p>
<p v-if="riskInfo?.approvalSignature" class="text">贷款审批-审批签字{{ riskInfo?.approvalSignature }}</p>
<p v-if="riskInfo?.contractMaterials" class="text">签订合同-提供的材料{{ riskInfo?.contractMaterials }}</p>
<p v-if="riskInfo?.loanContract" class="text">需要签订借贷合同{{ riskInfo?.loanContract }}</p>
<p v-if="riskInfo?.mortgageContract" class="text">需要签订抵押合同{{ riskInfo?.mortgageContract }}</p>
<p v-if="riskInfo?.pledgeContract" class="text">需要签订质押合同{{ riskInfo?.pledgeContract }}</p>
<p v-if="riskInfo?.guaranteeContract" class="text">需要签订担保合同{{ riskInfo?.guaranteeContract }}</p>
<template v-if="info.postLoanSelectionStrategyList && info.postLoanSelectionStrategyList.length">
<template v-for="(item, i) in info.postLoanSelectionStrategyList">
<p v-if="item.tacticsSelectedStatus" :key="i" class="text flex">
系统跑批{{ item.pointName }}{{ item.tacticsName || '无需跑批' }}
<img v-if="item.tacticsName" src="@/assets/svgs/preview.svg" alt="" class="cursor-pointer ml-2" @click="previewAfter(item, i)" />
</p>
</template>
</template> </template>
<p v-if="riskInfo?.supplementaryMaterials"
class="text">贷款申请-提供材料-补充材料{{ riskInfo?.supplementaryMaterials }}</p>
<p v-if="riskInfo?.runBatchObject"
class="text">系统跑批准入风控策略-跑批对象{{ riskInfo?.runBatchObject }}</p>
<p v-if="riskInfo?.accessStrategy"
class="text">系统跑批准入风控策略-准入策略{{ riskInfo?.accessStrategy }}</p>
<p v-if="riskInfo?.personalCreditScoringStrategies"
class="text">系统跑批准入风控策略-信用评分策略{{ riskInfo?.personalCreditScoringStrategies }}</p>
<p v-if="riskInfo?.riskDegreeStrategy"
class="text">系统跑批准入风控策略-风险度策略{{ riskInfo?.riskDegreeStrategy }}</p>
<p v-if="riskInfo?.interestRatePricingModel"
class="text">系统跑批准入风控策略-利率定价模型-{{ info.productType ? '企业' : '个人' }}额度模型{{ riskInfo?.interestRatePricingModel }}</p>
<p v-if="riskInfo?.individualInterestRateModel === '需要跑批'"
class="text">系统跑批准入风控策略-利率定价模型-{{ info.productType ? '企业' : '个人' }}利率模型</p>
<p v-if="riskInfo?.dueDiligenceMode"
class="text">尽职调查-尽调方式{{ riskInfo?.dueDiligenceMode }}</p>
<p v-if="riskInfo?.dueDiligenceContent"
class="text">尽职调查-尽调内容{{ riskInfo?.dueDiligenceContent }}</p>
<p v-if="riskInfo?.reviewContent"
class="text">贷款审查-审查内容{{ riskInfo?.reviewContent }}</p>
<p v-if="riskInfo?.reviewSignature"
class="text">贷款审查-审查签字{{ riskInfo?.reviewSignature }}</p>
<p v-if="riskInfo?.reviewApproveContent"
class="text">贷款审批-审批内容{{ riskInfo?.reviewApproveContent }}</p>
<p v-if="riskInfo?.approvalSignature"
class="text">贷款审批-审批签字{{ riskInfo?.approvalSignature }}</p>
<p v-if="riskInfo?.contractMaterials"
class="text">签订合同-提供的材料{{ riskInfo?.contractMaterials }}</p>
<p v-if="riskInfo?.loanContract"
class="text">签订合同-合同模板-借贷合同{{ riskInfo?.loanContract }}</p>
<p v-if="riskInfo?.mortgageContract"
class="text">签订合同-合同模板-抵押合同{{ riskInfo?.mortgageContract }}</p>
<p v-if="riskInfo?.pledgeContract"
class="text">签订合同-合同模板-质押合同{{ riskInfo?.pledgeContract }}</p>
<p v-if="riskInfo?.guaranteeContract"
class="text">签订合同-合同模板-担保合同{{ riskInfo?.guaranteeContract }}</p>
<p v-if="riskInfo?.selectionStrategy"
class="text">贷后管理-选择策略{{ riskInfo?.selectionStrategy }}</p>
<h6 class="step-name mt-5">{{ route.params.action !== 'add' ? '四、' : '' }}业务流程</h6> <h6 class="step-name mt-5">{{ route.params.action !== 'add' ? '四、' : '' }}业务流程</h6>
<p class="text">1贷款人APP向智信银行公司业务部门提交借款申请同时提交贷款用途证明文件以及有关资料</p> <p class="text">1贷款人APP向智信银行公司业务部门提交借款申请同时提交贷款用途证明文件以及有关资料</p>
@ -118,11 +129,8 @@
</template> </template>
</div> </div>
<div v-if="approvals.length" <div v-if="approvals.length" class="mt-10">
class="mt-10"> <div v-for="(item, i) in approvals" :key="i" class="audit">
<div v-for="(item, i) in approvals"
:key="i"
class="audit">
<div class="line"> <div class="line">
<span class="field">审批意见</span> <span class="field">审批意见</span>
<span class="status">{{ getStatus(item?.status) }}</span> <span class="status">{{ getStatus(item?.status) }}</span>
@ -132,23 +140,24 @@
{{ item.opinionDescription }} {{ item.opinionDescription }}
</div> </div>
<p class="mb-2 text-sm text-[#333] text-right">审查日期{{ item.approvalTime }}</p> <p class="mb-2 text-sm text-[#333] text-right">审查日期{{ item.approvalTime }}</p>
<p class="mb-2 text-sm text-[#333] text-right">审查员{{ userName }}</p> <p class="mb-2 text-sm text-[#333] text-right">{{ i === 10 ? '' : '审查员:' }}{{ item.examinationApprovalOfficer }}</p>
</div> </div>
</div> </div>
<el-drawer v-model="visible" :title="curPreviewTitle" size="100%" :z-index="10" class="model-drawer">
<component v-if="loadedComponents[activeComponent]" :is="loadedComponents[activeComponent]" v-model:row="curRow" disabled :key="curRow.strategyId" />
</el-drawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch, defineExpose } from 'vue'; import { ref, computed, watch, defineExpose, defineAsyncComponent, markRaw } from 'vue';
import { findById, approvalRecord } from '@/api/bank'; import { findById, approvalRecord } from '@/api/bank';
import { useRouter, useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import { getStatus } from '@/store/useProduct'; import { getStatus } from '@/store/useProduct';
import { getUsername } from '@/utils/common'; import { getUsername } from '@/utils/common';
import Cookies from 'js-cookie';
// const props = defineProps({
// tab: String,
// });
const emit = defineEmits(['updateAudits']); const emit = defineEmits(['updateAudits']);
const router = useRouter();
const route = useRoute(); const route = useRoute();
const id = computed(() => +route.query.id); const id = computed(() => +route.query.id);
const info = ref<Record<string, any>>({}); const info = ref<Record<string, any>>({});
@ -156,35 +165,115 @@ const riskInfo = ref<Record<string, any>>(null);
const approvals = ref<Record<string, any>[]>([]); const approvals = ref<Record<string, any>[]>([]);
const userName = ref<string>(); const userName = ref<string>();
const visible = ref<boolean>(false);
const curRow = ref<Record<string, any>>();
const curPreviewTitle = ref<string>();
const asyncComponents = {
'150': defineAsyncComponent(() => import('../strategy/150/Detail.vue')),
'151': defineAsyncComponent(() => import('../strategy/151/Detail.vue')),
'152': defineAsyncComponent(() => import('../strategy/152/Detail.vue')),
'153': defineAsyncComponent(() => import('../strategy/153/Detail.vue')),
'154': defineAsyncComponent(() => import('../strategy/154/Detail.vue')),
'155': defineAsyncComponent(() => import('../strategy/155/Detail.vue')),
'156': defineAsyncComponent(() => import('../strategy/156/Detail.vue')),
'512': defineAsyncComponent(() => import('../strategy/512/Detail.vue')),
'513': defineAsyncComponent(() => import('../strategy/513/Detail.vue')),
'772': defineAsyncComponent(() => import('../interestRate/772/Detail.vue')),
'935': defineAsyncComponent(() => import('../interestRate/935/Detail.vue')),
'936': defineAsyncComponent(() => import('../interestRate/936/Detail.vue')),
'1029': defineAsyncComponent(() => import('../afterLoan/1029/Detail.vue')),
'1030': defineAsyncComponent(() => import('../afterLoan/1030/Detail.vue')),
'1031': defineAsyncComponent(() => import('../afterLoan/1031/Detail.vue')),
'1032': defineAsyncComponent(() => import('../afterLoan/1032/Detail.vue')),
'1033': defineAsyncComponent(() => import('../afterLoan/1033/Detail.vue')),
};
const loadedComponents = markRaw({});
const activeComponent = ref<string>('');
//
const loadComponent = async (componentName: string) => {
if (!loadedComponents[componentName]) {
try {
loadedComponents[componentName] = asyncComponents[componentName];
activeComponent.value = componentName;
} catch (error) {
console.error(`Failed to load component ${componentName}`, error);
}
} else {
activeComponent.value = componentName;
}
};
// //
const getDetail = async () => { const getDetail = async () => {
userName.value = await getUsername(); if (!Cookies.get('sand-submit')) {
userName.value = await getUsername();
if (id.value) { if (id.value) {
try { try {
const { data } = await findById(id.value); const { data } = await findById(id.value);
info.value = data; info.value = data;
emit('updateAudits', data.rejectCount); if (info.value.riskControlDetails) riskInfo.value = data.riskControlDetails;
if (info.value.riskControlDetails) riskInfo.value = data.riskControlDetails;
const res = await approvalRecord({
const res = await approvalRecord({ id: id.value,
id: id.value, });
}); approvals.value = res.list;
approvals.value = res.list; emit('updateAudits', res.list.length);
} finally { } catch (e) {}
} }
} }
}; };
watch( watch(
() => route.query, () => route.query,
() => { () => {
getDetail(); route.path.startsWith('/product/bank') && getDetail();
}, },
{ {
immediate: true, immediate: true,
}, },
); );
//
const preview = async (row: Record<string, any>, i: number) => {
curRow.value = {
strategyId: row.tacticsId,
strategyName: row.tacticsName,
};
await loadComponent(Object.keys(asyncComponents)[i]);
curPreviewTitle.value = `查看${row.pointName}`;
visible.value = true;
};
//
const previewCredits = async (row: Record<string, any>, i: number) => {
curRow.value = {
id: row.tacticsId,
};
await loadComponent(i ? '513' : '512');
curPreviewTitle.value = `查看${row.pointName}`;
visible.value = true;
};
//
const previewRate = async (row: Record<string, any>, i: number) => {
curRow.value = {
id: row.tacticsId,
modelName: row.tacticsName,
};
await loadComponent(i === 2 ? '936' : i ? '772' : '935');
curPreviewTitle.value = `查看${row.pointName}`;
visible.value = true;
};
//
const previewAfter = async (row: Record<string, any>, i: number) => {
curRow.value = {
strategyId: row.tacticsId,
strategyName: row.tacticsName,
};
await loadComponent(Object.keys(asyncComponents)[i + 12]);
curPreviewTitle.value = `查看${row.pointName}`;
visible.value = true;
};
defineExpose({ defineExpose({
info, info,
}); });

@ -1,138 +1,79 @@
<template> <template>
<div class="block"> <div class="block">
<div class="flex justify-between items-center mb-5"> <div class="flex justify-between items-center mb-5">
<search v-model="params.keyWord" <search v-model="params.keyWord" @change="initList"></search>
@change="initList"></search>
<div class="filter"> <div class="filter">
<el-checkbox-group v-if="params.roleId == 42" <el-checkbox-group v-if="params.roleId == 42" class="mr-5" v-model="productTypes">
class="mr-5"
v-model="productTypes">
<el-checkbox :label="0">个人</el-checkbox> <el-checkbox :label="0">个人</el-checkbox>
<el-checkbox :label="1">企业</el-checkbox> <el-checkbox :label="1">企业</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
<div class="select"> <div class="select">
<el-select v-model="params.guarantyStyleId" <el-select v-model="params.guarantyStyleId" placeholder="担保方式" size="large">
placeholder="担保方式" <el-option label="担保方式" value="" />
size="large"> <el-option v-for="item in guarantees" :key="item.id" :label="item.name" :value="item.id" />
<el-option label="担保方式"
value="" />
<el-option v-for="item in guarantees"
:key="item.id"
:label="item.name"
:value="item.id" />
</el-select> </el-select>
<img src="@/assets/images/7.png" <img src="@/assets/images/7.png" alt="" class="icon" />
alt=""
class="icon" />
</div> </div>
<div class="select"> <div class="select">
<el-select v-model="params.status" <el-select v-model="params.status" placeholder="产品进度" size="large">
placeholder="产品进度" <el-option v-for="item in params.roleId == 43 ? getExpertStatus() : productState.status" :key="item.id" :label="item.name" :value="item.id" />
size="large">
<el-option v-for="item in params.roleId == 43 ? getExpertStatus() : productState.status"
:key="item.id"
:label="item.name"
:value="item.id" />
</el-select> </el-select>
<img src="@/assets/images/8.png" <img src="@/assets/images/8.png" alt="" class="icon" />
alt=""
class="icon" />
</div> </div>
<div v-if="params.roleId == 41" <div v-if="params.roleId == 41" class="add-btn" @click="toAdd">
class="add-btn" <img src="@/assets/images/plus.png" alt="" class="icon" />
@click="toAdd">
<img src="@/assets/images/plus.png"
alt=""
class="icon" />
新增产品 新增产品
</div> </div>
<img src="@/assets/images/9.png" <img src="@/assets/images/9.png" alt="" class="ml-4 cursor-pointer" @click="toCardList" />
alt=""
class="ml-4 cursor-pointer"
@click="toCardList" />
</div> </div>
</div> </div>
<el-table ref="table" <el-table ref="table" v-loading="loading" :data="list" @sort-change="handleSort">
v-loading="loading" <el-table-column prop="productName" label="产品名称" min-width="110"></el-table-column>
:data="list" <el-table-column prop="productNumber" label="产品编号" min-width="80"></el-table-column>
@sort-change="handleSort"> <el-table-column v-if="params.roleId != 41" prop="loanCeiling" :label="params.roleId == 42 ? '贷款对象' : '产品对象'" min-width="80">
<el-table-column prop="productName"
label="产品名称"
min-width="110"></el-table-column>
<el-table-column prop="productNumber"
label="产品编号"
min-width="80"></el-table-column>
<el-table-column v-if="params.roleId != 41"
prop="loanCeiling"
:label="params.roleId == 42 ? '贷款对象' : '产品对象'"
min-width="80">
<template #default="{ row }"> <template #default="{ row }">
{{ row.productType ? '企业' : '个人' }} {{ row.productType ? '企业' : '个人' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="guarantyStyle" <el-table-column prop="guarantyStyle" label="担保方式" min-width="80"></el-table-column>
label="担保方式" <el-table-column prop="loanCeiling" label="最高额度/年利率/期限" min-width="110">
min-width="80"></el-table-column>
<el-table-column prop="loanCeiling"
label="最高额度/年利率/期限"
min-width="110">
<template #default="{ row }"> <template #default="{ row }">
{{ row.loanCeiling + '万元/' + row.maximumAnnualInterestRate + '%/' + row.maximumTermOfLoan + '个月' }} {{ row.loanCeiling + '万元/' + row.maximumAnnualInterestRate + '%/' + row.maximumTermOfLoan + '个月' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="operationTime" <el-table-column prop="operationTime" label="创建日期" sortable="custom" min-width="80"></el-table-column>
label="创建日期" <el-table-column prop="status" label="产品进度" min-width="80">
sortable="custom"
min-width="80"></el-table-column>
<el-table-column prop="status"
label="产品进度"
min-width="80">
<template #default="{ row }"> <template #default="{ row }">
{{ getStatus(row.status) }} {{ getStatus(row.status) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="id" <el-table-column prop="id" label="操作" min-width="110">
label="操作"
min-width="110">
<template #default="{ row }"> <template #default="{ row }">
<el-button v-if="row.showDetailsOrNot" <el-button v-if="row.showDetailsOrNot" type="primary" link @click="toDetail(`/product/bank/detail`, row)" size="small">产品详情</el-button>
type="text" <el-button v-if="row.showElementsOrNot" type="primary" link size="small" @click="toDetail(`/product/bank/add`, row)">配置要素</el-button>
@click="toDetail(`/product/bank/detail`, row)" <el-button v-if="row.showRiskControlOrNot" type="primary" link size="small" @click="toDetail(`/product/bank/config`, row)">配置风控</el-button>
size="small">产品详情</el-button> <el-popconfirm v-if="row.showDeleteOrNot" title="您确定删除吗?" @confirm.stop="handleDelete(row.id)">
<el-button v-if="row.showElementsOrNot"
type="text"
size="small"
@click="toDetail(`/product/bank/add`, row)">配置要素</el-button>
<el-button v-if="row.showRiskControlOrNot"
type="text"
size="small"
@click="toDetail(`/product/bank/config`, row)">配置风控</el-button>
<el-popconfirm v-if="row.showDeleteOrNot"
title="您确定删除吗?"
@confirm.stop="handleDelete(row)">
<template #reference> <template #reference>
<el-button type="text" <el-button type="primary" link size="small" @click.stop="stop">删除</el-button>
size="small"
@click.stop="stop">删除</el-button>
</template> </template>
</el-popconfirm> </el-popconfirm>
<el-button v-if="row.showApprovalOrNot" <el-button v-if="row.showApprovalOrNot" type="primary" link size="small" @click="toDetail(`/product/bank/approve`, row)">审批</el-button>
type="text" </template></el-table-column
size="small" >
@click="toDetail(`/product/bank/approve`, row)">审批</el-button>
</template></el-table-column>
</el-table> </el-table>
<el-pagination v-model:currentPage="currentPage" <el-pagination
v-model:pageSize="pageSize" v-model:currentPage="currentPage"
:total="total" v-model:pageSize="pageSize"
:page-sizes="pageSizes" :total="total"
:layout="pageLayout" :page-sizes="pageSizes"
@size-change="getList()" :layout="pageLayout"
@current-change="getList()" @size-change="getList()"
small @current-change="getList()"
background small
class="px-3 py-2 justify-end"></el-pagination> background
class="px-3 py-2 justify-end"
></el-pagination>
</div> </div>
</template> </template>
@ -202,8 +143,10 @@ const initList = async () => {
getList(); getList();
}; };
onMounted(() => { onMounted(() => {
getGuarantee(); if (!Cookies.get('sand-submit')) {
getList(); getGuarantee();
getList();
}
}); });
watch([params, () => route.query], initList); watch([params, () => route.query], initList);

@ -1,44 +1,26 @@
<template> <template>
<div> <div>
<el-tabs v-model="curTab"> <el-tabs v-model="curTab">
<el-tab-pane :label="id ? '产品要素' : '新增产品'" <el-tab-pane :label="id ? '产品要素' : '新增产品'" name="tab1">
name="tab1"> <el-form label-width="100px" label-suffix="" class="max-w-[calc(100vw-540px)] lg:max-w-[calc(100vw-423px)] overflow-auto form" status-icon>
<el-form label-width="100px" <el-form-item label="基金名称" prop="fundName">
label-suffix=":" <el-input placeholder="取个有吸引力的产品名,限20字。" maxlength="20" v-model="form.fundName"></el-input>
class="max-w-[calc(100vw-540px)] overflow-auto form"
status-icon>
<el-form-item label="基金名称"
prop="fundName">
<el-input placeholder="取个有吸引力的产品名,限20字。"
maxlength="20"
v-model="form.fundName"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="基金类型" <el-form-item label="基金类型" prop="fundType">
prop="fundType"> <el-select v-model="form.fundType" placeholder="请选择">
<el-select v-model="form.fundType" <el-option v-for="item in config[1]?.subject?.itemList" :key="item" :label="item.options" :value="item.itemId" />
placeholder="请选择">
<el-option v-for="item in config[1]?.subject?.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="募集规模"> <el-form-item label="募集规模">
<div> <div>
<el-input placeholder="请输入" <el-input placeholder="请输入" v-model="form.fundraisingScale">
v-model="form.fundraisingScale">
<template #append>万元</template> <template #append>万元</template>
</el-input> </el-input>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="运作方式" <el-form-item label="运作方式" prop="modeOfOperation">
prop="modeOfOperation"> <el-select v-model="form.modeOfOperation" placeholder="请选择">
<el-select v-model="form.modeOfOperation" <el-option v-for="item in config[3]?.subject?.itemList" :key="item" :label="item.options" :value="item.itemId" />
placeholder="请选择">
<el-option v-for="item in config[3]?.subject?.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="持股配置"> <el-form-item label="持股配置">
@ -48,37 +30,30 @@
<p class="field-name w-[300px] mr-32">股票</p> <p class="field-name w-[300px] mr-32">股票</p>
<p class="field-name w-[100px] mr-32">比重(%)</p> <p class="field-name w-[100px] mr-32">比重(%)</p>
<div class="field-name"> <div class="field-name">
<el-icon class="cursor-pointer" <el-icon class="cursor-pointer" :size="16" color="#333" @click="addStock">
:size="16"
color="#333"
@click="addStock">
<Plus /> <Plus />
</el-icon> </el-icon>
</div> </div>
</div> </div>
<div v-for="(item, i) in form.shareholdingAllocationsList" <div v-for="(item, i) in form.shareholdingAllocationsList" :key="i" class="flex items-center mb-2">
:key="i"
class="flex items-center mb-2">
<div class="w-[300px] mr-32"> <div class="w-[300px] mr-32">
<el-select-v2 class="w-full" <el-select-v2
v-model="item.stockCode" class="w-full"
filterable v-model="item.stockCode"
remote filterable
:remote-method="val => remoteMethod(val, item)" remote
clearable :remote-method="(val) => remoteMethod(val, item)"
:options="item.stocks" clearable
:loading="loading" :options="item.stocks"
placeholder="请输入A股代码或者名称" /> :loading="loading"
placeholder="请输入A股代码或者名称"
/>
</div> </div>
<div class="w-[100px] mr-32"> <div class="w-[100px] mr-32">
<el-input placeholder="请输入" <el-input placeholder="请输入" v-model="item.proportion"></el-input>
v-model="item.proportion"></el-input>
</div> </div>
<div> <div>
<el-icon class="cursor-pointer" <el-icon class="cursor-pointer" :size="16" color="#333" @click="delStock(i)">
:size="16"
color="#333"
@click="delStock(i)">
<Minus /> <Minus />
</el-icon> </el-icon>
</div> </div>
@ -91,29 +66,17 @@
<!-- 份额时长 --> <!-- 份额时长 -->
<div class="flex items-center mb-3"> <div class="flex items-center mb-3">
客户T时买入T+ 客户T时买入T+
<el-input class="w-[100px] mx-2" <el-input class="w-[100px] mx-2" placeholder="请输入" v-model="form.buyingDuration"></el-input>
placeholder="请输入" <el-select class="w-[100px] mr-2" v-model="form.buyingUnit" placeholder="请选择">
v-model="form.buyingDuration"></el-input> <el-option v-for="item in config[5]?.recordChildren[0]?.recordChildren[1]?.subject?.itemList" :key="item" :value="item.options" />
<el-select class="w-[100px] mr-2"
v-model="form.buyingUnit"
placeholder="请选择">
<el-option v-for="item in config[5]?.recordChildren[0]?.recordChildren[1]?.subject?.itemList"
:key="item"
:value="item.options" />
</el-select> </el-select>
确认申购份额期间资金进入冻结账户 确认申购份额期间资金进入冻结账户
</div> </div>
<div class="flex items-center"> <div class="flex items-center">
客户T时卖出T+ 客户T时卖出T+
<el-input class="w-[100px] mx-2" <el-input class="w-[90px] mx-2" placeholder="请输入" v-model="form.sellingTime"></el-input>
placeholder="请输入" <el-select class="w-[90px] mr-2" v-model="form.soldUnit" placeholder="请选择">
v-model="form.sellingTime"></el-input> <el-option v-for="item in config[5]?.recordChildren[0]?.recordChildren[1]?.subject?.itemList" :key="item" :value="item.options" />
<el-select class="w-[100px] mr-2"
v-model="form.soldUnit"
placeholder="请选择">
<el-option v-for="item in config[5]?.recordChildren[0]?.recordChildren[1]?.subject?.itemList"
:key="item"
:value="item.options" />
</el-select> </el-select>
确认赎回金额期间资金进入冻结账户 确认赎回金额期间资金进入冻结账户
</div> </div>
@ -122,60 +85,35 @@
<p class="mt-10 mb-2 text-xs text-[#ef3838]">买入费率单笔费率应小于5.00%5000</p> <p class="mt-10 mb-2 text-xs text-[#ef3838]">买入费率单笔费率应小于5.00%5000</p>
<div class="flex"> <div class="flex">
<p class="field-name w-[400px] mr-32">金额</p> <p class="field-name w-[400px] mr-32">金额</p>
<p class="field-name w-[100px] mr-32">费率</p> <p class="field-name w-[90px] mr-32 xl:mr-10">费率</p>
<div class="field-name"> <div class="field-name">
<el-icon class="cursor-pointer" <el-icon class="cursor-pointer" :size="16" color="#333" @click="addRatio(0)">
:size="16"
color="#333"
@click="addRatio(0)">
<Plus /> <Plus />
</el-icon> </el-icon>
</div> </div>
</div> </div>
<div v-for="(item, i) in form.buySellRatioList0" <div v-for="(item, i) in form.buySellRatioList0" :key="i" class="flex items-center mb-2">
:key="i" <div class="w-[390px] mr-10">
class="flex items-center mb-2"> <el-input v-if="i" class="w-[90px] mr-2" placeholder="请输入" disabled v-model="form.buySellRatioList0[i - 1].input2"></el-input>
<div class="w-[400px] mr-10"> <el-input v-else class="w-[90px] mr-2" placeholder="请输入" disabled v-model="item.input1"></el-input>
<el-input v-if="i"
class="w-[100px] mr-2"
placeholder="请输入"
disabled
v-model="form.buySellRatioList0[i - 1].input2"></el-input>
<el-input v-else
class="w-[100px] mr-2"
placeholder="请输入"
disabled
v-model="item.input1"></el-input>
{{ i ? '万' : '&emsp;' }} {{ i ? '万' : '&emsp;' }}
<span class="mx-2"> <span class="mx-2"> &lt;= 买入金额</span>
&lt;= 买入金额</span>
<template v-if="i !== form.buySellRatioList0.length - 1"> <template v-if="i !== form.buySellRatioList0.length - 1">
&lt; &lt;
<el-input class="w-[100px] mx-2" <el-input class="w-[90px] mx-2" placeholder="请输入" v-model="item.input2"></el-input>
placeholder="请输入"
v-model="item.input2"></el-input>
</template> </template>
</div> </div>
<div class="mr-32"> <div class="mr-32 xl:mr-10">
<el-input class="w-[100px] mr-2" <el-input class="w-[90px] mr-2" placeholder="请输入" v-model="item.rate"></el-input>
placeholder="请输入" <el-select class="w-[90px]" v-model="item.rateUnit" placeholder="请选择">
v-model="item.rate"></el-input> <el-option v-for="item in units" :key="item" :value="item" />
<el-select class="w-[90px]"
v-model="item.rateUnit"
placeholder="请选择">
<el-option v-for="item in units"
:key="item"
:value="item" />
</el-select> </el-select>
</div> </div>
<div v-if="i"> <div v-if="i">
<el-icon class="cursor-pointer" <el-icon class="cursor-pointer" :size="16" color="#333" @click="delRatio(0, i)">
:size="16"
color="#333"
@click="delRatio(0, i)">
<Minus /> <Minus />
</el-icon> </el-icon>
</div> </div>
@ -191,21 +129,15 @@
<p class="mt-10 mb-2 text-xs text-[#ef3838]">运作费率单笔费率应小于5.00%</p> <p class="mt-10 mb-2 text-xs text-[#ef3838]">运作费率单笔费率应小于5.00%</p>
<div class="flex"> <div class="flex">
<span class="w-[140px]">管理费</span> <span class="w-[140px]">管理费</span>
<el-input class="w-[100px] mr-2" <el-input class="w-[100px] mr-2" placeholder="请输入" v-model="form.operationManagementRate"></el-input>%
placeholder="请输入"
v-model="form.operationManagementRate"></el-input>%
</div> </div>
<div class="flex my-2"> <div class="flex my-2">
<span class="w-[140px]">托管费</span> <span class="w-[140px]">托管费</span>
<el-input class="w-[100px] mr-2" <el-input class="w-[100px] mr-2" placeholder="请输入" v-model="form.operatingEscrowRate"></el-input>%
placeholder="请输入"
v-model="form.operatingEscrowRate"></el-input>%
</div> </div>
<div class="flex"> <div class="flex">
<span class="w-[140px]">销售服务费</span> <span class="w-[140px]">销售服务费</span>
<el-input class="w-[100px] mr-2" <el-input class="w-[100px] mr-2" placeholder="请输入" v-model="form.operatingSalesServiceRates"></el-input>%
placeholder="请输入"
v-model="form.operatingSalesServiceRates"></el-input>%
</div> </div>
<div class="mt-5 text-xs text-[#7a7a7a]"> <div class="mt-5 text-xs text-[#7a7a7a]">
<p>运作费计算</p> <p>运作费计算</p>
@ -217,78 +149,43 @@
<!-- 赎回费率 --> <!-- 赎回费率 -->
<p class="mt-10 mb-2 text-xs text-[#ef3838]">赎回费率单笔费率应小于5.00%5000</p> <p class="mt-10 mb-2 text-xs text-[#ef3838]">赎回费率单笔费率应小于5.00%5000</p>
<div class="flex"> <div class="flex">
<p class="field-name w-[600px] mr-32">持有时长</p> <p class="field-name w-[600px] mr-32 xl:w-[540px] xl:mr-20">持有时长</p>
<p class="field-name w-[100px] mr-32">费率</p> <p class="field-name w-[90px] mr-20 xl:mr-10">费率</p>
<div class="field-name"> <div class="field-name">
<el-icon class="cursor-pointer" <el-icon class="cursor-pointer" :size="16" color="#333" @click="addRatio(1)">
:size="16"
color="#333"
@click="addRatio(1)">
<Plus /> <Plus />
</el-icon> </el-icon>
</div> </div>
</div> </div>
<div v-for="(item, i) in form.buySellRatioList1" <div v-for="(item, i) in form.buySellRatioList1" :key="i" class="flex items-center mb-2">
:key="i" <div class="w-[590px] mr-10 xl:w-[538px] xl:mr-0">
class="flex items-center mb-2"> <el-input v-if="i" class="w-[90px] mr-2" placeholder="请输入" disabled v-model="form.buySellRatioList1[i - 1].input2"></el-input>
<div class="w-[600px] mr-10"> <el-input v-else class="w-[90px] mr-[98px]" placeholder="请输入" disabled v-model="item.input1"></el-input>
<el-input v-if="i"
class="w-[100px] mr-2"
placeholder="请输入"
disabled
v-model="form.buySellRatioList1[i - 1].input2"></el-input>
<el-input v-else
class="w-[100px] mr-[108px]"
placeholder="请输入"
disabled
v-model="item.input1"></el-input>
<el-select v-if="i" <el-select v-if="i" class="w-[90px]" v-model="form.buySellRatioList1[i - 1].soldUnit2" placeholder="请选择" disabled>
class="w-[100px]" <el-option v-for="item in times" :key="item" :value="item" />
v-model="form.buySellRatioList1[i - 1].soldUnit2"
placeholder="请选择"
disabled>
<el-option v-for="item in times"
:key="item"
:value="item" />
</el-select> </el-select>
<span class="mx-2"> <span class="mx-2"> &lt;= 持有时长</span>
&lt;= 持有时长</span>
<template v-if="i !== form.buySellRatioList1.length - 1"> <template v-if="i !== form.buySellRatioList1.length - 1">
&lt; &lt;
<el-input class="w-[100px] mx-2" <el-input class="w-[90px] mx-2" placeholder="请输入" v-model="item.input2"></el-input>
placeholder="请输入"
v-model="item.input2"></el-input>
<el-select class="w-[100px]" <el-select class="w-[90px]" v-model="item.soldUnit2" placeholder="请选择">
v-model="item.soldUnit2" <el-option v-for="item in times" :key="item" :value="item" />
placeholder="请选择">
<el-option v-for="item in times"
:key="item"
:value="item" />
</el-select> </el-select>
</template> </template>
</div> </div>
<div class="mr-32"> <div class="min-w-[190px] mr-20 xl:mr-6">
<el-input class="w-[100px] mr-2" <el-input class="w-[90px] mr-2" placeholder="请输入" v-model="item.rate"></el-input>
placeholder="请输入" <el-select class="w-[90px]" v-model="item.rateUnit" placeholder="请选择">
v-model="item.rate"></el-input> <el-option v-for="item in units" :key="item" :value="item" />
<el-select class="w-[90px]"
v-model="item.rateUnit"
placeholder="请选择">
<el-option v-for="item in units"
:key="item"
:value="item" />
</el-select> </el-select>
</div> </div>
<div v-if="i"> <div v-if="i">
<el-icon class="cursor-pointer" <el-icon class="cursor-pointer" :size="16" color="#333" @click="delRatio(1, i)">
:size="16"
color="#333"
@click="delRatio(1, i)">
<Minus /> <Minus />
</el-icon> </el-icon>
</div> </div>
@ -301,8 +198,7 @@
</div> </div>
</el-form-item> </el-form-item>
<div class="flex justify-end"> <div class="flex justify-end">
<div class="submit" <div class="submit" @click="submit">完成</div>
@click="submit">完成</div>
</div> </div>
</el-form> </el-form>
</el-tab-pane> </el-tab-pane>
@ -311,7 +207,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, computed, watch, onMounted, defineEmits } from 'vue'; import { ref, reactive, computed, onMounted, defineEmits } from 'vue';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { Plus, Minus } from '@element-plus/icons-vue'; import { Plus, Minus } from '@element-plus/icons-vue';
import { getAListOfAShares, saveFund } from '@/api/fund'; import { getAListOfAShares, saveFund } from '@/api/fund';
@ -437,7 +333,7 @@ const remoteMethod = (query: string, item: Record<string, any>) => {
// //
const addRatio = (type: number) => { const addRatio = (type: number) => {
if (form['buySellRatioList' + type].length === 5) { if (form[`buySellRatioList${type}`].length === 5) {
ElMessage.error('规则最多只能添加5条!'); ElMessage.error('规则最多只能添加5条!');
} else { } else {
const temp = { const temp = {
@ -451,12 +347,12 @@ const addRatio = (type: number) => {
temp.soldUnit1 = ''; temp.soldUnit1 = '';
temp.soldUnit2 = ''; temp.soldUnit2 = '';
} }
form['buySellRatioList' + type].push(temp); form[`buySellRatioList${type}`].push(temp);
} }
}; };
// //
const delRatio = (type: number, i: number) => { const delRatio = (type: number, i: number) => {
form['buySellRatioList' + type].length > 1 && form['buySellRatioList' + type].splice(i, 1); form[`buySellRatioList${type}`].length > 1 && form[`buySellRatioList${type}`].splice(i, 1);
}; };
const getId = (str: string): string | number => { const getId = (str: string): string | number => {
@ -467,10 +363,10 @@ const getId = (str: string): string | number => {
const addRecord = async (data: Record<string, any>) => { const addRecord = async (data: Record<string, any>) => {
const preIds = `1,${levelId},1161`; // 1id const preIds = `1,${levelId},1161`; // 1id
const rule = [ const rule = [
handleId(1162, 308, data.fundName, preIds + ',1162', 3), handleId(1162, 308, data.fundName, `${preIds},1162`, 3),
handleId(1163, 309, 764, preIds + ',1163', 1), handleId(1163, 309, 764, `${preIds},1163`, 1),
handleId(1164, 310, data.fundraisingScale, preIds + ',1164', 3), handleId(1164, 310, data.fundraisingScale, `${preIds},1164`, 3),
handleId(1165, 311, 765, preIds + ',1165', 1), handleId(1165, 311, 765, `${preIds},1165`, 1),
]; ];
const stockId = 1167; const stockId = 1167;
@ -479,10 +375,10 @@ const addRecord = async (data: Record<string, any>) => {
rule.push(handleId(1178, 313, e.proportion, `${preIds},1166,${stockId + i},1178`, 3)); rule.push(handleId(1178, 313, e.proportion, `${preIds},1166,${stockId + i},1178`, 3));
}); });
rule.push( rule.push(
handleId(1181, 314, data.buyingDuration, preIds + ',1179,1180,1181', 3), handleId(1181, 314, data.buyingDuration, `${preIds},1179,1180,1181`, 3),
handleId(1182, 315, getId(data.buyingUnit), preIds + ',1179,1180,1182', 1), handleId(1182, 315, getId(data.buyingUnit), `${preIds},1179,1180,1182`, 1),
handleId(1184, 314, data.sellingTime, preIds + ',1179,1183,1184', 3), handleId(1184, 314, data.sellingTime, `${preIds},1179,1183,1184`, 3),
handleId(1185, 315, getId(data.soldUnit), preIds + ',1179,1183,1185', 1), handleId(1185, 315, getId(data.soldUnit), `${preIds},1179,1183,1185`, 1),
); );
// //
@ -500,9 +396,9 @@ const addRecord = async (data: Record<string, any>) => {
}); });
rule.push( rule.push(
handleId(1196, 319, data.operationManagementRate, preIds + ',1179,1195,1196', 3), handleId(1196, 319, data.operationManagementRate, `${preIds},1179,1195,1196`, 3),
handleId(1197, 320, data.operatingEscrowRate, preIds + ',1179,1195,1197', 3), handleId(1197, 320, data.operatingEscrowRate, `${preIds},1179,1195,1197`, 3),
handleId(1198, 321, data.operatingSalesServiceRates, preIds + ',1179,1195,1198', 3), handleId(1198, 321, data.operatingSalesServiceRates, `${preIds},1179,1195,1198`, 3),
); );
await addOperation({ await addOperation({
@ -545,7 +441,7 @@ const submit = async () => {
// //
param.buySellRatioList0.forEach((e, i) => { param.buySellRatioList0.forEach((e, i) => {
e.amountOrDuration = (i ? param.buySellRatioList0[i - 1].input2 : e.input1) + `${i !== param.buySellRatioList0.length - 1 ? '~' + e.input2 : ''}`; e.amountOrDuration = `${i ? param.buySellRatioList0[i - 1].input2 : e.input1}${i !== param.buySellRatioList0.length - 1 ? `~${e.input2}` : ''}`;
}); });
param.buySellRatioList1.forEach((e, i) => { param.buySellRatioList1.forEach((e, i) => {
e.amountOrDuration = i ? param.buySellRatioList1[i - 1].input2 + param.buySellRatioList1[i - 1].soldUnit2 : e.input1; e.amountOrDuration = i ? param.buySellRatioList1[i - 1].input2 + param.buySellRatioList1[i - 1].soldUnit2 : e.input1;
@ -557,7 +453,7 @@ const submit = async () => {
delete param.buySellRatioList0; delete param.buySellRatioList0;
delete param.buySellRatioList1; delete param.buySellRatioList1;
const res = await saveFund(param); const res = await saveFund(param);
router.push(`/product/fund/detail?id=` + res.message); router.push(`/product/fund/detail?id=${res.message}`);
addRecord(recordParam); addRecord(recordParam);
ElMessage.success('提交成功!'); ElMessage.success('提交成功!');
emit('getList'); emit('getList');
@ -565,7 +461,9 @@ const submit = async () => {
} }
}; };
onMounted(() => { onMounted(() => {
getConfig(); if (!Cookies.get('sand-submit')) {
getConfig();
}
}); });
</script> </script>

@ -1,32 +1,23 @@
<template> <template>
<div class="block card-list flex py-0"> <div class="block card-list flex py-0">
<div class="left"> <div class="left">
<div class="flex justify-center items-center py-2 mb-3 text-sm text-[#006BFF] bg-[rgba(0,107,255,0.1)] border border-solid border-[#006BFF] rounded-[10px] cursor-pointer" <div
@click="toAdd"> class="flex justify-center items-center py-2 mb-3 text-sm text-[#006BFF] bg-[rgba(0,107,255,0.1)] border border-solid border-[#006BFF] rounded-[10px] cursor-pointer"
<el-icon class="mr-1" @click="toAdd"
:size="16" >
color="#006BFF"> <el-icon class="mr-1" :size="16" color="#006BFF">
<Plus /> <Plus />
</el-icon> </el-icon>
新增产品 新增产品
</div> </div>
<div class="flex justify-end mb-4"> <div class="flex justify-end mb-4">
<img src="@/assets/images/fold.png" <img src="@/assets/images/fold.png" alt="" class="cursor-pointer" @click="toList" />
alt=""
class="cursor-pointer"
@click="toList" />
</div> </div>
<ul class="products"> <ul class="products">
<li v-for="(item, i) in list" <li v-for="(item, i) in list" :key="i" :class="{ active: item.id === id }" @click="switchProduct(item.id)">
:key="i" <el-popconfirm title="您确定删除吗?" @confirm="handleDelete(item.id)">
:class="{ active: item.id === id }"
@click="switchProduct(item.id)">
<el-popconfirm title="您确定删除吗?"
@confirm="handleDelete(item.id)">
<template #reference> <template #reference>
<img src="@/assets/images/trash.png" <img src="@/assets/images/trash.png" alt="" class="del" />
alt=""
class="del" />
</template> </template>
</el-popconfirm> </el-popconfirm>
@ -39,8 +30,7 @@
</div> </div>
<div class="right"> <div class="right">
<detail v-if="action === 'detail'"></detail> <detail v-if="action === 'detail'"></detail>
<add v-else-if="action === 'add'" <add v-else-if="action === 'add'" @getList="getList"></add>
@getList="getList"></add>
</div> </div>
</div> </div>
</template> </template>
@ -51,10 +41,10 @@ import { ElMessage } from 'element-plus';
import { Plus } from '@element-plus/icons-vue'; import { Plus } from '@element-plus/icons-vue';
import { fundProductList, batchDeletion } from '@/api/fund'; import { fundProductList, batchDeletion } from '@/api/fund';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import Detail from './Detail.vue';
import Add from './Add.vue';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { getIds } from '@/utils/common'; import { getIds } from '@/utils/common';
import Detail from './Detail.vue';
import Add from './Add.vue';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
@ -65,19 +55,21 @@ const loading = ref<boolean>(false);
const id = computed(() => +route.query.id); const id = computed(() => +route.query.id);
// //
const getList = async (refresh?: number) => { const getList = async (refresh?: number) => {
loading.value = true; if (!Cookies.get('sand-submit')) {
try { loading.value = true;
const { data } = await fundProductList({ try {
...getIds(), const { data } = await fundProductList({
pageNum: 1, ...getIds(),
pageSize: 1000, pageNum: 1,
fundName: route.query.name ?? '', pageSize: 1000,
createDateSort: route.query.createDateSort ?? '', fundName: route.query.name ?? '',
}); createDateSort: route.query.createDateSort ?? '',
list.value = data.data.records; });
refresh && list.value.length && switchProduct(list.value[0].id); list.value = data.data.records;
} finally { refresh && list.value.length && switchProduct(list.value[0].id);
loading.value = false; } finally {
loading.value = false;
}
} }
}; };
onMounted(() => { onMounted(() => {
@ -95,7 +87,7 @@ watch(
); );
// //
const switchProduct = (fundId: number) => { const switchProduct = (fundId: number) => {
router.push(`/product/fund/detail?id=` + fundId); router.push(`/product/fund/detail?id=${fundId}`);
}; };
// //
const toAdd = () => { const toAdd = () => {

@ -1,8 +1,7 @@
<template> <template>
<div> <div>
<el-tabs v-model="curTab"> <el-tabs v-model="curTab">
<el-tab-pane label="产品详情" <el-tab-pane label="产品详情" name="tab1">
name="tab1">
<info /> <info />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>

@ -10,9 +10,7 @@
<p class="w-[130px] mr-32">股票</p> <p class="w-[130px] mr-32">股票</p>
<p class="">比重(%)</p> <p class="">比重(%)</p>
</div> </div>
<div v-for="(item, i) in info.shareholdingAllocationsList" <div v-for="(item, i) in info.shareholdingAllocationsList" :key="item" class="flex">
:key="item"
class="flex">
<p class="w-[130px] mr-32">{{ item.stockName }}({{ item.stockCode }})</p> <p class="w-[130px] mr-32">{{ item.stockName }}({{ item.stockCode }})</p>
<p class="">{{ item.proportion }}</p> <p class="">{{ item.proportion }}</p>
</div> </div>
@ -27,12 +25,9 @@
<p class="w-[130px] mr-32">金额</p> <p class="w-[130px] mr-32">金额</p>
<p class="">费率</p> <p class="">费率</p>
</div> </div>
<div v-for="(item, i) in info.purchaseRateList" <div v-for="(item, i) in info.purchaseRateList" :key="item" class="flex">
:key="item"
class="flex">
<p class="w-[130px] mr-32">{{ item.amountOrDuration }}</p> <p class="w-[130px] mr-32">{{ item.amountOrDuration }}</p>
<p class="">{{ item.rate }}{{ item.rateUnit <p class="">{{ item.rate }}{{ item.rateUnit }}</p>
}}</p>
</div> </div>
</div> </div>
@ -46,9 +41,7 @@
<p class="w-[130px] mr-32">持有时长</p> <p class="w-[130px] mr-32">持有时长</p>
<p class="">费率</p> <p class="">费率</p>
</div> </div>
<div v-for="(item, i) in info.sellingRateList" <div v-for="(item, i) in info.sellingRateList" :key="item" class="flex">
:key="item"
class="flex">
<p class="w-[130px] mr-32">{{ item.amountOrDuration }}</p> <p class="w-[130px] mr-32">{{ item.amountOrDuration }}</p>
<p class="">{{ item.rate }}{{ item.rateUnit }}</p> <p class="">{{ item.rate }}{{ item.rateUnit }}</p>
</div> </div>
@ -57,18 +50,18 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'; import { ref, computed, watch } from 'vue';
import { findById } from '@/api/fund'; import { findById } from '@/api/fund';
import { useRouter, useRoute } from 'vue-router'; import { useRoute } from 'vue-router';
import Cookies from 'js-cookie';
const router = useRouter();
const route = useRoute(); const route = useRoute();
const id = computed(() => +route.query.id); const id = computed(() => +route.query.id);
const info = ref<Record<string, any>>({}); const info = ref<Record<string, any>>({});
// //
const getDetail = async () => { const getDetail = async () => {
if (id.value) { if (id.value && !Cookies.get('sand-submit')) {
try { try {
const { data } = await findById(id.value); const { data } = await findById(id.value);
info.value = data; info.value = data;

@ -1,76 +1,47 @@
<template> <template>
<div class="block"> <div class="block">
<div class="flex justify-between items-center mb-5"> <div class="flex justify-between items-center mb-5">
<search v-model="params.fundName" <search v-model="params.fundName" @change="initList"></search>
@change="initList"></search>
<div class="filter"> <div class="filter">
<div class="add-btn" <div class="add-btn" @click="toAdd">
@click="toAdd"> <img src="@/assets/images/plus.png" alt="" class="icon" />
<img src="@/assets/images/plus.png"
alt=""
class="icon" />
新增产品 新增产品
</div> </div>
<img src="@/assets/images/9.png" <img src="@/assets/images/9.png" alt="" class="ml-4 cursor-pointer" @click="toCardList" />
alt=""
class="ml-4 cursor-pointer"
@click="toCardList" />
</div> </div>
</div> </div>
<el-table ref="table" <el-table ref="table" v-loading="loading" :data="list" @sort-change="handleSort">
v-loading="loading" <el-table-column prop="fundName" label="基金名称" min-width="150"></el-table-column>
:data="list" <el-table-column prop="fundCode" label="基金代码" min-width="100"></el-table-column>
@sort-change="handleSort"> <el-table-column prop="fundType" label="基金类型" min-width="100"></el-table-column>
<el-table-column prop="fundName" <el-table-column prop="fundraisingScale" label="募集规模" min-width="100"></el-table-column>
label="基金名称" <el-table-column prop="modeOfOperation" label="运作方式" min-width="100"></el-table-column>
min-width="150"></el-table-column> <el-table-column prop="buying" label="买入费率" min-width="120"></el-table-column>
<el-table-column prop="fundCode" <el-table-column prop="sale" label="赎回费率" min-width="120"></el-table-column>
label="基金代码" <el-table-column prop="operationTime" label="创建日期" width="180" sortable="custom"></el-table-column>
min-width="100"></el-table-column> <el-table-column label="操作" width="140">
<el-table-column prop="fundType"
label="基金类型"
min-width="100"></el-table-column>
<el-table-column prop="fundraisingScale"
label="募集规模"
min-width="100"></el-table-column>
<el-table-column prop="modeOfOperation"
label="运作方式"
min-width="100"></el-table-column>
<el-table-column prop="buying"
label="买入费率"
min-width="120"></el-table-column>
<el-table-column prop="sale"
label="赎回费率"
min-width="120"></el-table-column>
<el-table-column prop="operationTime"
label="创建日期"
width="180"
sortable="custom"></el-table-column>
<el-table-column label="操作"
width="140">
<template #default="{ row }"> <template #default="{ row }">
<el-popconfirm title="您确定删除吗?" <el-popconfirm title="您确定删除吗?" @confirm.stop="handleDelete(row.id)">
@confirm.stop="handleDelete(row.id)">
<template #reference> <template #reference>
<el-button type="text" <el-button type="primary" link size="small">删除</el-button>
size="small">删除</el-button>
</template> </template>
</el-popconfirm> </el-popconfirm>
<el-button type="text" <el-button type="primary" link @click="toDetail(`/product/fund/detail`, row.id)" size="small">产品详情</el-button>
@click="toDetail(`/product/fund/detail`, row.id)" </template></el-table-column
size="small">产品详情</el-button> >
</template></el-table-column>
</el-table> </el-table>
<el-pagination v-model:currentPage="currentPage" <el-pagination
v-model:pageSize="pageSize" v-model:currentPage="currentPage"
:total="total" v-model:pageSize="pageSize"
:page-sizes="pageSizes" :total="total"
:layout="pageLayout" :page-sizes="pageSizes"
@size-change="getList()" :layout="pageLayout"
@current-change="getList()" @size-change="getList()"
small @current-change="getList()"
background small
class="px-3 py-2 justify-end"></el-pagination> background
class="px-3 py-2 justify-end"
></el-pagination>
</div> </div>
</template> </template>
@ -101,13 +72,15 @@ const list = ref<Record<string, any>[]>([]);
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
// //
const getList = async () => { const getList = async () => {
loading.value = true; if (!Cookies.get('sand-submit')) {
try { loading.value = true;
const { data } = await fundProductList({ pageNum: currentPage.value, pageSize: pageSize.value, ...toParams(params) }); try {
list.value = data.data.records; const { data } = await fundProductList({ pageNum: currentPage.value, pageSize: pageSize.value, ...toParams(params) });
total.value = data.data.total; list.value = data.data.records;
} finally { total.value = data.data.total;
loading.value = false; } finally {
loading.value = false;
}
} }
}; };
// //

@ -1,37 +1,22 @@
<template> <template>
<div> <div>
<el-tabs v-model="curTab"> <el-tabs v-model="curTab">
<el-tab-pane :label="id ? '产品要素' : '新增产品'" <el-tab-pane :label="id ? '产品要素' : '新增产品'" name="tab1">
name="tab1"> <el-form label-width="100px" label-suffix="" class="max-w-[calc(100vw-540px)] lg:max-w-[calc(100vw-423px)] overflow-auto form" status-icon>
<el-form label-width="100px" <el-form-item label="保险名称" prop="insuranceName">
label-suffix=":" <el-input placeholder="取个有吸引力的产品名,限20字。" maxlength="20" v-model="form.insuranceName"></el-input>
class="max-w-[calc(100vw-540px)] overflow-auto form"
status-icon>
<el-form-item label="保险名称"
prop="insuranceName">
<el-input placeholder="取个有吸引力的产品名,限20字。"
maxlength="20"
v-model="form.insuranceName"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="险种分类" <el-form-item label="险种分类" prop="insuranceType">
prop="insuranceType"> <el-select v-model="form.insuranceType" placeholder="请选择">
<el-select v-model="form.insuranceType" <el-option v-for="item in config[0]?.recordChildren[1]?.subject?.itemList" :key="item" :label="item.options" :value="item.itemId" />
placeholder="请选择">
<el-option v-for="item in config[0]?.recordChildren[1]?.subject?.itemList"
:key="item"
:label="item.options"
:value="item.itemId" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item v-if="form.insuranceType === 310" <el-form-item v-if="form.insuranceType === 310" label="承保年龄">
label="承保年龄">
<div class="flex items-center"> <div class="flex items-center">
<div class="num-inputs"> <div class="num-inputs">
<el-input placeholder="最小年龄" <el-input placeholder="最小年龄" v-model.number="form.minimumAge"></el-input>
v-model.number="form.minimumAge"></el-input>
<span class="split">-</span> <span class="split">-</span>
<el-input placeholder="最大年龄" <el-input placeholder="最大年龄" v-model.number="form.maximumAge"></el-input>
v-model.number="form.maximumAge"></el-input>
<span class="unit">周岁</span> <span class="unit">周岁</span>
</div> </div>
</div> </div>
@ -42,68 +27,50 @@
<p class="field-name w-[130px] mr-32">保险责任</p> <p class="field-name w-[130px] mr-32">保险责任</p>
<p class="field-name">保额</p> <p class="field-name">保额</p>
</div> </div>
<div v-for="(item, i) in config[form.insuranceType === 310 ? 0 : 1]?.recordChildren[2]?.recordChildren" <div v-for="(item, i) in config[form.insuranceType === 310 ? 0 : 1]?.recordChildren[2]?.recordChildren" :key="i" class="flex items-center mb-2">
:key="i"
class="flex items-center mb-2">
<div class="w-[130px] mr-32"> <div class="w-[130px] mr-32">
<el-checkbox :key="item.id" <el-checkbox :key="item.id" v-model="item.check" :label="item.name" />
v-model="item.check"
:label="item.name" />
</div> </div>
<div v-if="item.check"> <div v-if="item.check">
<el-input placeholder="请输入" <el-input placeholder="请输入" v-model="item.sumInsured">
v-model="item.sumInsured">
<template #append>{{ item.id === 764 || item.id === 765 ? '元' : '万' }}</template> <template #append>{{ item.id === 764 || item.id === 765 ? '元' : '万' }}</template>
</el-input> </el-input>
</div> </div>
</div> </div>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="保费金额" <el-form-item label="保费金额" prop="minimumLoan">
prop="minimumLoan">
<div> <div>
<el-input placeholder="请输入" <el-input placeholder="请输入" v-model="form.premiumAmount">
v-model="form.premiumAmount">
<template #append></template> <template #append></template>
</el-input> </el-input>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="缴纳形式"> <el-form-item label="缴纳形式">
<el-radio :label="312" <el-radio :label="312" v-model="form.formOfPayment">趸交</el-radio>
v-model="form.formOfPayment">趸交</el-radio>
</el-form-item> </el-form-item>
<el-form-item label="保险期限"> <el-form-item label="保险期限">
<div class="flex"> <div class="flex">
<el-input class="mr-2" <el-input class="mr-2" placeholder="请输入" v-model="form.insuranceDeadline"></el-input>
placeholder="请输入" <el-select v-model="form.insuranceDeadlineUnit" placeholder="请选择" clearable>
v-model="form.insuranceDeadline"></el-input> <el-option v-for="item in units" :key="item" :label="item" :value="item" />
<el-select v-model="form.insuranceDeadlineUnit"
placeholder="请选择"
clearable>
<el-option v-for="item in units"
:key="item"
:label="item"
:value="item" />
</el-select> </el-select>
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="申请材料"> <el-form-item label="申请材料">
<el-checkbox-group v-model="form.applicationMaterial"> <el-checkbox-group v-model="form.applicationMaterial">
<el-checkbox v-for="(item, i) in config[form.insuranceType === 310 ? 0 : 1]?.recordChildren[6]?.subject?.itemList" <el-checkbox v-for="(item, i) in config[form.insuranceType === 310 ? 0 : 1]?.recordChildren[6]?.subject?.itemList" :key="i" :label="item.itemId">{{
:key="i" item.options
:label="item.itemId">{{ item.options }}</el-checkbox> }}</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<el-form-item label="责任免除"> <el-form-item label="责任免除">
<el-checkbox-group v-model="form.exemptionFromLiability"> <el-checkbox-group v-model="form.exemptionFromLiability">
<el-checkbox v-for="(item, i) in config[0]?.recordChildren[7]?.subject?.itemList" <el-checkbox v-for="(item, i) in config[0]?.recordChildren[7]?.subject?.itemList" :key="i" :label="item.itemId">{{ item.options }}</el-checkbox>
:key="i"
:label="item.itemId">{{ item.options }}</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</el-form-item> </el-form-item>
<div class="flex justify-end"> <div class="flex justify-end">
<div class="submit" <div class="submit" @click="submit">完成</div>
@click="submit">完成</div>
</div> </div>
</el-form> </el-form>
</el-tab-pane> </el-tab-pane>
@ -146,12 +113,14 @@ const form = reactive({
// //
const getConfig = async () => { const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(275); if (!Cookies.get('sand-submit')) {
config.value = process; const { process } = await getProcessInformationBasedOnRoles(275);
config.value = process;
}
}; };
// //
const getDetail = async () => { const getDetail = async () => {
if (id.value) { if (id.value && !Cookies.get('sand-submit')) {
try { try {
const { data } = await insuranceProductDetails(id.value); const { data } = await insuranceProductDetails(id.value);
info.value = data; info.value = data;
@ -172,30 +141,30 @@ watch(
const addRecord = async (data: Record<string, any>) => { const addRecord = async (data: Record<string, any>) => {
const isAcci = data.insuranceType === 310; // const isAcci = data.insuranceType === 310; //
const preIds = `1,${Cookies.get('sand-level')},275,${isAcci ? 276 : 277}`; // 1id const preIds = `1,${Cookies.get('sand-level')},275,${isAcci ? 276 : 277}`; // 1id
const rule: Array<Record<string, any>> = [handleId(278, 118, data.insuranceName, preIds + ',278', 3), handleId(279, 119, data.insuranceType, preIds + ',279', 1)]; const rule: Array<Record<string, any>> = [handleId(278, 118, data.insuranceName, `${preIds},278`, 3), handleId(279, 119, data.insuranceType, `${preIds},279`, 1)];
data.minimumAge && rule.push(handleId(680, 219, data.minimumAge, preIds + ',678,680', 3)); data.minimumAge && rule.push(handleId(680, 219, data.minimumAge, `${preIds},678,680`, 3));
data.maximumAge && rule.push(handleId(679, 218, data.maximumAge, preIds + ',678,679', 3)); data.maximumAge && rule.push(handleId(679, 218, data.maximumAge, `${preIds},678,679`, 3));
// //
config.value[form.insuranceType === 310 ? 0 : 1]?.recordChildren[2]?.recordChildren?.map((e) => { config.value[form.insuranceType === 310 ? 0 : 1]?.recordChildren[2]?.recordChildren?.map((e) => {
rule.push(handleId(isAcci ? 766 : 768, 140, e.check ? 345 : 346, `${preIds},${isAcci ? 280 : 288},${e.id},${isAcci ? 766 : 768}`, 1)); rule.push(handleId(isAcci ? 766 : 768, 140, e.check ? 345 : 346, `${preIds},${isAcci ? 280 : 288},${e.id},${isAcci ? 766 : 768}`, 1));
e.check && e.sumInsured && rule.push(handleId(isAcci ? 767 : 769, 234, e.sumInsured, `${preIds},${isAcci ? 280 : 288},${e.id},${isAcci ? 767 : 769}`, 3)); e.check && e.sumInsured && rule.push(handleId(isAcci ? 767 : 769, 234, e.sumInsured, `${preIds},${isAcci ? 280 : 288},${e.id},${isAcci ? 767 : 769}`, 3));
}); });
data.premiumAmount && rule.push(handleId(296, 134, data.premiumAmount, preIds + ',296', 3)); data.premiumAmount && rule.push(handleId(296, 134, data.premiumAmount, `${preIds},296`, 3));
data.formOfPayment && rule.push(handleId(297, 135, data.formOfPayment, preIds + ',297', 1)); data.formOfPayment && rule.push(handleId(297, 135, data.formOfPayment, `${preIds},297`, 1));
form.insuranceDeadline && rule.push(handleId(770, 136, form.insuranceDeadline, preIds + ',298,770', 3)); form.insuranceDeadline && rule.push(handleId(770, 136, form.insuranceDeadline, `${preIds},298,770`, 3));
form.insuranceDeadlineUnit && form.insuranceDeadlineUnit &&
rule.push( rule.push(
handleId( handleId(
771, 771,
235, 235,
config.value[form.insuranceType === 310 ? 0 : 1]?.recordChildren[5]?.recordChildren[1]?.subject?.itemList?.find((e) => e.options === form.insuranceDeadlineUnit)?.itemId, config.value[form.insuranceType === 310 ? 0 : 1]?.recordChildren[5]?.recordChildren[1]?.subject?.itemList?.find((e) => e.options === form.insuranceDeadlineUnit)?.itemId,
preIds + ',298,771', `${preIds},298,771`,
1, 1,
), ),
); );
data.applicationMaterial && rule.push(handleId(isAcci ? 299 : 300, isAcci ? 137 : 138, data.applicationMaterial, `${preIds},${isAcci ? 299 : 300}`, 1)); data.applicationMaterial && rule.push(handleId(isAcci ? 299 : 300, isAcci ? 137 : 138, data.applicationMaterial, `${preIds},${isAcci ? 299 : 300}`, 1));
data.exemptionFromLiability && rule.push(handleId(301, 139, data.exemptionFromLiability, preIds + ',301', 1)); data.exemptionFromLiability && rule.push(handleId(301, 139, data.exemptionFromLiability, `${preIds},301`, 1));
await addOperation({ await addOperation({
...getIds(), ...getIds(),
@ -234,19 +203,19 @@ const submit = async () => {
if (!param.insuranceCoverageConfigList.length) return ElMessage.error('请至少输入一项保险额度'); if (!param.insuranceCoverageConfigList.length) return ElMessage.error('请至少输入一项保险额度');
if (isIllegalNum(param.premiumAmount)) { if (isIllegalNum(param.premiumAmount)) {
return ElMessage.error('请输入合理的保费金额'); return ElMessage.error('请输入合理的保费金额');
} else {
param.premiumAmount = Math.round(Number(param.premiumAmount) * 100) / 100;
} }
param.premiumAmount = Math.round(Number(param.premiumAmount) * 100) / 100;
if (!param.formOfPayment) return ElMessage.error('请选择缴纳形式'); if (!param.formOfPayment) return ElMessage.error('请选择缴纳形式');
if (isIllegalNum(param.insuranceDeadline)) return ElMessage.error('请输入合理的保险期限'); if (isIllegalNum(param.insuranceDeadline)) return ElMessage.error('请输入合理的保险期限');
if (!param.insuranceDeadlineUnit) return ElMessage.error('请选择保险期限'); if (!param.insuranceDeadlineUnit) return ElMessage.error('请选择保险期限');
param.insuranceDeadline = param.insuranceDeadline + param.insuranceDeadlineUnit; param.insuranceDeadline += param.insuranceDeadlineUnit;
if (!param.applicationMaterial.length) return ElMessage.error('请至少选择一项申请材料'); if (!param.applicationMaterial.length) return ElMessage.error('请至少选择一项申请材料');
if (!param.exemptionFromLiability.length) return ElMessage.error('请至少选择一项责任免除'); if (!param.exemptionFromLiability.length) return ElMessage.error('请至少选择一项责任免除');
param.applicationMaterial = param.applicationMaterial.join(); param.applicationMaterial = param.applicationMaterial.join();
param.exemptionFromLiability = param.exemptionFromLiability.join(); param.exemptionFromLiability = param.exemptionFromLiability.join();
const res = await addInsuranceProducts(param); const res = await addInsuranceProducts(param);
router.push(`/product/insurance/detail?id=` + res.message); router.push(`/product/insurance/detail?id=${res.message}`);
addRecord(param); addRecord(param);
ElMessage.success('提交成功!'); ElMessage.success('提交成功!');
emit('getList'); emit('getList');

@ -1,48 +1,36 @@
<template> <template>
<div class="block card-list flex py-0"> <div class="block card-list flex py-0">
<div class="left"> <div class="left">
<div class="flex justify-center items-center py-2 mb-3 text-sm text-[#006BFF] bg-[rgba(0,107,255,0.1)] border border-solid border-[#006BFF] rounded-[10px] cursor-pointer" <div
@click="toAdd"> class="flex justify-center items-center py-2 mb-3 text-sm text-[#006BFF] bg-[rgba(0,107,255,0.1)] border border-solid border-[#006BFF] rounded-[10px] cursor-pointer"
<el-icon class="mr-1" @click="toAdd"
:size="16" >
color="#006BFF"> <el-icon class="mr-1" :size="16" color="#006BFF">
<Plus /> <Plus />
</el-icon> </el-icon>
新增产品 新增产品
</div> </div>
<div class="flex justify-end mb-4"> <div class="flex justify-end mb-4">
<img src="@/assets/images/fold.png" <img src="@/assets/images/fold.png" alt="" class="cursor-pointer" @click="toList" />
alt=""
class="cursor-pointer"
@click="toList" />
</div> </div>
<ul class="products"> <ul class="products">
<li v-for="(item, i) in list" <li v-for="(item, i) in list" :key="i" :class="{ active: item.insuranceId === id }" @click="switchProduct(item.insuranceId)">
:key="i" <el-popconfirm title="您确定删除吗?" @confirm="handleDelete(item.insuranceId)">
:class="{ active: item.insuranceId === id }"
@click="switchProduct(item.insuranceId)">
<el-popconfirm title="您确定删除吗?"
@confirm="handleDelete(item.insuranceId)">
<template #reference> <template #reference>
<img src="@/assets/images/trash.png" <img src="@/assets/images/trash.png" alt="" class="del" />
alt=""
class="del" />
</template> </template>
</el-popconfirm> </el-popconfirm>
<h6>{{ item.insuranceName }}</h6> <h6>{{ item.insuranceName }}</h6>
<p v-if="item.minimumAge && item.maximumAge" <p v-if="item.minimumAge && item.maximumAge" class="type">{{ item.minimumAge + '-' + item.maximumAge + '周岁' }}</p>
class="type">{{ item.minimumAge + '-' + item.maximumAge + '周岁' }}</p> <p v-if="item.insuranceCoverageConfig" class="type">{{ item.insuranceCoverageConfig }}万保额</p>
<p v-if="item.insuranceCoverageConfig"
class="type">{{ item.insuranceCoverageConfig }}万保额</p>
<p class="meta">创建日期{{ item.operationTime }}</p> <p class="meta">创建日期{{ item.operationTime }}</p>
</li> </li>
</ul> </ul>
</div> </div>
<div class="right"> <div class="right">
<detail v-if="action === 'detail'"></detail> <detail v-if="action === 'detail'"></detail>
<add v-else-if="action === 'add'" <add v-else-if="action === 'add'" @getList="getList"></add>
@getList="getList"></add>
</div> </div>
</div> </div>
</template> </template>
@ -53,10 +41,10 @@ import { ElMessage } from 'element-plus';
import { Plus } from '@element-plus/icons-vue'; import { Plus } from '@element-plus/icons-vue';
import { insuranceList, batchDeletion } from '@/api/insurance'; import { insuranceList, batchDeletion } from '@/api/insurance';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import Detail from './Detail.vue';
import Add from './Add.vue';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import { getIds } from '@/utils/common'; import { getIds } from '@/utils/common';
import Detail from './Detail.vue';
import Add from './Add.vue';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
@ -69,20 +57,22 @@ const loading = ref<boolean>(false);
const id = computed(() => +route.query.id); const id = computed(() => +route.query.id);
// //
const getList = async (first: any) => { const getList = async (first: any) => {
loading.value = true; if (!Cookies.get('sand-submit')) {
try { loading.value = true;
const { data } = await insuranceList({ try {
...getIds(), const { data } = await insuranceList({
pageNum: 1, ...getIds(),
pageSize: 1000, pageNum: 1,
insuranceName: route.query.name ?? '', pageSize: 1000,
createDateSort: route.query.createDateSort ?? '', insuranceName: route.query.name ?? '',
insuranceType: route.query.insuranceType ?? '', createDateSort: route.query.createDateSort ?? '',
}); insuranceType: route.query.insuranceType ?? '',
list.value = data.records; });
first && list.value.length && switchProduct(list.value[0].insuranceId); list.value = data.records;
} finally { first && list.value.length && switchProduct(list.value[0].insuranceId);
loading.value = false; } finally {
loading.value = false;
}
} }
}; };
onMounted(() => { onMounted(() => {
@ -100,7 +90,7 @@ watch(
); );
// //
const switchProduct = (insId: number) => { const switchProduct = (insId: number) => {
router.push(`/product/insurance/detail?id=` + insId); router.push(`/product/insurance/detail?id=${insId}`);
}; };
// //
const toAdd = () => { const toAdd = () => {

@ -1,8 +1,7 @@
<template> <template>
<div> <div>
<el-tabs v-model="curTab"> <el-tabs v-model="curTab">
<el-tab-pane label="产品详情" <el-tab-pane label="产品详情" name="tab1">
name="tab1">
<info /> <info />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>

@ -1,46 +1,37 @@
<template> <template>
<div class="info my-2"> <div class="info my-2">
<h2 class="text-center text-lg">{{info.insuranceName}}</h2> <h2 class="text-center text-lg">{{ info.insuranceName }}</h2>
<p class="text">险种分类{{ info.insuranceType }}</p> <p class="text">险种分类{{ info.insuranceType }}</p>
<p v-if="info.minimumAge && info.maximumAge" <p v-if="info.minimumAge && info.maximumAge" class="text">承保年龄{{ info.minimumAge + '-' + info.maximumAge + '周岁' }}</p>
class="text">承保年龄{{ info.minimumAge + '-' + info.maximumAge + '周岁' }}</p> <p v-if="info.insuranceDeadline" class="text">保险期限{{ info.insuranceDeadline }}</p>
<p v-if="info.insuranceDeadline"
class="text">保险期限{{ info.insuranceDeadline }}</p>
<div class="text"> <div class="text">
<div class="flex"> <div class="flex">
<p class="w-[130px] mr-32">保险责任</p> <p class="w-[130px] mr-32">保险责任</p>
<p class="">保额</p> <p class="">保额</p>
</div> </div>
<div v-for="(item, i) in info.insuranceCoverageConfigList" <div v-for="(item, i) in info.insuranceCoverageConfigList" :key="item" class="flex">
:key="item"
class="flex">
<p class="w-[130px] mr-32">{{ item.insuranceCoverage }}</p> <p class="w-[130px] mr-32">{{ item.insuranceCoverage }}</p>
<p>{{ Number(item.sumInsured * (item.insuredLiabilityId === 764 || item.insuredLiabilityId === 765 ? 1 : 10000)).toFixed(2) }}</p> <p>{{ Number(item.sumInsured * (item.insuredLiabilityId === 764 || item.insuredLiabilityId === 765 ? 1 : 10000)).toFixed(2) }}</p>
</div> </div>
</div> </div>
<p v-if="info.premiumAmount" <p v-if="info.premiumAmount" class="text">保费金额{{ Number(info.premiumAmount).toFixed(2) }}</p>
class="text">保费金额{{ Number(info.premiumAmount).toFixed(2) }}</p> <p v-if="info.formOfPayment" class="text">缴纳形式{{ info.formOfPayment }}</p>
<p v-if="info.formOfPayment" <div v-if="info.applicationMaterialList?.length" class="text">
class="text">缴纳形式{{ info.formOfPayment }}</p>
<div v-if="info.applicationMaterialList?.length"
class="text">
申请材料 申请材料
<p v-for="(item, i) in info.applicationMaterialList" <p v-for="(item, i) in info.applicationMaterialList" :key="item">{{ i + 1 }}{{ item }}</p>
:key="item">{{ i + 1 }}{{item}}</p>
</div> </div>
<div v-if="info.exemptionFromLiabilityList?.length" <div v-if="info.exemptionFromLiabilityList?.length" class="text">
class="text">
责任免除 责任免除
<p v-for="(item, i) in info.exemptionFromLiabilityList" <p v-for="(item, i) in info.exemptionFromLiabilityList" :key="item">{{ i + 1 }}{{ item }}</p>
:key="item">{{ i + 1 }}{{item}}</p>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'; import { ref, computed, watch } from 'vue';
import { insuranceProductDetails } from '@/api/insurance'; import { insuranceProductDetails } from '@/api/insurance';
import { useRouter, useRoute } from 'vue-router'; import { useRouter, useRoute } from 'vue-router';
import Cookies from 'js-cookie';
const router = useRouter(); const router = useRouter();
const route = useRoute(); const route = useRoute();
@ -49,7 +40,7 @@ const info = ref<Record<string, any>>({});
// //
const getDetail = async () => { const getDetail = async () => {
if (id.value) { if (id.value && !Cookies.get('sand-submit')) {
try { try {
const { data } = await insuranceProductDetails(id.value); const { data } = await insuranceProductDetails(id.value);
info.value = data; info.value = data;

@ -1,104 +1,68 @@
<template> <template>
<div class="block"> <div class="block">
<div class="flex justify-between items-center mb-5"> <div class="flex justify-between items-center mb-5">
<search v-model="params.insuranceName" <search v-model="params.insuranceName" @change="initList"></search>
@change="initList"></search>
<div class="filter"> <div class="filter">
<div class="select"> <div class="select">
<el-select v-model="params.insuranceType" <el-select v-model="params.insuranceType" placeholder="险种分类" size="large" clearable>
placeholder="险种分类" <el-option v-for="item in insuranceTypes" :key="item.id" :label="item.name" :value="item.id" />
size="large"
clearable>
<el-option v-for="item in insuranceTypes"
:key="item.id"
:label="item.name"
:value="item.id" />
</el-select> </el-select>
<img src="@/assets/images/7.png" <img src="@/assets/images/7.png" alt="" class="icon" />
alt=""
class="icon" />
</div> </div>
<div class="add-btn" <div class="add-btn" @click="toAdd">
@click="toAdd"> <img src="@/assets/images/plus.png" alt="" class="icon" />
<img src="@/assets/images/plus.png"
alt=""
class="icon" />
新增产品 新增产品
</div> </div>
<img src="@/assets/images/9.png" <img src="@/assets/images/9.png" alt="" class="ml-4 cursor-pointer" @click="toCardList" />
alt=""
class="ml-4 cursor-pointer"
@click="toCardList" />
</div> </div>
</div> </div>
<el-table ref="table" <el-table ref="table" v-loading="loading" :data="list" @sort-change="handleSort">
v-loading="loading" <el-table-column prop="insuranceName" label="保险名称" min-width="150"></el-table-column>
:data="list" <el-table-column prop="insuranceTypeName" label="险种分类" min-width="100"></el-table-column>
@sort-change="handleSort"> <el-table-column prop="minimumAge" label="承保年龄" min-width="100">
<el-table-column prop="insuranceName"
label="保险名称"
min-width="150"></el-table-column>
<el-table-column prop="insuranceTypeName"
label="险种分类"
min-width="100"></el-table-column>
<el-table-column prop="minimumAge"
label="承保年龄"
min-width="100">
<template #default="{ row }"> <template #default="{ row }">
{{ row.minimumAge && row.maximumAge ? row.minimumAge + ' - ' + row.maximumAge + '周岁' : '-' }} {{ row.minimumAge && row.maximumAge ? row.minimumAge + ' - ' + row.maximumAge + '周岁' : '-' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="insuranceCoverageConfig" <el-table-column prop="insuranceCoverageConfig" label="保险额度(元)" min-width="300">
label="保险额度(元)"
min-width="300">
<template #default="{ row }"> <template #default="{ row }">
{{ row.insuranceCoverageConfig ? row.insuranceCoverageConfig + '万' : '-' }} {{ row.insuranceCoverageConfig ? row.insuranceCoverageConfig + '万' : '-' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="insuranceDeadline" <el-table-column prop="insuranceDeadline" label="保险期限" min-width="100">
label="保险期限"
min-width="100">
<template #default="{ row }"> <template #default="{ row }">
{{ row.insuranceDeadline || '-' }} {{ row.insuranceDeadline || '-' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="premiumAmount" <el-table-column prop="premiumAmount" label="保费金额(元)" min-width="140">
label="保费金额(元)"
min-width="140">
<template #default="{ row }"> <template #default="{ row }">
{{ row.premiumAmount?.toFixed(2) || '-' }} {{ row.premiumAmount?.toFixed(2) || '-' }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="operationTime" <el-table-column prop="operationTime" label="创建日期" width="180" sortable="custom"></el-table-column>
label="创建日期" <el-table-column label="操作" width="140">
width="180"
sortable="custom"></el-table-column>
<el-table-column label="操作"
width="140">
<template #default="{ row }"> <template #default="{ row }">
<el-popconfirm title="您确定删除吗?" <el-popconfirm title="您确定删除吗?" @confirm.stop="handleDelete(row.insuranceId)">
@confirm.stop="handleDelete(row.insuranceId)">
<template #reference> <template #reference>
<el-button type="text" <el-button type="primary" link size="small" @click.stop="stop">删除</el-button>
size="small"
@click.stop="stop">删除</el-button>
</template> </template>
</el-popconfirm> </el-popconfirm>
<el-button type="text" <el-button type="primary" link @click="toDetail(`/product/insurance/detail`, row.insuranceId)" size="small">产品详情</el-button>
@click="toDetail(`/product/insurance/detail`, row.insuranceId)" </template></el-table-column
size="small">产品详情</el-button> >
</template></el-table-column>
</el-table> </el-table>
<el-pagination v-model:currentPage="currentPage" <el-pagination
v-model:pageSize="pageSize" v-model:currentPage="currentPage"
:total="total" v-model:pageSize="pageSize"
:page-sizes="pageSizes" :total="total"
:layout="pageLayout" :page-sizes="pageSizes"
@size-change="getList()" :layout="pageLayout"
@current-change="getList()" @size-change="getList()"
small @current-change="getList()"
background small
class="px-3 py-2 justify-end"></el-pagination> background
class="px-3 py-2 justify-end"
></el-pagination>
</div> </div>
</template> </template>
@ -140,13 +104,15 @@ const loading = ref<boolean>(false);
const stop = () => {}; const stop = () => {};
// //
const getList = async () => { const getList = async () => {
loading.value = true; if (!Cookies.get('sand-submit')) {
try { loading.value = true;
const { data } = await insuranceList({ pageNum: currentPage.value, pageSize: pageSize.value, ...toParams(params) }); try {
list.value = data.records; const { data } = await insuranceList({ pageNum: currentPage.value, pageSize: pageSize.value, ...toParams(params) });
total.value = data.total; list.value = data.records;
} finally { total.value = data.total;
loading.value = false; } finally {
loading.value = false;
}
} }
}; };
// //

@ -1,304 +0,0 @@
<template>
<!-- 个人额度模型 -->
<el-form label-width="80px"
class="form"
status-icon>
<h6 class="step-name mb-2">{{ formProcess[0]?.name }}</h6>
<el-form-item label="不超过">
<el-select v-model="form.firstMode">
<el-option v-for="item in formProcess[0]?.recordChildren[0]?.subject?.itemList"
:key="item"
:value="item.options" />
</el-select>
</el-form-item>
<h6 class="step-name mt-4 mb-2">{{ formProcess[1]?.name }}</h6>
<el-form-item label="不超过">
<el-select v-model="form.secondMode">
<el-option v-for="item in formProcess[1]?.recordChildren[0]?.subject?.itemList"
:key="item"
:value="item.options" />
</el-select>
</el-form-item>
<h6 class="step-name mt-4 mb-2">{{ formProcess[2]?.name }}</h6>
<el-form-item label="不超过">
<el-select v-model="form.thirdMode">
<el-option v-for="item in formProcess[2]?.recordChildren[0]?.subject?.itemList"
:key="item"
:value="item.options" />
</el-select>
</el-form-item>
<el-form-item label="且"></el-form-item>
<el-form-item label="不超过">
<el-select v-model="form.andThird">
<el-option v-for="item in formProcess[2]?.recordChildren[1]?.subject?.itemList"
:key="item"
:value="item.options" />
</el-select>
</el-form-item>
<el-form-item label="额度模型">
<el-table class="c-table"
:data="form.individualCreditModels"
:span-method="span"
:cell-style="{background:'#fff'}"
border>
<el-table-column prop="indexName"
label="指标名称"
min-width="100"
align="center">
<template #default="{ row, $index }">
<span :class="{'text-[#006bff]': !$index || $index === len}">{{ row?.indexName }}</span>
</template>
</el-table-column>
<el-table-column label="描述"
min-width="150">
<template #default="{ row, $index }">
<span :class="{'text-[#006bff]': !$index || $index === len}">{{ row?.description }}</span>
</template>
</el-table-column>
<el-table-column label="分值"
min-width="150">
<template #default="{ row, $index }">
<div v-if="$index !== len"
class="flex items-center">
<span v-if="!$index"
class="mr-2 whitespace-nowrap">{{ row?.subject?.name }}</span>
<el-select v-if="row.subject"
v-model="row.score">
<el-option v-for="item in row?.subject?.itemList.sort((a, b) => +(a.options.replace(/[^\d-]/, '')) - +(b.options.replace(/[^\d-]/, '')))"
:key="item"
:value="item.options" />
</el-select>
</div>
<span v-else
class="text-[#006bff]">以上分值合计</span>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
<div class="flex justify-end">
<div class="submit"
@click="submit">确认完成配置</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElMessage, ElLoading } from 'element-plus';
import { personalCreditModelDetails, personalCreditModelSaveOrUpdate } from '@/api/model';
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment';
import type { TableColumnCtx } from 'element-plus';
import { useRouter, useRoute } from 'vue-router';
import { handleId, getIds } from '@/utils/common';
import Cookies from 'js-cookie';
const router = useRouter();
const route = useRoute();
let loading = null;
const form = ref<Record<string, any>>({
...getIds(),
andThird: '',
firstMode: '',
secondMode: '',
thirdMode: '',
type: 1,
individualCreditModels: [],
});
const formProcess = ref<Record<string, any>[]>([]);
const info = ref<Record<string, any>[]>([]);
const len = ref<number>(0);
//
const getConfig = async () => {
const { process } = await getProcessInformationBasedOnRoles(772);
formProcess.value = process.slice(0, 3);
const list = process[3]?.recordChildren;
let cur = info.value.length ? info.value[0] : {};
const result = [
{
modelId: cur?.modelId || '',
id: cur?.id || '',
indexName: list[0]?.name,
description: list[0]?.remark,
subject: list[0]?.recordChildren[0]?.subject,
score: cur?.score || '',
},
];
const length = list.length - 1;
list?.forEach((e, i) => {
if (i && i !== length) {
cur = info.value.length ? info.value[i] : {};
let temp = {
indexName: e.name,
recordChildren: e.recordChildren,
stRecordId: e.id,
ruleId: e?.recordChildren[0]?.id || '',
description: e?.recordChildren[0]?.name || '',
subject: e?.recordChildren[0]?.subject || [],
score: '',
};
result.push(temp);
e?.recordChildren.forEach((n, j) => {
if (j) {
temp = JSON.parse(JSON.stringify(temp));
temp.description = n.name;
temp.subject = n.subject;
temp.ruleId = n.id;
result.push(temp);
}
});
}
});
cur = info.value.length ? info.value[info.value.length - 1] : {};
result.push({
indexName: list[length]?.name,
description: list[length]?.remark,
subject: list[length]?.subject,
score: '',
});
len.value = result.length - 1;
if (info.value.length) {
result.forEach((e, i) => {
result[i].score = info.value[i].score;
result[i].id = info.value[i].id;
result[i].modelId = info.value[i].modelId;
});
}
form.value.individualCreditModels = result;
loading.close();
};
//
const getDetail = async (load?: number) => {
if (load) loading = ElLoading.service();
try {
const { data } = await personalCreditModelDetails();
if (data) {
form.value = data;
info.value = data.individualCreditModels;
}
getConfig();
} finally {
}
};
onMounted(() => {
getDetail(1);
});
interface SpanMethodProps {
row: Record<string, any>;
column: TableColumnCtx<Record<string, any>>;
rowIndex: number;
columnIndex: number;
}
const rowMerge1 = [1, 7, 16, 23, 71, 75, 87, 98];
const rowMerge2 = [5, 30, 59, 61, 63, 79];
const rowMerge3 = [11, 38, 45];
const rowMerge4 = [20, 27, 50, 53, 56, 65, 68, 81, 84, 102, 105, 108];
const rowMerge5 = [0, 43, 44, 111];
//
const span = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
if (columnIndex === 0) {
if (rowMerge1.includes(rowIndex)) {
return {
rowspan: 4,
colspan: 1,
};
} else if (rowMerge2.includes(rowIndex)) {
return {
rowspan: 2,
colspan: 1,
};
} else if (rowMerge3.includes(rowIndex)) {
return {
rowspan: 5,
colspan: 1,
};
} else if (rowMerge4.includes(rowIndex)) {
return {
rowspan: 3,
colspan: 1,
};
} else if (rowIndex === 32) {
return {
rowspan: 6,
colspan: 1,
};
} else if (rowIndex === 91) {
return {
rowspan: 7,
colspan: 1,
};
} else if (rowMerge5.includes(rowIndex)) {
return {
rowspan: 1,
colspan: 1,
};
} else {
return {
rowspan: 0,
colspan: 0,
};
}
}
};
const getItemId = (name: string): number | string => {
if (!name) return '';
return formProcess.value[0]?.recordChildren[0]?.subject?.itemList.find((e) => e.options === name)?.itemId;
};
//
const addRecord = async (data: Record<string, any>) => {
let preIds = `1,${Cookies.get('sand-level')},42,68,756,772`; // 1id
const rule: Array<Record<string, any>> = [];
data.firstMode && rule.push(handleId(777, 236, getItemId(data.firstMode), preIds + ',774,777', 1));
data.secondMode && rule.push(handleId(777, 236, getItemId(data.secondMode), preIds + ',775,777', 1));
data.thirdMode && rule.push(handleId(777, 236, getItemId(data.thirdMode), preIds + ',776,777', 1));
data.andThird && rule.push(handleId(778, 236, getItemId(data.andThird), preIds + ',776,778', 1));
preIds += `,788`;
form.value.individualCreditModels[0].score &&
rule.push(
handleId(
790,
238,
form.value?.individualCreditModels[0]?.subject?.itemList.find((e) => e.options === form.value.individualCreditModels[0].score)?.itemId,
preIds + ',789,790',
1,
),
);
form.value.individualCreditModels.forEach((e, i) => {
if (i && i !== len.value && e.subject) {
e.score && rule.push(handleId(e.ruleId, e.subject.subjectId, e?.subject?.itemList?.find((n) => n.options === e.score)?.itemId, `${preIds},${e.stRecordId},${e.ruleId}`, 1));
}
});
await addOperation({
...getIds(),
parentId: preIds,
lcJudgmentRuleReq: rule,
});
};
//
const submit = async () => {
const param = JSON.parse(JSON.stringify(form.value));
param?.individualCreditModels.forEach((e, i) => {
delete e.recordChildren;
delete e.subject;
});
loading = ElLoading.service();
await personalCreditModelSaveOrUpdate(param);
addRecord(param);
getDetail();
ElMessage.success('提交成功!');
};
</script>
<style lang="scss" scoped>
@import url(../../../styles/form.scss);
.c-table {
:deep(.el-input__inner) {
@apply px-2;
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save