Compare commits

..

62 Commits

Author SHA1 Message Date
yujialong cec85a91dc 实验报告导出 1 month ago
yujialong ea02b0c2ae fix 1 month ago
yujialong 170ed08b45 fix 2 months ago
yujialong ea144afa12 fix 3 months ago
yujialong 6d8f7a338d 提交后不再查询列表和详情 5 months ago
yujialong 0ca09ffa98 fix 5 months ago
yujialong c0299db074 实验报告loading 5 months ago
yujialong a9db2570fe fix 7 months ago
yujialong 1174a60114 实验报告且或 9 months ago
yujialong 480e5f35fe 所有策略的弹框层级降低为10 9 months ago
yujialong 83530b7bf4 fix 9 months ago
yujialong 092e66ac0b fix 9 months ago
yujialong 44a88fc28a fix 9 months ago
yujialong a5cc5d3874 eslint配置修改并修复 9 months ago
yujialong a16f29184b 配置风控里添加新增策略的入口 9 months ago
yujialong e7b21ece0b vue升级成3.2.34 9 months ago
yujialong 68a17fad68 企业信用评分及企业利率模型默认计算公式 9 months ago
yujialong 9f41401a10 element-plus升级至2.4.3 9 months ago
yujialong 4967b00c9b 模型里内置数据只能查看 9 months ago
yujialong 5723015aa5 fix 9 months ago
yujialong 0aeb30a000 策略同步的提示 9 months ago
yujialong 2ad7e088ae fix 9 months ago
yujialong 795d254f8f 模型保存后查询左侧菜单待处理数量 9 months ago
yujialong 49bf13759d fix 9 months ago
yujialong 058dbd96f6 8个策略添加是跟否单选 9 months ago
yujialong 9a0868d8c9 策略添加判断是否有绑定产品 9 months ago
yujialong 44c5a142ad 动态引入组件优化 10 months ago
yujialong f0a342b470 fix 10 months ago
yujialong 73ee648b97 模型添加loading 10 months ago
yujialong 1369206c2e 贷后管理模型联调 10 months ago
yujialong 53913f3f19 利率定价模型联调 10 months ago
yujialong 957ae65af6 信用评分联调 10 months ago
yujialong 0d12df5652 配置风控策略相关判分 10 months ago
yujialong 39534bf322 准入策略联调完成 10 months ago
yujialong 4d2374a38d 配置风控及策略联调 10 months ago
yujialong 331cf3e493 配置风控及策略联调 10 months ago
yujialong ae5899a977 fix 10 months ago
yujialong ea29e820e3 政务黑名单改成列表 10 months ago
yujialong 9cdbe2dbe7 准入模型左侧导航改成分级菜单 10 months ago
yujialong ec99648a44 测试表头字段名V1.0.3修改 10 months ago
yujialong bd996b5cc3 fix 10 months ago
yujialong 8dafd693ef fix 10 months ago
yujialong d811eba4b6 fix 11 months ago
yujialong f855d54174 银行相关修复 11 months ago
yujialong 81269748e5 fix 11 months ago
yujialong e190b065b2 优化无用代码 11 months ago
yujialong ec385dda77 银行相关1.0.2需求 11 months ago
yujialong 50a5452471 银行要素回显等 11 months ago
yujialong a898ec4a9b 自适应 11 months ago
yujialong 771c36beee fix 11 months ago
yujialong 149e71e481 重复提交的问题,及去掉i18n 11 months ago
yujialong 250c14b3da fix 11 months ago
yujialong 67e6360ace fix 11 months ago
yujialong 8558fa84cf 模型判分id修复 11 months ago
yujialong e011a0cc6d fix 11 months ago
yujialong 00f09e0488 fix 11 months ago
yujialong 5390916ca9 fix 12 months ago
yujialong e2c1376608 全部模块的列表新增加上考核id、竞赛id 12 months ago
yujialong b455947c6a fix 12 months ago
yujialong fa6e48314e 配置风控选项联调 12 months ago
yujialong da1ace2eff fix 12 months ago
yujialong 80f49ab21e 模型高度自适应,个人银行产品新增修改 1 year ago
  1. 6
      .env
  2. 2
      .env.production
  3. 2
      .env.test
  4. 5
      .eslintrc.js
  5. 9
      index.html
  6. 346
      package-lock.json
  7. 8
      package.json
  8. 462
      public/tinymce/langs/zh_CN.js
  9. 419
      public/tinymce/langs/zh_TW.js
  10. 7
      public/tinymce/skins/content/dark/content.min.css
  11. 7
      public/tinymce/skins/content/default/content.min.css
  12. 7
      public/tinymce/skins/content/document/content.min.css
  13. 7
      public/tinymce/skins/content/writer/content.min.css
  14. 7
      public/tinymce/skins/ui/oxide-dark/content.inline.min.css
  15. 7
      public/tinymce/skins/ui/oxide-dark/content.min.css
  16. 7
      public/tinymce/skins/ui/oxide-dark/content.mobile.min.css
  17. BIN
      public/tinymce/skins/ui/oxide-dark/fonts/tinymce-mobile.woff
  18. 7
      public/tinymce/skins/ui/oxide-dark/skin.min.css
  19. 7
      public/tinymce/skins/ui/oxide-dark/skin.mobile.min.css
  20. 7
      public/tinymce/skins/ui/oxide-dark/skin.shadowdom.min.css
  21. 7
      public/tinymce/skins/ui/oxide/content.inline.min.css
  22. 7
      public/tinymce/skins/ui/oxide/content.min.css
  23. 7
      public/tinymce/skins/ui/oxide/content.mobile.min.css
  24. BIN
      public/tinymce/skins/ui/oxide/fonts/tinymce-mobile.woff
  25. 7
      public/tinymce/skins/ui/oxide/skin.min.css
  26. 7
      public/tinymce/skins/ui/oxide/skin.mobile.min.css
  27. 7
      public/tinymce/skins/ui/oxide/skin.shadowdom.min.css
  28. 7
      src/App.vue
  29. 5
      src/api/bank.ts
  30. 4
      src/api/config.ts
  31. 7
      src/api/judgment.ts
  32. 225
      src/api/model.ts
  33. 8
      src/api/system.ts
  34. 31
      src/api/user.ts
  35. 1
      src/assets/svgs/preview.svg
  36. 2
      src/components/AliOss/upload.ts
  37. 10
      src/components/Back.vue
  38. 258
      src/components/DialogForm.vue
  39. 30
      src/components/HelloI18n.vue
  40. 17
      src/components/LabelTip.vue
  41. 27
      src/components/ListMove.vue
  42. 703
      src/components/Panel/index.vue
  43. 59
      src/components/QueryForm/QueryForm.vue
  44. 16
      src/components/QueryForm/QueryInput.vue
  45. 64
      src/components/QueryForm/QueryItem.vue
  46. 2
      src/components/QueryForm/index.ts
  47. 9
      src/components/Search.vue
  48. 34
      src/components/StrategyConfirm.vue
  49. 45
      src/components/TableList/ColumnList.vue
  50. 40
      src/components/TableList/ColumnSetting.vue
  51. 2
      src/components/TableList/index.ts
  52. 55
      src/components/TableList/useColumns.ts
  53. 11
      src/components/Tinymce/index.vue
  54. 118
      src/components/Upload/BaseUpload.vue
  55. 136
      src/components/Upload/FileListUpload.vue
  56. 84
      src/components/Upload/ImageCropper.vue
  57. 157
      src/components/Upload/ImageListUpload.vue
  58. 149
      src/components/Upload/ImageUpload.vue
  59. 4
      src/components/Upload/index.ts
  60. 335
      src/data.ts
  61. 35
      src/layout/components/AppHeader.vue
  62. 3
      src/layout/components/AppMain.vue
  63. 172
      src/layout/components/AppSidebar/Menu.vue
  64. 46
      src/layout/components/AppSidebar/index.vue
  65. 8
      src/layout/components/Logo.vue
  66. 22
      src/layout/index.vue
  67. 5
      src/permission.ts
  68. 2
      src/router/index.ts
  69. 10
      src/settings.ts
  70. 2
      src/store/useCurrentUser.ts
  71. 23
      src/store/useProduct.ts
  72. 26
      src/styles/form.scss
  73. 53
      src/styles/index.scss
  74. 4
      src/utils/auth.ts
  75. 32
      src/utils/common.ts
  76. 6
      src/utils/getPageTitle.ts
  77. 47
      src/utils/request.ts
  78. 9
      src/views/403.vue
  79. 17
      src/views/404.vue
  80. 96
      src/views/Home.vue
  81. 98
      src/views/Role.vue
  82. 58
      src/views/bankProduct/index.vue
  83. 144
      src/views/config/level/Index.vue
  84. 110
      src/views/config/param/Buyer.vue
  85. 40
      src/views/config/param/Financial.vue
  86. 15
      src/views/config/param/Index.vue
  87. 27
      src/views/finance/Account.vue
  88. 95
      src/views/finance/Bank.vue
  89. 117
      src/views/finance/BankDetail.vue
  90. 114
      src/views/finance/Fund.vue
  91. 88
      src/views/finance/Insurance.vue
  92. 68
      src/views/finance/Order.vue
  93. 92
      src/views/finance/Publish.vue
  94. 174
      src/views/product/afterLoan/1029.vue
  95. 194
      src/views/product/afterLoan/1029/Detail.vue
  96. 157
      src/views/product/afterLoan/1029/Index.vue
  97. 187
      src/views/product/afterLoan/1030.vue
  98. 219
      src/views/product/afterLoan/1030/Detail.vue
  99. 157
      src/views/product/afterLoan/1030/Index.vue
  100. 347
      src/views/product/afterLoan/1031.vue
  101. Some files were not shown because too many files have changed in this diff Show More

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

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

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

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

@ -4,6 +4,15 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>金融产品设计及数字化营销沙盘</title>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement('script');
hm.src = 'https://hm.baidu.com/hm.js?f2fcf78da19a1a04b48b45a07549d1d7';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body>
<div id="app"></div>

346
package-lock.json generated

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

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

@ -9,7 +9,14 @@ import { computed } from 'vue';
import { ElConfigProvider } from 'element-plus';
import { useI18n } from 'vue-i18n';
import { getElementPlusLocale } from '@/i18n';
import Cookies from 'js-cookie';
const { locale } = useI18n({ useScope: 'global' });
const lang = computed(() => getElementPlusLocale(locale.value as string));
console.log(33, document.referrer);
//
if (!document.referrer) {
window.location.href = decodeURIComponent(Cookies.get('sand-referrer'));
}
</script>

@ -11,10 +11,12 @@ export const personalRiskControlConfigurationField = async (): Promise<any> =>
(await axios.post('/product/riskControlConfigurationField/personalRiskControlConfigurationField')).data;
export const productElement = async (id: number): Promise<any> => (await axios.post(`/product/product/bank/products/productElement?id=${id}`)).data;
export const findById = async (id: number): Promise<any> => (await axios.post(`/product/product/bank/products/findById?id=${id}`)).data;
export const elementDetail = async (id: number): Promise<any> => (await axios.post(`/product/product/bank/products/elementDetail?id=${id}`)).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 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> =>
(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> =>
(await axios.post(`/product/product/bank/products/examineAndApprove?id=${id}&opinionDescription=${opinionDescription}&status=${status}&approvalTime=${approvalTime}`)).data;
export const update = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/product/bank/products/update`, data)).data;
@ -22,3 +24,4 @@ export const cancelCollection = async (id: number): Promise<any> => (await axios
export const collect = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/checkPointCollect/collect`, data)).data;
export const submitOpe = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/product/bank/operation/submit`, data)).data;
export const statistics = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/product/bank/products/statistics`, data)).data;
export const approvalRecord = async (params: Record<string, any>): Promise<any> => (await axios.post(`/product/product/bank/products/approvalRecord`, {}, { params })).data;

@ -20,6 +20,6 @@ export const checkPointListByStu = async (projectId: number, displayCollection?:
export const getTheCurrentUserName = async (): Promise<any> => (await axios.post('/product/product/bank/products/getTheCurrentUserName')).data;
export const getOperationTime = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/product/bank/products/getOperationTime?checkPointId=${checkpointId}&projectId=${projectId}`)).data;
(await axios.post(`/product/product/bank/products/getOperationTime?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const saveOperationTime = async (checkpointId: number, projectId: number, operationTime: string): Promise<any> =>
(await axios.post(`/product/product/bank/products/saveOperationTime?checkPointId=${checkpointId}&projectId=${projectId}&operationTime=${operationTime}`)).data;
(await axios.post(`/product/product/bank/products/saveOperationTime?checkpointId=${checkpointId}&projectId=${projectId}&operationTime=${operationTime}`)).data;

@ -14,3 +14,10 @@ export const deleteCache = async (data: Record<string, any>): Promise<any> =>
)
).data;
export const getOperation = async (params?: Record<string, any>): Promise<any> => (await axios.get('/product/product/bank/operation/getOperation', { params })).data;
export const getSandTableLastCache = async (data: Record<string, any>): Promise<any> =>
(
await axios.post(
`/product/product/bank/operation/getSandTableLastCache?cid=${data.cid}&projectId=${data.projectId}&assessmentId=${data.assessmentId}&competitionId=${data.competitionId}`,
)
).data;
export const deleteOperationData = async (data: Record<string, any>): Promise<any> => (await axios.post('/product/product/bank/operation/deleteOperationData', data)).data;

@ -1,84 +1,213 @@
import axios from '@/utils/request';
export const accessStrategyGovernmentBlacklistFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyGovernmentBlacklist/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
import { getIds } from '@/utils/common';
const host = `http://192.168.31.51:9000`;
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> =>
(await axios.post(`/product/accessStrategyGovernmentBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyEnterpriseBlacklistFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyEnterpriseBlacklist/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyGovernmentBlacklistDel = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyGovernmentBlacklist/delete`, data)).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> =>
(await axios.post(`/product/accessStrategyEnterpriseBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyAntiFraudStrategyFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyAntiFraudStrategy/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyEnterpriseBlacklistDel = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyEnterpriseBlacklist/delete`, data)).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> =>
(await axios.post(`/product/accessStrategyAntiFraudStrategy/saveOrUpdate`, data)).data;
export const accessStrategyBusinessBlacklistFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyBusinessBlacklist/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyAntiFraudStrategyDel = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyAntiFraudStrategy/delete`, data)).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> =>
(await axios.post(`/product/accessStrategyBusinessBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyCreditBlacklistFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyCreditBlacklist/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyBusinessBlacklistDel = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/accessStrategyBusinessBlacklist/delete`, data)).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> =>
(await axios.post(`/product/accessStrategyCreditBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyInlineBlacklistFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyInlineBlacklist/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyCreditBlacklistDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/accessStrategyCreditBlacklist/delete`, data)).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> =>
(await axios.post(`/product/accessStrategyInlineBlacklist/saveOrUpdate`, data)).data;
export const accessStrategyNegativeIndustryStrategyFind = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/accessStrategyNegativeIndustryStrategy/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const accessStrategyInlineBlacklistDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/accessStrategyInlineBlacklist/delete`, data)).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> =>
(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 listCredit = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/creditScoringStrategy/list?checkpointId=${data.checkpointId}&projectId=${data.projectId}&pageNum=${data.pageNum}&pageSize=${data.pageSize}`)).data;
(
await axios.post(`/product/creditScoringStrategy/list`, {
...data,
...getIds(),
})
).data;
export const saveCredit = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/creditScoringStrategy/saveOrUpdate`, data)).data;
export const detailRick = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/riskDegreeStrategy/details?checkpointId=${data.checkpointId}&projectId=${data.projectId}&type=${data.type}`)).data;
export const detailRick = async (type: number): Promise<any> =>
(
await axios.post(`/product/riskDegreeStrategy/details`, {
...getIds(),
type,
})
).data;
export const saveRick = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/riskDegreeStrategy/saveOrUpdate`, data)).data;
export const businessInterestRateDetails = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/interestRateModel/businessInterestRateDetails?checkpointId=${checkpointId}&projectId=${projectId}`)).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> =>
(await axios.post(`/product/interestRateModel/businessInterestRateSaveOrUpdate`, data)).data;
export const personalInterestRateDetails = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/interestRateModel/personalInterestRateDetails?checkpointId=${checkpointId}&projectId=${projectId}`)).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> =>
(await axios.post(`/product/interestRateModel/personalInterestRateSaveOrUpdate`, data)).data;
export const businessQuotaModelDetails = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/quotaModel/businessQuotaModelDetails?checkpointId=${checkpointId}&projectId=${projectId}`)).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 businessQuotaModelSaveOrUpdate = async (data: Record<string, any>): Promise<any> =>
(await axios.post(`/product/quotaModel/businessQuotaModelSaveOrUpdate`, data)).data;
export const personalCreditModelDetails = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/quotaModel/personalCreditModelDetails?checkpointId=${checkpointId}&projectId=${projectId}`)).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> =>
(await axios.post(`/product/quotaModel/personalCreditModelSaveOrUpdate`, data)).data;
export const fiveLevelClassificationDetails = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/fiveLevelClassification/details?checkpointId=${checkpointId}&projectId=${projectId}`)).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 postLoanInspectionDetails = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/postLoanInspection/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const fiveLevelClassificationDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/fiveLevelClassification/delete`, data)).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 postCreditScoreDetails = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/postCreditScore/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const postLoanInspectionDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postLoanInspection/delete`, data)).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 postLoanWarningDetails = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/postLoanWarning/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const postCreditScoreDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postCreditScore/delete`, data)).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 collectionAfterLoanDetails = async (checkpointId: number, projectId: number): Promise<any> =>
(await axios.post(`/product/collectionAfterLoan/details?checkpointId=${checkpointId}&projectId=${projectId}`)).data;
export const postLoanWarningDel = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/postLoanWarning/delete`, data)).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 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;

@ -10,9 +10,15 @@ export const getDetailById = async (id: number | string): Promise<any> => (await
export const getCompetition = async (id: number | string): Promise<any> => (await axios.post(`/competition/competition/management/getCompetition?competitionId=${id}`)).data;
export const reportDetail = async (id: number | string): Promise<any> => (await axios.get(`/occupationlab/occupationlab/achievement/reportDetail?reportId=${id}`)).data;
export const exportBankExperimentReport = async (data: Record<string, any>): Promise<any> =>
(await axios.post('/occupationlab/occupationlab/achievement/exportBankExperimentReport', data)).data;
(
await axios.post('/occupationlab/occupationlab/achievement/exportBankExperimentReport', data, {
responseType: 'blob',
})
).data;
export const updateReport = async (data: Record<string, any>): Promise<any> => (await axios.post('/occupationlab/occupationlab/achievement/updateReport', data)).data;
export const editExperimentalData = async (data: Record<string, any>): Promise<any> =>
(await axios.post('/occupationlab/occupationlab/experimentalReport/editExperimentalData', data)).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 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) => {
try {
// 上传到阿里云oss
const res = await client.multipartUpload(Date.now() + '.' + getFileExt(file.name), file);
const res = await client.multipartUpload(`${Date.now()}.${getFileExt(file.name)}`, file);
resolve({
format: getFileExt(file.name),
name: file.name,

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

@ -1,258 +0,0 @@
<template>
<el-dialog
:title="title"
:close-on-click-modal="!unsaved"
:model-value="modelValue"
@update:model-value="$emit('update:modelValue', $event)"
@opened="!isEdit && focus?.focus()"
:width="large ? '98%' : '683px'"
:top="large ? '16px' : undefined"
>
<div>
<el-button v-if="isEdit && addable" :disabled="perm(`${perms}:create`)" type="primary" :icon="Plus" @click="handleAdd">{{ $t('add') }}</el-button>
<el-popconfirm v-if="isEdit" :title="$t('confirmDelete')" @confirm="handleDelete">
<template #reference>
<el-button :loading="buttonLoading" :disabled="disableDelete?.(bean) || perm(`${perms}:delete`)" :icon="Delete">{{ $t('delete') }}</el-button>
</template>
</el-popconfirm>
<el-button v-if="isEdit" @click="handlePrev" :disabled="!hasPrev">{{ $t('form.prev') }}</el-button>
<el-button v-if="isEdit" @click="handleNext" :disabled="!hasNext">{{ $t('form.next') }}</el-button>
<el-button @click="handleCancel" type="primary">{{ $t('back') }}</el-button>
<el-tooltip :content="$t('form.continuous')" placement="top">
<el-switch v-model="continuous" size="small" class="ml-2"></el-switch>
</el-tooltip>
<el-tag v-if="unsaved" type="danger" class="ml-2">{{ $t('form.unsaved') }}</el-tag>
<slot name="header" :values="values" :bean="bean" :isEdit="isEdit"></slot>
</div>
<el-form
:class="['mt-5', 'pr-5']"
ref="form"
v-loading="loading"
:model="values"
:disabled="!editable"
:label-width="labelWidth ?? '150px'"
:label-position="labelPosition ?? 'right'"
>
<slot :values="values" :bean="bean" :isEdit="isEdit"></slot>
<div v-if="editable">
<el-button :disabled="perm(isEdit ? `${perms}:update` : `${perms}:create`)" :loading="buttonLoading" @click.prevent="handleSubmit" type="primary" native-type="submit">
{{ $t('submit') }}
</el-button>
</div>
</el-form>
</el-dialog>
</template>
<script lang="ts">
import { computed, defineComponent, PropType, ref, toRefs, watch } from 'vue';
import { ElMessage } from 'element-plus';
import { Plus, Delete } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
import _ from 'lodash';
import { perm } from '@/store/useCurrentUser';
const CONTINUOUS_SETTINGS = 'ujcms_continuous_settings';
function fetchContinuous(): Record<string, boolean> {
const settings = localStorage.getItem(CONTINUOUS_SETTINGS);
return settings ? JSON.parse(settings) : {};
}
function storeContinuous(settings: Record<string, boolean>) {
localStorage.setItem(CONTINUOUS_SETTINGS, JSON.stringify(settings));
}
function getContinuous(name: string) {
const settings = fetchContinuous();
return settings[name] ?? false;
}
function setContinuous(name: string, continuous: boolean) {
const settings = fetchContinuous();
settings[name] = continuous;
storeContinuous(settings);
}
export default defineComponent({
name: 'DialogForm',
props: {
modelValue: { type: Boolean, required: true },
name: { type: String, required: true },
beanId: { required: true },
beanIds: { type: Array, required: true },
initValues: { type: Function as PropType<(bean?: any) => any>, required: true },
toValues: { type: Function as PropType<(bean: any) => any>, required: true },
queryBean: { type: Function as PropType<(id: any) => Promise<any>>, required: true },
createBean: { type: Function as PropType<(bean: any) => Promise<any>>, required: true },
updateBean: { type: Function as PropType<(bean: any) => Promise<any>>, required: true },
deleteBean: { type: Function as PropType<(ids: any[]) => Promise<any>>, required: true },
disableDelete: { type: Function as PropType<(bean: any) => boolean> },
addable: { type: Boolean, default: true },
editable: { type: Boolean, default: true },
perms: String,
focus: Object,
large: Boolean,
labelPosition: String,
labelWidth: String,
},
emits: {
'update:modelValue': null,
finished: null,
beanChange: null,
beforeSubmit: null,
},
setup(props, { emit }) {
const { name, beanId, beanIds, focus, modelValue: visible } = toRefs(props);
const { t } = useI18n();
const loading = ref<boolean>(false);
const buttonLoading = ref<boolean>(false);
const continuous = ref<boolean>(getContinuous(name.value));
const reseted = ref<boolean>(false);
const unsaved = ref<boolean>(false);
const form = ref<any>();
const values = ref<any>(props.initValues());
const bean = ref<any>({});
const id = ref<any>();
const ids = ref<Array<any>>([]);
const isEdit = computed(() => id.value != null);
const title = computed(() => `${name.value} - ${isEdit.value ? `${t('edit')} (ID: ${id.value})` : `${t('add')}`}`);
const idChanged = async () => {
loading.value = true;
unsaved.value = false;
reseted.value = true;
try {
bean.value = id.value != null ? await props.queryBean(id.value) : {};
values.value = id.value != null ? props.toValues(bean.value) : props.initValues(values.value);
emit('beanChange', bean.value);
form.value.resetFields();
} finally {
loading.value = false;
}
};
watch(visible, () => {
if (visible.value) {
ids.value = beanIds.value;
if (id.value !== beanId.value) {
id.value = beanId.value;
} else if (id.value != null) {
idChanged();
}
if (id.value == null) {
reseted.value = true;
values.value = props.initValues();
}
}
});
watch(id, () => {
idChanged();
});
watch(
// 使 lodash
// https://v3.vuejs.org/guide/reactivity-computed-watchers.html#watching-reactive-objects
() => _.cloneDeep(values.value),
(curr, prev) => {
// bean
if (reseted.value) {
reseted.value = false;
} else if (JSON.stringify(curr) !== JSON.stringify(prev)) {
// values.customsundefined
// watchjsonjsonunsaved
unsaved.value = true;
}
},
{ deep: true },
);
watch(continuous, () => setContinuous(name.value, continuous.value));
const index = computed(() => ids.value.indexOf(id.value));
const hasPrev = computed(() => index.value > 0);
const hasNext = computed(() => index.value < ids.value.length - 1);
const handlePrev = () => {
if (hasPrev.value) {
id.value = ids.value[index.value - 1];
}
};
const handleNext = () => {
if (hasNext.value) {
id.value = ids.value[index.value + 1];
}
};
const handleAdd = () => {
// eslint-disable-next-line no-unused-expressions
focus?.value?.focus?.();
id.value = undefined;
};
const handleCancel = () => {
emit('update:modelValue', false);
};
const handleSubmit = () => {
form.value.validate(async (valid: boolean) => {
if (!valid) return;
buttonLoading.value = true;
try {
emit('beforeSubmit', values.value);
if (isEdit.value) {
await props.updateBean(values.value);
unsaved.value = false;
} else {
await props.createBean(values.value);
// eslint-disable-next-line no-unused-expressions
focus?.value?.focus?.();
unsaved.value = false;
reseted.value = true;
values.value = props.initValues(values.value);
form.value.resetFields();
}
ElMessage.success(t('success'));
if (!continuous.value) emit('update:modelValue', false);
emit('finished', bean.value);
} finally {
buttonLoading.value = false;
}
});
};
const handleDelete = async () => {
buttonLoading.value = true;
try {
await props.deleteBean([id.value]);
if (!continuous.value) emit('update:modelValue', false);
if (hasNext.value) {
handleNext();
ids.value.splice(index.value - 1, 1);
} else if (hasPrev.value) {
handlePrev();
ids.value.splice(index.value + 1, 1);
} else {
emit('update:modelValue', false);
}
ElMessage.success(t('success'));
emit('finished');
} finally {
buttonLoading.value = false;
}
};
const setUnsaved = (bool: boolean) => {
unsaved.value = bool;
};
return {
perm,
handleAdd,
handleDelete,
handleSubmit,
handleCancel,
handlePrev,
handleNext,
hasPrev,
hasNext,
loading,
buttonLoading,
continuous,
unsaved,
isEdit,
form,
values,
bean,
id,
title,
setUnsaved,
Plus,
Delete,
};
},
});
</script>

@ -1,30 +0,0 @@
<template>
<p>{{ t('hello') }}</p>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { useI18n } from 'vue-i18n';
export default defineComponent({
name: 'HelloI18n',
setup() {
const { t } = useI18n({
inheritLocale: true,
useScope: 'local',
});
// Something todo ..
return { t };
},
});
</script>
<i18n>
{
"en": {
"hello": "Hello i18n in SFC!"
}
}
</i18n>

@ -1,17 +0,0 @@
<template>
{{ label ?? $t(message) }}
<el-tooltip :content="tooltip ?? $t(message + '.tooltip')"
placement="top">
<el-icon class="text-base align-text-top"><question-filled /></el-icon>
</el-tooltip>
</template>
<script setup lang="ts">
import { QuestionFilled } from '@element-plus/icons-vue';
defineProps({
label: { type: String },
tooltip: { type: String },
message: { type: String, required: true },
});
</script>

@ -1,27 +0,0 @@
<template>
<el-button-group>
<el-button :disabled="disabled"
:icon="Top"
@click="$emit('move', 'top')">{{ $t('moveTop') }}</el-button>
<el-button :disabled="disabled"
:icon="ArrowUp"
@click="$emit('move', 'up')">{{ $t('moveUp') }}</el-button>
<el-button :disabled="disabled"
:icon="ArrowDown"
@click="$emit('move', 'down')">{{ $t('moveDown') }}</el-button>
<el-button :disabled="disabled"
:icon="Bottom"
@click="$emit('move', 'bottom')">{{ $t('moveBottom') }}</el-button>
</el-button-group>
</template>
<script setup lang="ts">
import { Top, Bottom, ArrowUp, ArrowDown } from '@element-plus/icons-vue';
defineProps({
disabled: { type: Boolean, required: true },
});
defineEmits({
move: null,
});
</script>

@ -1,83 +1,48 @@
<template>
<div v-if="!hidePanel"
:class="['panel', { active: visible }]"
id="panel"
ref="container"
:style="style">
<el-container class="scrollbar"
id="container"
v-show="visible">
<el-header id="header">
<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="selectProject">
<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 v-if="!hidePanel" :class="['panel', { active: visible }]" id="panel" ref="container" :style="style" v-loading="loading">
<el-container class="scrollbar" id="container" v-show="visible">
<el-header class="panel-header" id="panelHeader">
<div class="project">
<div class="inline-flex items-center">
<p class="whitespace-nowrap">实训项目</p>
<el-tooltip effect="dark" content="点击右侧“下三角”按钮可切换实验项目" placement="bottom">
<i class="info el-icon-warning" style="margin-left: 10px"></i>
</el-tooltip>
</div>
<div class="item">
<div>
总得分
<span class="total-score">{{ grade }}</span>
</div>
</div>
<div>
<el-button class="h-[40px]"
@click="toReport"
v-if="isSubmit">查看实验报告</el-button>
<el-button class="reload h-[40px]"
@click="reload"
v-show="per == 0">重新开始</el-button>
<el-button type="primary"
class="submit btn h-[40px]"
:loading="submiting"
@click="submit"
:disabled="isSubmit || !projectList.length">提交</el-button>
<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 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-container id="infoContainer">
<el-aside id="aside"
width="30%">
<el-aside id="aside" width="30%">
<div class="aside-header">
<div class="p-title">
<i class="el-icon-s-order"></i>
<p>实验目标</p>
</div>
<div class="goal">
<div v-if="pd.experimentTargetType == 0 || !pd.experimentTargetType"
class="ql-editor"
v-html="pd.experimentTarget"></div>
<div v-if="pd.experimentTargetType == 0 || !pd.experimentTargetType" class="ql-editor" v-html="pd.experimentTarget"></div>
<mavon-editor v-else
class="md"
v-model="pd.experimentTarget"
:ishljs="true"
:subfield="false"
:editable="false"
:toolbarsFlag="false"
:boxShadowStyle="none" />
<mavon-editor v-else class="md" v-model="pd.experimentTarget" :ishljs="true" :subfield="false" :editable="false" :toolbarsFlag="false" :boxShadowStyle="none" />
</div>
</div>
<div class="aside-footer">
@ -88,35 +53,20 @@
<div>
<el-row>
<el-col :span="24">
<el-card shadow="never"
:border="false">
<el-table class="task-table"
:data="taskList"
:stripe="true">
<el-card shadow="never" :border="false">
<el-table class="task-table" :data="taskList" :stripe="true">
<el-table-column type="index"></el-table-column>
<el-table-column prop="name"
label="判分点"
align="center"></el-table-column>
<el-table-column prop="score"
label="分值"
width="60"
align="center"></el-table-column>
<el-table-column prop="name" label="判分点" align="center"></el-table-column>
<el-table-column prop="score" label="分值" width="60" align="center"></el-table-column>
<template v-if="!param.competitionId">
<el-table-column label="结果"
width="60"
align="center">
<template v-slot="scope">
<el-table-column label="结果" width="60" align="center">
<template #default="{ row }">
<template v-if="isSubmit">
<div v-if="!param.competitionId"
class="flex justify-center items-center">
<el-icon v-if="scope.row.finishedResult"
color="#15d500"
:size="16">
<div v-if="!param.competitionId" class="flex justify-center items-center">
<el-icon v-if="row.finishedResult" color="#15d500" :size="16">
<Check />
</el-icon>
<el-icon v-else
color="#f00"
:size="16">
<el-icon v-else color="#f00" :size="16">
<Close />
</el-icon>
</div>
@ -124,12 +74,9 @@
</template>
</template>
</el-table-column>
<el-table-column prop="score"
label="得分"
width="60"
align="center">
<template v-slot="scope">
<template v-if="isSubmit">{{ param.competitionId ? '-' : scope.row.examScore }}</template>
<el-table-column label="得分" width="60" align="center">
<template #default="{ row }">
<template v-if="isSubmit">{{ param.competitionId ? '-' : row.examScore }}</template>
</template>
</el-table-column>
</template>
@ -141,65 +88,38 @@
</div>
</el-aside>
<el-main id="main">
<el-tabs class="info-tab"
v-model="pannelTab"
type="card">
<el-tab-pane label="项目背景"
name="first">
<div v-if="pd.experimentDescriptionType == 0 || !pd.experimentDescriptionType"
class="ql-editor"
v-html="pd.experimentDescription"></div>
<el-tabs class="info-tab" v-model="pannelTab" type="card">
<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
class="md"
v-model="pd.experimentDescription"
:ishljs="true"
:subfield="false"
:editable="false"
:toolbarsFlag="false"
:boxShadowStyle="none" />
<mavon-editor v-else class="md" v-model="pd.experimentDescription" :ishljs="true" :subfield="false" :editable="false" :toolbarsFlag="false" :boxShadowStyle="none" />
</el-tab-pane>
<el-tab-pane label="实验要求"
name="second">
<el-tab-pane label="实验要求" name="second">
<el-collapse v-model="curReq">
<el-collapse-item v-for="item in points"
:name="item.judgmentId"
:key="item.judgmentId">
<el-collapse-item v-for="item in points" :name="item.judgmentId" :key="item.judgmentId">
<template v-slot:title>
<i class="el-icon-s-ticket"></i>
<div class="break-all des"
v-html="item.name"></div>
<div class="break-all des" v-html="item.name"></div>
</template>
<div v-if="item.experimentalRequirementsType == 0 || !item.experimentalRequirementsType"
class="ql-editor"
v-html="item.experimentalRequirements"></div>
<div v-if="item.experimentalRequirementsType == 0 || !item.experimentalRequirementsType" class="ql-editor" v-html="item.experimentalRequirements"></div>
<mavon-editor v-else
class="md"
v-model="item.experimentalRequirements"
:ishljs="true"
:subfield="false"
:editable="false"
:toolbarsFlag="false"
:boxShadowStyle="none" />
<mavon-editor
v-else
class="md"
v-model="item.experimentalRequirements"
:ishljs="true"
:subfield="false"
:editable="false"
:toolbarsFlag="false"
:boxShadowStyle="none"
/>
</el-collapse-item>
</el-collapse>
</el-tab-pane>
<el-tab-pane label="实验提示"
name="third"
v-if="hintOpen">
<div v-if="pd.experimentHintType == 0 || !pd.experimentHintType"
class="ql-editor"
v-html="pd.experimentHint"></div>
<el-tab-pane label="实验提示" name="third" v-if="hintOpen">
<div v-if="pd.experimentHintType == 0 || !pd.experimentHintType" class="ql-editor" v-html="pd.experimentHint"></div>
<mavon-editor v-else
class="md"
v-model="pd.experimentHint"
:ishljs="true"
:subfield="false"
:editable="false"
:toolbarsFlag="false"
:boxShadowStyle="none" />
<mavon-editor v-else class="md" v-model="pd.experimentHint" :ishljs="true" :subfield="false" :editable="false" :toolbarsFlag="false" :boxShadowStyle="none" />
</el-tab-pane>
</el-tabs>
</el-main>
@ -207,27 +127,21 @@
</el-container>
<div :class="['toggle absolute top-[200px] text-center', visible ? 'top-[35%] left-[100%]' : '']">
<el-icon class="cursor-pointer"
color="#f1772b"
:size="24">
<el-icon class="cursor-pointer" color="#f1772b" :size="24">
<Rank id="toggle" />
</el-icon>
<div class="toggle-panel w-[40px] h-[175px] bg-[length:100%_100%] bg-no-repeat cursor-pointer"
:class="{ active: visible }"
ref="handle"
@click="visible = !visible"></div>
<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>
</div>
</div>
<div v-if="isSubmit && !isReport"
class="z-[199] fixed top-[64px] right-0 bottom-0 left-0 bg-[rgba(0,0,0,.3)]"></div>
<div v-if="isSubmit && !isReport" class="z-[199] fixed top-[64px] right-0 bottom-0 left-0 bg-[rgba(0,0,0,.3)]"></div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, inject, computed, watch } from 'vue';
import { ref, reactive, onMounted, inject, computed, watch, onUnmounted } from 'vue';
import { submitOpe } from '@/api/bank';
import { deleteCache } from '@/api/judgment';
import { pageStuAssessment, getProjectBySystemId, getProjectDetail, getDetailById, getCompetition, getStartTime } from '@/api/system';
import { getSandTableLastCache, deleteOperationData } from '@/api/judgment';
import { getProjectBySystemId, getProjectDetail, getDetailById, getCompetition, getStartTime, heartbeatDetection, initData } from '@/api/system';
import Settings from '@/settings';
import { useRouter, useRoute } from 'vue-router';
import { useRouter, useRoute, beforeRouteLeave } from 'vue-router';
import type { Action } from 'element-plus';
import { ElMessage, ElMessageBox } from 'element-plus';
import { Close, Check, Rank } from '@element-plus/icons-vue';
@ -236,9 +150,9 @@ import Cookies from 'js-cookie';
import { mavonEditor } from 'mavon-editor';
import 'mavon-editor/dist/css/index.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 { getIds, getNow } from '@/utils/common';
import { getNow } from '@/utils/common';
const router = useRouter();
const route = useRoute();
@ -253,6 +167,7 @@ const isReport = ref<boolean>(true);
const grade = ref<string | number>('00');
const text = ref<string>(''); //
const counterTimer = ref<any>(null);
const heartBeatTimer = ref<any>(null);
const day = ref<number | string>(0);
const seconds = ref<number | string>(0);
const minutes = ref<number | string>(0);
@ -265,20 +180,23 @@ const judgmentId = ref<string | number>('');
const curReq = ref<Record<string, any>[]>([]);
const taskList = ref<Record<string, any>[]>([]);
const pannelTab = ref<string>('first');
const loading = ref<boolean>(false);
const submiting = ref<boolean>(false);
const reportId = ref<string | number>('');
const countVal = ref<any>('');
const getLevel = ref();
const container = ref<HTMLElement | null>(null);
const handle = ref<HTMLElement | null>(null);
const { width, height } = useWindowSize();
//
const { x, y, style } = useDraggable(container, {
initialValue: { x: 0, y: 200 },
stopPropagation: true,
handle: handle.value,
onStart(position, e) {
onStart: (p: Position, e: PointerEvent): boolean => {
const { id } = e.target;
if (id !== 'panelHeader' && id !== 'toggle') return false;
return true;
},
});
@ -305,6 +223,7 @@ if (param.token) {
Cookies.set('sand-account', param.account ?? '');
Cookies.set('sand-admin', param.admin ?? ''); //
Cookies.remove('sand-submit');
Cookies.remove('sand-loaded');
router.replace(route.path);
} else {
param.systemId = Cookies.get('sand-systemId');
@ -340,21 +259,28 @@ watch(
);
//
const getSumTime = (): Promise<any> => {
let getSumTime = (reset?: number): Promise<any> => {
return new Promise(async (resolve, reject) => {
const res = await getStartTime({
permissions: per.value,
projectId: param.projectId,
reset,
});
resolve(res.startTime ? new Date(res.startTime) : '');
});
};
//
let getEntryTime = async (resetTime?: number) => {
let now = await getSumTime(resetTime); //
if (!now) now = await getNow();
entryTime.value = now;
};
//
const timeFormat = (num: number): string | number => {
return num < 10 ? `0${num}` : num;
};
//
const reloadCount = () => {
let reloadCount = () => {
clearInterval(counterTimer.value);
countVal.value = '';
day.value = '00';
@ -363,49 +289,55 @@ const reloadCount = () => {
hour.value = '00';
};
//
const counter = (counterTime: number) => {
const leave1 = counterTime % (24 * 3600); //
const leave2 = leave1 % 3600; //
const leave3 = leave2 % 60; //
let counter = async (counterTime: number) => {
if (counterTime <= 0) {
if (per.value) {
clearInterval(counterTimer.value);
// /
if (!Cookies.get('sand-submit')) {
Cookies.set('sand-submit', 'true');
await submit();
submiting.value = true;
ElMessageBox.alert(`${per.value === 1 ? '考核' : '竞赛'}时间已到,系统已自动交卷`, '提示', {
confirmButtonText: '确定',
closeOnClickModal: false,
showClose: false,
callback: (action: Action) => {
logout();
},
});
}
}
} else {
const leave1 = counterTime % (24 * 3600); //
const leave2 = leave1 % 3600; //
const leave3 = leave2 % 60; //
day.value = timeFormat(Math.floor(counterTime / (24 * 3600)));
hour.value = timeFormat(Math.floor(leave1 / 3600));
minutes.value = timeFormat(Math.floor(leave2 / 60));
seconds.value = timeFormat(Math.round(leave3));
day.value = timeFormat(Math.floor(counterTime / (24 * 3600)));
hour.value = timeFormat(Math.floor(leave1 / 3600));
minutes.value = timeFormat(Math.floor(leave2 / 60));
seconds.value = timeFormat(Math.round(leave3));
}
};
//
const startCount = () => {
let startCount = () => {
clearInterval(counterTimer.value);
counterTimer.value = setInterval(() => {
counter(per.value ? countVal.value-- : countVal.value++);
}, 1000);
};
//
const setSubmit = (val: boolean) => {
let setSubmit = (val: boolean) => {
isSubmit.value = val;
Cookies.set('sand-submit', val);
val ? Cookies.set('sand-submit', val) : Cookies.remove('sand-submit');
};
//
const getAssList = async () => {
// const { list } = await pageStuAssessment({
// pageNum: 1,
// pageSize: 10000,
// });
// let done = false;
// // reportIdclassIdclassId
// if (list.find((e) => e.assessmentId == param.assessmentId && e.reportId && e.classId == param.classId)) {
// done = true;
// setSubmit(true);
// ElMessage.error('');
// setTimeout((_) => {
// window.history.back(); //
// }, 1500);
// }
getProDetail();
getAssStatus();
let getAssList = async () => {
await getAssStatus();
await getProDetail();
};
//
const getAssStatus = async () => {
//
let getAssStatus = async () => {
//
if (!isSubmit.value) {
const { data } = await getDetailById(param.assessmentId);
@ -415,6 +347,8 @@ const getAssStatus = async () => {
submit();
ElMessageBox.alert(`考核时间已到,系统已自动交卷`, '提示', {
confirmButtonText: '确定',
closeOnClickModal: false,
showClose: false,
callback: (action: Action) => {
logout();
},
@ -423,8 +357,8 @@ const getAssStatus = async () => {
}
};
//
const getCompetitionStatus = async () => {
//
let getCompetitionStatus = async () => {
//
if (!isSubmit.value) {
const { competition } = await getCompetition(param.competitionId);
@ -435,13 +369,15 @@ const getCompetitionStatus = async () => {
const now = await getNow();
//
if (now >= endTime) {
submit();
ElMessageBox.alert(`竞赛时间已到,系统已自动交卷`, '提示', {
confirmButtonText: '确定',
closeOnClickModal: false,
showClose: false,
callback: (action: Action) => {
logout();
},
});
submit();
} else {
//
countVal.value = (endTime - now) / 1000;
@ -450,49 +386,145 @@ const getCompetitionStatus = async () => {
}
}
};
//
const selectProject = () => {
//
let delCache = async () => {
await deleteOperationData({
cid: param.cid,
projectId: param.projectId,
assessmentId: param.assessmentId,
competitionId: param.competitionId,
});
};
//
let setNewProject = (reloadPage?: number) => {
Cookies.set('sand-projectId', param.projectId);
getProDetail();
setSubmit(false);
countVal.value = 0;
grade.value = '00';
pannelTab.value = 'first';
reload();
//
if (route.path === '/') {
location.reload();
getEntryTime();
if (reloadPage) {
//
if (route.path === '/') {
location.reload();
} else {
getLevel.value && getLevel.value();
}
}
};
//
const initBuiltInData = async () => {
await initData({
assessmentId: param.assessmentId,
cid: param.cid,
competitionId: param.competitionId,
projectId: param.projectId,
});
};
//
let getCache = async (reloadPage?: number) => {
initBuiltInData();
//
const res = await getSandTableLastCache({
cid: param.cid,
projectId: param.projectId,
assessmentId: param.assessmentId || '',
competitionId: param.competitionId || '',
});
//
if (res.getLastCache) {
ElMessageBox.confirm('是否要继续上次的操作记录?', '提示', {
confirmButtonText: '是',
cancelButtonText: '否',
type: 'success',
closeOnClickModal: false,
showClose: false,
})
.then(async () => {
// id
if (res.checkpointId) {
Cookies.set('sand-level', res.checkpointId);
}
setNewProject(reloadPage);
})
.catch(async () => {
Cookies.remove('sand-level');
setNewProject();
delCache();
//
if (reloadPage) {
if (route.path === '/') {
location.reload();
} else {
getLevel.value && getLevel.value();
}
}
});
} else {
getLevel.value && getLevel.value();
Cookies.remove('sand-level');
setNewProject(reloadPage);
}
};
let handleCache = () => {
//
if (!isSubmit.value) {
param.cid && getEntryTime();
visible.value && !Cookies.get('sand-loaded') && getCache(0); //
}
};
//
const toReport = () => {
router.push('/report');
router.replace('/report');
};
//
const reload = async () => {
await deleteCache(getIds());
reloadCount();
grade.value = '00';
setSubmit(false);
startCount();
router.push('/');
let reload = async () => {
if (!per.value) {
reloadCount();
startCount();
grade.value = '00';
pannelTab.value = 'first';
setSubmit(false);
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;
};
//
const submit = async () => {
if (isSubmit.value) return false;
ElMessageBox.confirm('此操作将视为结束考试,是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => {
submiting.value = true;
const date = new Date();
const timeSum = Math.ceil((date.getTime() - entryTime.value.getTime()) / 60000); //
const submitTime = dayjs(date).format('YYYY-MM-DD HH:mm:ss');
reloadCount();
let submit = async () => {
if (!submiting.value) {
submiting.value = true;
const checkpointId = Cookies.get('sand-level') ?? '';
const date = await getNow();
const timeSum = Math.ceil((date.getTime() - entryTime.value.getTime()) / 60000); //
const submitTime = dayjs(date).format('YYYY-MM-DD HH:mm:ss');
reloadCount();
try {
const { retMap } = await submitOpe({
classId: param.classId ? param.classId : '',
className: param.className ? param.className : '',
@ -501,7 +533,7 @@ const submit = async () => {
endTime: per.value ? param.stopTime : submitTime, //
submitTime, // 3
timeSum,
checkpointId: Cookies.get('sand-level') ?? '',
checkpointId,
projectId: param.projectId,
projectName: projectList.value.find((e) => e.projectId == param.projectId)?.projectName,
lcId: curReq.value,
@ -515,7 +547,6 @@ const submit = async () => {
});
setSubmit(true);
let score = 0;
//
taskList.value.map((e) => {
const item = retMap?.scoreInfo.find((n) => n.lcId === e.judgmentId);
@ -523,69 +554,93 @@ const submit = async () => {
if (item) {
e.examScore = item.questionScore;
e.finishedResult = item.calculate; // 12
score += item.questionScore; //
} else {
e.examScore = 0;
}
} catch (e) {}
});
grade.value = score < 10 ? '0' + score : score;
const score = retMap.totalScore;
grade.value = score < 10 && !(score % 1) ? `0${score}` : score;
reportId.value = retMap.reportId;
Cookies.set('sand-reportId', retMap.reportId);
Cookies.set('sand-score', grade.value);
localStorage.setItem('sand-taskList', JSON.stringify(taskList.value));
await deleteCache(getIds());
delCache();
submiting.value = false;
//
per.value &&
ElMessageBox.alert(
`提交成功${param.resultsDetails == 0 && param.resultAnnouncementTime != 0 ? ',成绩将在' + param.resultAnnouncementTime + '小时后发布,请去参赛信息模块查看' : ''}`,
'提示',
{
confirmButtonText: '确定',
callback: (action: Action) => {
logout();
},
if (per.value) {
const time = param.resultAnnouncementTime;
const msg =
time === '0' ? '提交成功!成绩将在比赛结束后公布,请前往参赛信息模块查看' : time > 0 ? `提交成功!成绩将在比赛结束后${time}小时公布,请前往参赛信息模块查看` : '提交成功';
ElMessageBox.alert(msg, '提示', {
confirmButtonText: '确定',
closeOnClickModal: false,
showClose: false,
callback: (action: Action) => {
logout();
},
);
})
});
}
} catch (e) {
submiting.value = false;
}
}
};
//
let confirmSubmit = () => {
if (isSubmit.value) return false;
if (!Cookies.get('sand-level')) return ElMessage.error('请选择关卡');
ElMessageBox.confirm('此操作将视为结束考试,是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
closeOnClickModal: false,
})
.then(submit)
.catch(() => {
submiting.value = false;
});
};
//
const getProDetail = async () => {
const res = await getProjectDetail({
projectId: param.projectId,
stuAssessent: 1,
});
const pointsList = res.projectJudgmentVos;
const project = res.projectManage;
Cookies.set('sand-projectId', param.projectId);
// /
if (per.value) {
projectList.value = [
{
projectId: param.projectId,
projectName: project.projectName,
},
];
}
curReq.value = pointsList.map((e) => e.judgmentId); // judgmentIditem
points.value = pointsList;
taskList.value = isSubmit.value ? JSON.parse(localStorage.getItem('sand-taskList')) : pointsList; //
judgmentId.value = pointsList[0].judgmentId; //
pd.value = project;
curSystemId.value = project.systemId;
hintOpen.value = project.founder ? !project.hintOpenBySchool : !project.hintOpen; // 01
const isPrac = per.value === 0; //
text.value = isPrac ? '已用' : '剩余';
//
if (!param.competitionId && !isSubmit.value) {
const now = await getNow();
countVal.value = (isPrac ? now - entryTime.value : new Date(param.stopTime).getTime() - now) / 1000; //
startCount();
let getProDetail = async () => {
loading.value = true;
try {
const res = await getProjectDetail({
projectId: param.projectId,
stuAssessent: 1,
});
const pointsList = res.projectJudgmentVos;
const project = res.projectManage;
Cookies.set('sand-projectId', param.projectId);
// /
if (per.value) {
projectList.value = [
{
projectId: param.projectId,
projectName: project.projectName,
},
];
}
curReq.value = pointsList.map((e) => e.judgmentId); // judgmentIditem
points.value = pointsList;
taskList.value = isSubmit.value ? JSON.parse(localStorage.getItem('sand-taskList')) : pointsList; //
grade.value = isSubmit.value ? Cookies.get('sand-score') : '00';
judgmentId.value = pointsList[0].judgmentId; //
pd.value = project;
curSystemId.value = project.systemId;
hintOpen.value = project.founder ? !project.hintOpenBySchool : !project.hintOpen; // 01
const isPrac = per.value === 0; //
text.value = isPrac ? '已用' : '剩余';
//
if (!param.competitionId && !isSubmit.value) {
const now = await getNow();
countVal.value = (isPrac ? now - entryTime.value : new Date(param.stopTime).getTime() - now) / 1000; //
startCount();
}
} finally {
loading.value = false;
}
};
@ -601,12 +656,6 @@ const getList = async () => {
if (!per.value && !param.projectId) param.projectId = projects[0]?.projectId ?? 0; //
getProDetail();
};
//
const getEntryTime = async () => {
let now = await getSumTime(); //
if (!now) now = await getNow();
entryTime.value = now;
};
// websocket
// socket
@ -623,9 +672,9 @@ const getMessage = (msg) => {
console.log(JSON.parse(msg.data));
const { content } = JSON.parse(msg.data);
// 1234-id
if (content == 1) {
if (content == 1 && per.value === 2) {
getCompetitionStatus();
} else if (content.includes('3-')) {
} else if (content.includes('3-') && per.value === 1) {
// 3-id
getAssStatus();
}
@ -646,41 +695,80 @@ const initSocket = () => {
// socket
socket.onmessage = getMessage;
};
onMounted(() => {
getLevel.value = inject('getLevel'); //
//
let setHeartbeatDetection = () => {
heartBeatTimer.value = setInterval(async () => {
await heartbeatDetection();
}, 58 * 1000);
};
//
const init = async () => {
console.log('init');
per.value = param.assessmentId ? 1 : param.competitionId ? 2 : 0;
param.cid && getEntryTime();
if (param.assessmentId) {
getAssList();
//
await getAssList();
handleCache();
initSocket();
setHeartbeatDetection();
} else if (param.competitionId) {
//
getCompetitionStatus();
handleCache();
initSocket();
setHeartbeatDetection();
} else {
//
param.cid && getList();
if (param.competitionId) {
getCompetitionStatus();
initSocket();
}
handleCache();
}
if (!Cookies.get('sand-loaded')) {
Cookies.set('sand-loaded', 1); //
} else if (per.value) {
// /
getProDetail();
}
};
onMounted(init);
onUnmounted(() => {
counter = null;
submit = null;
pannelToggle = null;
setHeartbeatDetection = null;
getProDetail = null;
getCache = null;
getAssList = null;
getAssStatus = null;
getCompetitionStatus = null;
confirmSubmit = null;
handleCache = null;
getSumTime = null;
getEntryTime = null;
reloadCount = null;
delCache = null;
setNewProject = null;
reload = null;
reloadConfirm = null;
startCount = null;
setSubmit = null;
clearInterval(counterTimer.value);
clearInterval(heartBeatTimer.value);
console.log('onUnmounted');
});
</script>
<style lang="scss" scoped>
.el-main {
width: 60%;
background-color: #fff;
color: #333;
padding: 0;
font-size: 16px;
margin: 0px 20px 10px 10px;
white-space: pre-wrap;
overflow: hidden;
@apply w-[60%] p-0 mr-5 mb-2 ml-2 text-[#333] text-base whitespace-pre-wrap bg-white overflow-hidden;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
height: auto !important;
.project {
display: inline-flex;
align-items: center;
@ -821,7 +909,7 @@ onMounted(() => {
font-size: 14px;
}
:deep(.select) {
@apply flex-1;
@apply flex-1 min-w-[180px];
.el-select__caret:before {
// content: '\e78f';
padding: 3px;
@ -836,7 +924,7 @@ onMounted(() => {
.el-input {
padding: 10px 0;
}
.el-input--suffix .el-input__inner {
.el-input--suffix .el-input__wrapper {
height: 40px !important;
padding-right: 50px;
margin-left: 15px;
@ -848,6 +936,7 @@ onMounted(() => {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
box-shadow: none;
}
}
.panel {
@ -894,4 +983,14 @@ onMounted(() => {
.ql-editor {
@apply text-sm;
}
@media (max-width: 1450px) {
.panel-header {
.actions {
z-index: 10;
position: absolute;
top: 70px;
right: 30px;
}
}
}
</style>

@ -1,59 +0,0 @@
<template>
<form class="flex">
<div class="space-y-1">
<div v-for="(name, index) in names" :key="name" class="flex">
<el-button :icon="index == 0 ? Plus : Minus" @click="handelRow(index)" :disabled="index <= 0 && remains.length <= 0" circle></el-button>
<el-select v-model="names[index]" @change="clearParams()" class="w-36">
<el-option v-for="item in data.filter((it) => it.name === names[index] || remains.includes(it))" :key="item.name" :label="item.label" :value="item.name"></el-option>
</el-select>
<query-input :inputs="inputs" :name="names[index]"></query-input>
</div>
</div>
<div>
<el-button-group class="ml-2">
<el-button native-type="submit" :icon="Search" @click.prevent="$emit('search')">{{ $t('search') }}</el-button>
<el-button :icon="Refresh" @click="$emit('reset')">{{ $t('reset') }}</el-button>
</el-button-group>
</div>
</form>
</template>
<script setup lang="ts">
import { defineEmits, useSlots, provide, computed, ref, toRefs } from 'vue';
import { Plus, Minus, Search, Refresh } from '@element-plus/icons-vue';
import QueryInput from './QueryInput.vue';
const props = defineProps({ params: { type: Object, required: true } });
const { params } = toRefs(props);
const slots = useSlots();
provide('params', params);
defineEmits({
search: null,
reset: null,
});
const data = ref<any[]>([]);
const inputs = ref<any[]>([]);
inputs.value = slots.default?.() ?? [];
data.value = inputs.value.map((item) => ({ label: item.props?.label, name: item.props?.name }));
const [first] = data.value;
const names = ref<string[]>([first.name]);
const remains = computed(() => data.value.filter((it) => !names.value.includes(it.name)));
const clearParams = () => {
Object.keys(params.value).forEach((key) => {
if (!names.value.includes(key) && names.value.findIndex((item) => item.split(',').includes(key)) === -1) {
delete params.value[key];
}
});
};
const handelRow = (index: number) => {
if (index === 0) {
const [item] = remains.value;
names.value[names.value.length] = item.name;
} else {
names.value.splice(index, 1);
clearParams();
}
};
</script>

@ -1,16 +0,0 @@
<script lang="ts">
import { defineComponent, computed, toRefs } from 'vue';
export default defineComponent({
name: 'QueryInput',
props: { inputs: { type: Array, required: true }, name: { type: String, required: true } },
setup(props) {
const { inputs, name } = toRefs(props);
const input = computed(() => inputs.value.find((item: any) => item.props.name === name.value));
return { input };
},
render() {
return this.input;
},
});
</script>

@ -1,64 +0,0 @@
<template>
<slot>
<div v-if="type === 'number'"
class="inline-block">
<el-input-number v-model="params[first]"
:placeholder="$t('begin.number')"
class="w-48"></el-input-number>
<el-input-number v-model="params[second]"
:placeholder="$t('end.number')"
class="w-48"></el-input-number>
</div>
<el-date-picker v-else-if="type === 'date'"
v-model="params[name]"
type="daterange"
:start-placeholder="$t('begin.date')"
:end-placeholder="$t('end.date')"
class="w-96"></el-date-picker>
<el-date-picker v-else-if="type === 'datetime'"
v-model="params[name]"
type="datetimerange"
:start-placeholder="$t('begin.date')"
:end-placeholder="$t('end.date')"
class="w-96">
</el-date-picker>
<!--
<div v-else-if="type === 'date'" class="inline-block">
<el-date-picker v-model="params[first]" type="date" :placeholder="$t('begin.date')" class="w-48"></el-date-picker>
<el-date-picker v-model="params[second]" type="date" :placeholder="$t('end.date')" class="w-48"></el-date-picker>
</div>
<div v-else-if="type === 'datetime'" class="inline-block">
<el-date-picker v-model="params[first]" type="datetime" class="w-48"></el-date-picker>
<el-date-picker v-model="params[second]" type="datetime" class="w-48"></el-date-picker>
</div>
-->
<el-select v-else-if="options"
v-model="params[name]"
multiple
class="w-96">
<el-option v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"></el-option>
</el-select>
<el-input v-else
v-model="params[name]"
class="w-96"></el-input>
</slot>
</template>
<script setup lang="ts">
import { inject, PropType, ref, toRefs } from 'vue';
const props = defineProps({
label: { type: String, required: true },
name: { type: String, required: true },
// 'string' | 'date' | 'datetime' | 'number'
type: { type: String },
options: { type: Object as PropType<Array<{ label: string; value: string | number }>> },
});
const params = inject<any>('params');
const { name } = toRefs(props);
const [firstName, secondName] = name.value.split(',');
const first = ref<string>(firstName);
const second = ref<string>(secondName);
</script>

@ -1,2 +0,0 @@
export { default as QueryForm } from './QueryForm.vue';
export { default as QueryItem } from './QueryItem.vue';

@ -1,12 +1,7 @@
<template>
<div class="search">
<input type="text"
placeholder="搜索"
maxlength="20"
v-model="val" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
<input type="text" placeholder="搜索" maxlength="20" v-model="val" />
<img src="@/assets/images/search.png" alt="" class="icon" />
</div>
</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,45 +0,0 @@
<script lang="ts">
import { computed, defineComponent, toRefs } from 'vue';
import { useI18n } from 'vue-i18n';
import { ColumnState, getColumnSettings, setColumnOrigins } from './useColumns';
export default defineComponent({
name: 'ColumnList',
props: { name: { type: String, required: true } },
setup(props, { slots }) {
const { name } = toRefs(props);
const { t } = useI18n();
const slotColumns = slots.default?.() ?? [];
//
const getColumnTitle = (columnProps: any) => {
// checkbox
if (columnProps?.type === 'selection') return t('table.selection');
return columnProps?.label;
};
// el-table-column
const origins: ColumnState[] = slotColumns.map((column) => ({ title: getColumnTitle(column.props), display: column.props?.display !== 'none' }));
setColumnOrigins(name.value, origins);
const settings = getColumnSettings(name.value);
const columns = computed(() =>
slotColumns
.filter((column) => {
const matched = settings.value.find((item) => getColumnTitle(column.props) === item.title);
return !matched || matched.display;
})
.map((column) => ({ ...column, key: getColumnTitle(column.props) }))
.sort((a, b) => {
let indexA = settings.value.findIndex((item) => item.title === getColumnTitle(a));
if (indexA < 0) indexA = slotColumns.findIndex((item) => getColumnTitle(item) === getColumnTitle(a));
let indexB = settings.value.findIndex((item) => item.title === getColumnTitle(b));
if (indexB < 0) indexB = slotColumns.findIndex((item) => getColumnTitle(item) === getColumnTitle(b));
return indexA - indexB;
}),
);
return { columns };
},
render() {
return this.columns;
},
});
</script>

@ -1,40 +0,0 @@
<template>
<el-dropdown class="align-middle"
trigger="click"
:hide-on-click="false">
<el-tooltip :content="$t('table.columnsSetting')"
placement="top">
<el-icon class="text-base">
<setting />
</el-icon>
</el-tooltip>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<el-button @click="resetColumns"
type="text">{{ $t('table.columnsReset') }}</el-button>
</el-dropdown-item>
<el-dropdown-item v-for="(column, index) in settings"
:key="column.title"
:divided="index === 0">
<el-checkbox v-model="column.display">{{ column.title }}</el-checkbox>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>
<script setup lang="ts">
import { toRefs, watch } from 'vue';
import { Setting } from '@element-plus/icons-vue';
import { getColumnOrigins, getColumnSettings, mergeColumns, storeColumnSettings } from './useColumns';
const props = defineProps({ name: { type: String, required: true } });
const { name } = toRefs(props);
const settings = getColumnSettings(name.value);
const origins = getColumnOrigins(name.value);
watch(settings, () => storeColumnSettings(), { deep: true });
const resetColumns = () => {
settings.value = mergeColumns([], origins.value);
};
</script>

@ -1,2 +0,0 @@
export { default as ColumnSetting } from './ColumnSetting.vue';
export { default as ColumnList } from './ColumnList.vue';

@ -1,55 +0,0 @@
import { reactive, toRef } from 'vue';
export interface ColumnState {
title: string;
display: boolean;
}
const COLUMN_SETTINGS = 'ujcms_column_settings';
function fetchColumnSettings(): Record<string, ColumnState[]> {
const settings = localStorage.getItem(COLUMN_SETTINGS);
return settings ? JSON.parse(settings) : {};
}
const originStore: Record<string, ColumnState[]> = reactive({});
const settingStore: Record<string, ColumnState[]> = reactive(fetchColumnSettings());
export function storeColumnSettings() {
localStorage.setItem(COLUMN_SETTINGS, JSON.stringify(settingStore));
}
export const getColumnOrigins = (name: string) => {
if (!originStore[name]) originStore[name] = [];
return toRef(originStore, name);
};
export const mergeColumns = (settings: ColumnState[], origins: ColumnState[]) => {
// 去除不存在的列
for (let i = 0, len = settings.length; i < len; ) {
if (origins.findIndex((column) => column.title === settings[i].title) === -1) {
settings.splice(i, 1);
len -= 1;
} else {
i += 1;
}
}
// 增加未记录的列
origins.forEach((column) => {
if (settings.findIndex((item) => item.title === column.title) === -1) {
settings.push({ ...column });
}
});
return settings;
};
export const setColumnOrigins = (name: string, origins: ColumnState[]) => {
originStore[name] = origins;
if (!settingStore[name]) settingStore[name] = [];
const settings = settingStore[name];
mergeColumns(settings, origins);
};
export const getColumnSettings = (name: string) => {
if (!settingStore[name]) settingStore[name] = [];
return toRef(settingStore, name);
};
// export const setColumnSettings = (name: string, settings: ColumnState[]) => {
// settingStore[name] = settings;
// };

@ -1,13 +1,11 @@
<template>
<div>
<textarea :id="elementId"
ref="element"></textarea>
<textarea :id="elementId" ref="element"></textarea>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, toRefs, watch, onMounted, onBeforeUnmount, onActivated, onDeactivated, PropType } from 'vue';
import { useI18n } from 'vue-i18n';
import { getAuthHeaders } from '@/utils/auth';
import { imageUploadUrl } from '@/api/system';
@ -56,8 +54,8 @@ import 'tinymce/plugins/visualblocks';
import 'tinymce/plugins/visualchars';
// import 'tinymce/plugins/wordcount';
import { isTextarea, uuid, initEditor } from './utils';
import Oss from '@/components/AliOss/upload.ts';
import { isTextarea, uuid, initEditor } from './utils';
export default defineComponent({
name: 'Tinymce',
@ -78,7 +76,6 @@ export default defineComponent({
},
setup(props, ctx) {
const { disabled, modelValue } = toRefs(props);
const { t } = useI18n();
const element = ref<any>();
let vueEditor: any = null;
const elementId: string = props.id || uuid('tiny-vue');
@ -127,7 +124,7 @@ export default defineComponent({
images_upload_handler(blobInfo: any, success: any, failure: any, progress: any) {
const fileSizeLimitByte = 0;
if (fileSizeLimitByte > 0 && blobInfo.blob().size > fileSizeLimitByte) {
failure(t('error.fileMaxSize', { size: `${fileSizeLimitByte / 1024 / 1024}MB` }), { remove: true });
failure(`文件大小不能超过 ${`${fileSizeLimitByte / 1024 / 1024}MB`}`, { remove: true });
return;
}
@ -210,7 +207,7 @@ export default defineComponent({
const file = files?.item(0);
if (!file) return;
if (fileSizeLimtByte > 0 && file.size > fileSizeLimtByte) {
tinymce.activeEditor.windowManager.alert(t('error.fileMaxSize', { size: `${fileSizeLimtByte / 1024 / 1024}MB` }));
tinymce.activeEditor.windowManager.alert(`文件大小不能超过 ${`${fileSizeLimtByte / 1024 / 1024}MB`}`);
return;
}
const xhr = new XMLHttpRequest();

@ -1,118 +0,0 @@
<template>
<el-upload
:action="action"
:headers="{ ...getAuthHeaders(), ...getSiteHeaders() }"
:accept="accept"
:before-upload="beforeUpload"
:on-progress="(event, file) => (progressFile = file)"
:show-file-list="false"
:disabled="disabled"
:multiple="multiple"
>
<!--
//
action="https://jsonplaceholder.typicode.com/posts/"
-->
<el-button type="primary">{{ $t('clickToUpload') }}</el-button>
</el-upload>
<el-progress v-if="progressFile.status === 'uploading'" :percentage="parseInt(progressFile.percentage, 10)"></el-progress>
</template>
<script lang="ts">
import { defineComponent, onMounted, ref, toRefs, computed } from 'vue';
import { ElMessage } from 'element-plus';
import { useI18n } from 'vue-i18n';
import { getAuthHeaders } from '@/utils/auth';
import { getSiteHeaders } from '@/utils/common';
import { imageUploadUrl, videoUploadUrl, docUploadUrl, fileUploadUrl, queryGlobalSettings } from '@/api/config';
export default defineComponent({
name: 'BaseUpload',
props: {
type: {
type: String,
default: 'file',
validator: (value: string) => ['image', 'video', 'doc', 'file'].includes(value),
},
uploadAction: { type: String },
fileAccept: { type: String },
fileMaxSize: { type: Number },
multiple: { type: Boolean },
disabled: { type: Boolean, default: false },
'on-success': { type: Function },
},
setup(props) {
const { type, uploadAction, fileAccept, fileMaxSize } = toRefs(props);
const { t } = useI18n();
const progressFile = ref<any>({});
const global = ref<any>();
const fetchGlobalSettings = async () => {
global.value = await queryGlobalSettings();
};
onMounted(() => {
fetchGlobalSettings();
});
const action = computed(() => {
if (uploadAction?.value != null) {
return uploadAction.value;
}
switch (type.value) {
case 'image':
return imageUploadUrl;
case 'video':
return videoUploadUrl;
case 'doc':
return docUploadUrl;
case 'file':
return fileUploadUrl;
default:
throw new Error(`Type not support: ${type.value}`);
}
});
const accept = computed(() => {
if (fileAccept?.value != null) {
return fileAccept.value;
}
switch (type.value) {
case 'image':
return global?.value?.upload?.imageInputAccept ?? '.jpg,.jpeg,.png,.gif';
case 'video':
return global?.value?.upload?.videoInputAccept ?? '.mp4,.m3u8';
case 'doc':
return global?.value?.upload?.docInputAccept ?? '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx';
case 'file':
return global?.value?.upload?.fileInputAccept ?? '.zip,.7z,.gz,.bz2,.iso,.rar,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.jpg,.jpeg,.png,.gif,.mp4,.m3u8,.mp3,.ogg';
default:
throw new Error(`Type not support: ${type.value}`);
}
});
const maxSize = computed(() => {
if (fileMaxSize?.value != null) {
return fileMaxSize.value;
}
switch (type.value) {
case 'image':
return global?.value?.upload?.imageLimitByte ?? 0;
case 'video':
return global?.value?.upload?.videoLimitByte ?? 0;
case 'doc':
return global?.value?.upload?.docLimitByte ?? 0;
case 'file':
return global?.value?.upload?.fileLimitByte ?? 0;
default:
throw new Error(`Type not support: ${type.value}`);
}
});
const beforeUpload = (file: any) => {
if (maxSize.value > 0 && file.size > maxSize.value) {
ElMessage.error(t('error.fileMaxSize', { size: `${maxSize.value / 1024 / 1024}MB` }));
return false;
}
return true;
};
return { progressFile, getAuthHeaders, getSiteHeaders, action, accept, beforeUpload };
},
});
</script>
<style lang="scss" scoped></style>

@ -1,136 +0,0 @@
<template>
<div class="w-full">
<el-upload :action="fileUploadUrl"
:headers="{ ...getAuthHeaders(), ...getSiteHeaders() }"
:accept="accept"
:before-upload="beforeUpload"
:on-success="(res) => fileList.push({ name: res.name, url: res.url, length: res.size })"
:on-progress="(event, file) => (progressFile = file)"
:show-file-list="false"
multiple>
<!--
action="https://jsonplaceholder.typicode.com/posts/"
-->
<el-button type="primary">{{ $t('clickToUpload') }}</el-button>
</el-upload>
<el-progress v-if="progressFile.status === 'uploading'"
:percentage="parseInt(progressFile.percentage, 10)"></el-progress>
<transition-group tag="ul"
:class="['el-upload-list', 'el-upload-list--text', { 'is-disabled': disabled }]"
name="el-list">
<li v-for="file in fileList"
:key="file.url"
class="el-upload-list__item is-success">
<a class="el-upload-list__item-name"
@click="handlePreview(file)">
<el-icon class="el-icon--document">
<Document />
</el-icon>{{ file.name }}
</a>
<label class="el-upload-list__item-status-label">
<el-icon class="el-icon--upload-success el-icon--circle-check">
<CircleCheck />
</el-icon>
</label>
<el-icon v-if="!disabled"
class="el-icon--close"
@click="fileList.splice(fileList.indexOf(file), 1)">
<Close />
</el-icon>
</li>
</transition-group>
<el-dialog :title="$t('article.fileList.attribute')"
v-model="previewVisible"
top="5vh"
:width="768"
append-to-body>
<el-form ref="form"
:model="previewFile"
label-width="150px">
<el-form-item prop="name"
:label="$t('name')"
:rules="{ required: true, message: () => $t('v.required') }">
<el-input v-model="previewFile.name"
maxlength="100"></el-input>
</el-form-item>
<el-form-item prop="length"
:label="$t('size')"
:rules="{ required: true, message: () => $t('v.required') }">
<el-input v-model="previewFile.length"
maxlength="19">
<template #append>Byte</template>
</el-input>
</el-form-item>
<el-form-item prop="url"
label="URL"
:rules="{ required: true, message: () => $t('v.required') }">
<el-input v-model="previewFile.url"
maxlength="255"></el-input>
</el-form-item>
<el-button @click.prevent="handleSubmit()"
type="primary"
native-type="submit">{{ $t('submit') }}</el-button>
</el-form>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, toRefs, computed } from 'vue';
import { ElMessage } from 'element-plus';
import { Close, Document, CircleCheck } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
import { getAuthHeaders } from '@/utils/auth';
import { getSiteHeaders } from '@/utils/common';
import { fileUploadUrl, queryGlobalSettings } from '@/api/config';
const props = defineProps({
modelValue: { type: Array, default: () => [] },
fileAccept: { type: String },
fileMaxSize: { type: Number },
disabled: { type: Boolean, default: false },
});
const emit = defineEmits({ 'update:modelValue': null });
const { fileAccept, fileMaxSize } = toRefs(props);
const { t } = useI18n();
const { modelValue } = toRefs(props);
const progressFile = ref<any>({});
const fileList = computed({
get: (): any[] => modelValue.value,
set: (val) => emit('update:modelValue', val),
});
const previewVisible = ref<boolean>(false);
const previewFile = ref<any>({});
const form = ref<any>();
const handlePreview = (file: any) => {
previewFile.value = file;
previewVisible.value = true;
};
const handleSubmit = () => {
form.value.validate(async (valid: boolean) => {
if (!valid) return;
previewVisible.value = false;
});
};
const global = ref<any>();
const fetchGlobalSettings = async () => {
global.value = await queryGlobalSettings();
};
onMounted(() => {
fetchGlobalSettings();
});
const defaultAccept = '.zip,.7z,.gz,.bz2,.iso,.rar,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.jpg,.jpeg,.png,.gif,.mp4,.m3u8,.mp3,.ogg';
const accept = computed(() => fileAccept?.value ?? global?.value?.upload?.fileInputAccept ?? defaultAccept);
const maxSize = computed(() => fileMaxSize?.value ?? global?.value?.upload?.fileLimitByte ?? 0);
const beforeUpload = (file: any) => {
if (maxSize.value > 0 && file.size > maxSize.value) {
ElMessage.error(t('error.fileMaxSize', { size: `${maxSize.value / 1024 / 1024}MB` }));
return false;
}
return true;
};
</script>
<style lang="scss" scoped></style>

@ -1,84 +0,0 @@
<template>
<el-dialog :title="$t('imageCrop')" v-model="visible" @closed="destroyCropper()" top="5vh" :width="768" destroy-on-close append-to-body>
<div class="text-center">
<img ref="imgRef" @load="initCropper()" :src="src" alt="" class="inline" style="max-height:410px" />
</div>
<div class="text-right">
<el-button @click.prevent="handleSubmit()" type="primary" native-type="submit" class="mt-4">{{ $t('submit') }}</el-button>
</div>
</el-dialog>
</template>
<script lang="ts">
import { computed, defineComponent, ref, toRefs } from 'vue';
import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
import { cropImage } from '@/api/config';
export default defineComponent({
name: 'ImageCropper',
props: {
modelValue: { type: Boolean, required: true },
src: { type: String, default: null },
width: { type: Number },
height: { type: Number },
thumbnailWidth: { type: Number },
thumbnailHeight: { type: Number },
},
emits: { 'update:modelValue': null, success: null },
setup(props, { emit }) {
const { modelValue, src, width, height, thumbnailWidth, thumbnailHeight } = toRefs(props);
const visible = computed({
get: () => modelValue.value,
set: (val) => emit('update:modelValue', val),
});
const imgRef = ref<any>();
const cropper = ref<any>();
const cropParam = ref<any>({});
const initCropper = () => {
if (imgRef.value) {
cropper.value = new Cropper(imgRef.value, {
aspectRatio: width?.value && height?.value ? width.value / height.value : NaN,
autoCropArea: width?.value && height?.value ? 1 : 0.8,
viewMode: 1,
minCropBoxWidth: width?.value ?? 16,
minCropBoxHeight: height?.value ?? 16,
zoomable: false,
crop(event) {
cropParam.value.url = src.value;
cropParam.value.x = Math.floor(event.detail.x);
cropParam.value.y = Math.floor(event.detail.y);
cropParam.value.width = Math.floor(event.detail.width);
cropParam.value.height = Math.floor(event.detail.height);
cropParam.value.maxWidth = width?.value;
cropParam.value.maxHeight = height?.value;
cropParam.value.thumbnailWidth = thumbnailWidth?.value;
cropParam.value.thumbnailHeight = thumbnailHeight?.value;
},
});
}
};
const destroyCropper = () => {
if (cropper.value) {
cropper.value.destroy();
}
};
const handleSubmit = async () => {
visible.value = false;
emit('success', (await cropImage(cropParam.value)).url);
};
return { imgRef, visible, initCropper, destroyCropper, handleSubmit };
},
});
</script>
<style lang="scss" scoped>
/* Ensure the size of the image fit the container perfectly */
:deep(img) {
display: block;
/* This rule is very important, please don't ignore this */
max-width: 100%;
}
</style>

@ -1,157 +0,0 @@
<template>
<div>
<!-- <transition-group tag="ul" :class="['el-upload-list', 'el-upload-list--picture-card', { 'is-disabled': disabled }]" name="el-list"> -->
<ul :class="['el-upload-list', 'el-upload-list--picture-card', { 'is-disabled': disabled }]">
<li v-for="file in fileList"
:key="file.url"
class="el-upload-list__item is-success">
<div class="w-full h-full bg-gray-50 flex justify-center items-center">
<img class="max-w-full max-h-full block"
:src="file.url"
alt="" />
<div class="full-flex-center absolute rounded-md cursor-default bg-black bg-opacity-50 opacity-0 hover:opacity-100 space-x-4"
@click.stop>
<el-icon class="image-action"
@click="(cropperVisible = true), (currentFile = file)"
:title="$t('cropImage')">
<Crop />
</el-icon>
<el-icon class="image-action"
@click="handlePreview(file)"
:title="$t('previewImage')">
<View />
</el-icon>
<el-icon class="image-action"
@click="fileList.splice(fileList.indexOf(file), 1)"
:title="$t('deleteImage')">
<Delete />
</el-icon>
</div>
</div>
</li>
</ul>
<!-- </transition-group> -->
<el-upload :action="imageUploadUrl"
:headers="{ ...getAuthHeaders(), ...getSiteHeaders() }"
:data="getData()"
:accept="accept"
:before-upload="beforeUpload"
:on-success="(res, file) => fileList.push({ name: res.name, url: res.url })"
:on-progress="(event, file) => (progressFile = file)"
:show-file-list="false"
multiple
class="inline-block">
<el-progress v-if="progressFile.status === 'uploading'"
type="circle"
:percentage="parseInt(progressFile.percentage, 10)" />
<div v-else
class="el-upload--picture-card">
<el-icon>
<Plus />
</el-icon>
</div>
</el-upload>
<div>
<el-dialog v-model="previewVisible"
top="5vh"
:width="768">
<el-input v-model="previewFile.url"
maxlength="255">
<template #prepend>URL</template>
</el-input>
<el-input v-model="previewFile.description"
type="textarea"
:rows="2"
:placeholder="$t('article.imageList.description')"
class="mt-1"></el-input>
<img :src="previewFile.url"
alt=""
class="mt-1 border border-gray-300" />
</el-dialog>
</div>
<image-cropper v-model="cropperVisible"
:src="currentFile.url"
:thumbnailWidth="thumbnailWidth"
:thumbnailHeight="thumbnailHeight"
@success="(url) => (currentFile.url = url)"></image-cropper>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, toRefs, computed } from 'vue';
import { ElMessage } from 'element-plus';
import { Plus, Crop, View, Delete } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
import { getAuthHeaders } from '@/utils/auth';
import { getSiteHeaders } from '@/utils/common';
import { imageUploadUrl, queryGlobalSettings } from '@/api/config';
import ImageCropper from './ImageCropper.vue';
const props = defineProps({
modelValue: { type: Array, default: () => [] },
fileAccept: { type: String },
fileMaxSize: { type: Number },
maxWidth: { type: Number },
maxHeight: { type: Number },
disabled: { type: Boolean, default: false },
});
const emit = defineEmits({ 'update:modelValue': null });
const { modelValue, maxWidth, maxHeight, fileAccept, fileMaxSize } = toRefs(props);
const { t } = useI18n();
const progressFile = ref<any>({});
const currentFile = ref<any>({});
const previewVisible = ref<boolean>(false);
const cropperVisible = ref<boolean>(false);
const previewFile = ref<any>({ src: 'data:;base64,=' });
const fileList = computed({
get: (): any => modelValue.value,
set: (val) => emit('update:modelValue', val),
});
const handlePreview = (file: any) => {
previewFile.value = file;
previewVisible.value = true;
};
const thumbnailWidth = 300;
const thumbnailHeight = 300;
const getData = () => {
const data: any = { isWatermark: true, thumbnailWidth, thumbnailHeight };
if (maxWidth?.value != null) {
data.maxWidth = maxWidth.value;
}
if (maxHeight?.value != null) {
data.maxHeight = maxHeight.value;
}
return data;
};
const global = ref<any>();
const fetchGlobalSettings = async () => {
global.value = await queryGlobalSettings();
};
onMounted(() => {
fetchGlobalSettings();
});
const defaultAccept = 'image/jpg,image/jpeg,image/png,image/gif';
const accept = computed(() => fileAccept?.value ?? global?.value?.upload?.imageInputAccept ?? defaultAccept);
const maxSize = computed(() => fileMaxSize?.value ?? global?.value?.upload?.imageLimitByte ?? 0);
const beforeUpload = (file: any) => {
if (maxSize.value > 0 && file.size > maxSize.value) {
ElMessage.error(t('error.fileMaxSize', { size: `${maxSize.value / 1024 / 1024}MB` }));
return false;
}
return true;
};
</script>
<style lang="scss" scoped>
:deep(.el-dialog__headerbtn) {
top: 4px;
}
.full-flex-center {
@apply w-full h-full flex justify-center items-center;
}
.image-action {
@apply cursor-pointer text-xl text-white;
}
</style>

@ -1,149 +0,0 @@
<template>
<el-upload :action="imageUploadUrl"
:headers="{ ...getAuthHeaders(), ...getSiteHeaders() }"
:accept="accept"
:before-upload="beforeUpload"
:data="data"
:show-file-list="false"
:on-success="(res) => ((src = res.url), (cropperVisible = mode === 'manual'))"
:on-progress="(event, file) => (progressFile = file)">
<!--
//
action="https://jsonplaceholder.typicode.com/posts/"
-->
<div v-if="src"
class="full-flex-center rounded-border relative hover:border-opacity-0">
<img :src="src"
class="max-w-full max-h-full block" />
<div class="full-flex-center absolute rounded-md cursor-default bg-black bg-opacity-50 opacity-0 hover:opacity-100 space-x-4"
@click.stop>
<el-icon class="image-action"
@click="cropperVisible = true"
:title="$t('cropImage')">
<Crop />
</el-icon>
<el-icon class="image-action"
@click="previewVisible = true"
:title="$t('previewImage')">
<View />
</el-icon>
<el-icon class="image-action"
@click="src = undefined"
:title="$t('deleteImage')">
<Delete />
</el-icon>
</div>
</div>
<el-progress v-else-if="progressFile.status === 'uploading'"
type="circle"
:percentage="parseInt(progressFile.percentage, 10)" />
<div v-else
class="el-upload--picture-card">
<el-icon>
<plus />
</el-icon>
</div>
</el-upload>
<div>
<el-dialog v-model="previewVisible"
top="5vh"
:width="768"
append-to-body
destroy-on-close>
<el-input v-model="src">
<template #prepend>URL</template>
</el-input>
<img :src="src"
alt=""
class="mt-1 border border-gray-300" />
</el-dialog>
</div>
<image-cropper v-model="cropperVisible"
:src="src"
:width="width"
:height="height"
@success="(url) => (src = url)"></image-cropper>
</template>
<script setup lang="ts">
import { computed, onMounted, ref, toRefs } from 'vue';
import { ElMessage } from 'element-plus';
import { Plus, Crop, View, Delete } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
import { getAuthHeaders } from '@/utils/auth';
import { getSiteHeaders } from '@/utils/common';
import { imageUploadUrl, queryGlobalSettings } from '@/api/config';
import ImageCropper from './ImageCropper.vue';
// 'image/jpg,image/jpeg,image/png,image/gif'
const props = defineProps({
modelValue: { type: String, default: null },
fileAccept: { type: String },
fileMaxSize: { type: Number },
width: { type: Number },
height: { type: Number },
mode: { type: String, default: 'none' },
});
const emit = defineEmits({ 'update:modelValue': null });
const { modelValue, width, height, mode, fileAccept, fileMaxSize } = toRefs(props);
const { t } = useI18n();
const progressFile = ref<any>({});
const previewVisible = ref<boolean>(false);
const cropperVisible = ref<boolean>(false);
const src = computed({
get: (): string | undefined => modelValue.value,
set: (val: string | undefined) => emit('update:modelValue', val),
});
const resizable = computed(() => ['cut', 'resize'].includes(mode.value));
const data = computed(() => {
const params: any = { resizeMode: mode.value === 'cut' ? 'cut' : 'normal' };
if (width?.value != null) {
// 0
params.maxWidth = resizable.value ? width.value : 0;
}
if (height?.value != null) {
// 0
params.maxHeight = resizable.value ? height.value : 0;
}
return params;
});
const global = ref<any>();
const fetchGlobalSettings = async () => {
global.value = await queryGlobalSettings();
};
onMounted(() => {
fetchGlobalSettings();
});
const accept = computed(() => fileAccept?.value ?? global?.value?.upload?.imageInputAccept ?? 'image/jpg,image/jpeg,image/png,image/gif');
const maxSize = computed(() => fileMaxSize?.value ?? global?.value?.upload?.imageLimitByte ?? 0);
const beforeUpload = (file: any) => {
if (maxSize.value > 0 && file.size > maxSize.value) {
ElMessage.error(t('error.fileMaxSize', { size: `${maxSize.value / 1024 / 1024}MB` }));
return false;
}
return true;
};
</script>
<style lang="scss" scoped>
:deep(.el-dialog__headerbtn) {
top: 4px;
}
:deep(.el-upload) {
width: 148px;
height: 148px;
}
.full-flex-center {
@apply w-full h-full flex justify-center items-center;
}
.rounded-border {
border: 1px solid #c0ccda;
@apply rounded-md bg-gray-50;
}
.image-action {
@apply cursor-pointer text-xl text-white;
}
</style>

@ -1,4 +0,0 @@
export { default as ImageUpload } from './ImageUpload.vue';
export { default as ImageListUpload } from './ImageListUpload.vue';
export { default as FileListUpload } from './FileListUpload.vue';
export { default as BaseUpload } from './BaseUpload.vue';

@ -1,335 +0,0 @@
import i18n from '@/i18n';
export function getPermsTreeData(): any[] {
const {
global: { t },
} = i18n;
return [
{
label: t('menu.home'),
key: 'home',
perms: ['auth'],
children: [
{
label: t('menu.personal'),
key: 'personal',
children: [
{
label: t('menu.personal.password'),
key: 'password:update',
perms: ['password:update'],
},
],
},
{
label: t('menu.content'),
key: 'content',
children: [
{
label: t('menu.content.article'),
key: 'article',
perms: ['article:page', 'article:list', 'channel:list', 'dict:list', 'model:list'],
children: [
{ label: t('list'), key: 'article:page' },
{ label: t('add'), key: 'article:create', perms: ['article:create'] },
{ label: t('edit'), key: 'article:update', perms: ['article:update', 'article:show'] },
{ label: t('delete'), key: 'article:delete', perms: ['article:delete'] },
],
},
{
label: t('menu.content.channel'),
key: 'channel',
perms: ['channel:page', 'channel:list'],
children: [
{ label: t('list'), key: 'channel:page' },
{ label: t('add'), key: 'channel:create', perms: ['channel:create'] },
{ label: t('edit'), key: 'channel:update', perms: ['channel:update', 'channel:show'] },
{ label: t('delete'), key: 'channel:delete', perms: ['channel:delete'] },
],
},
{
label: t('menu.content.blockItem'),
key: 'blockItem',
perms: ['blockItem:page', 'blockItem:list', 'block:list'],
children: [
{ label: t('list'), key: 'blockItem:page' },
{ label: t('add'), key: 'blockItem:create', perms: ['blockItem:create'] },
{ label: t('edit'), key: 'blockItem:update', perms: ['blockItem:update', 'blockItem:show'] },
{ label: t('delete'), key: 'blockItem:delete', perms: ['blockItem:delete'] },
],
},
{
label: t('menu.content.attachment'),
key: 'attachment',
perms: ['attachment:page', 'attachment:list'],
children: [
{ label: t('list'), key: 'attachment:page' },
{ label: t('add'), key: 'attachment:create', perms: ['attachment:create'] },
{ label: t('edit'), key: 'attachment:update', perms: ['attachment:update', 'attachment:show'] },
{ label: t('delete'), key: 'attachment:delete', perms: ['attachment:delete'] },
],
},
{
label: t('menu.content.generator'),
key: 'generator',
perms: ['generator:show', 'siteSettings:html:show', 'task:list', 'task:show', 'task:delete'],
children: [
{ label: t('generator.op.fulltext.reindexAll'), key: 'generator:fulltext:reindexAll', perms: ['generator:fulltext:reindexAll'] },
{ label: t('generator.op.fulltext.reindexSite'), key: 'generator:fulltext:reindexSite', perms: ['generator:fulltext:reindexSite'] },
{ label: t('generator.html'), key: 'generator:html', perms: ['generator:html'] },
{ label: t('site.settings.html'), key: 'siteSettings:html:update', perms: ['siteSettings:html:update', 'generator:html'] },
],
},
],
},
{
label: t('menu.config'),
key: 'config',
children: [
{
label: t('menu.config.globalSettings'),
key: 'globalSettings',
perms: ['globalSettings:show'],
children: [
{ label: t('global.settings.base'), key: 'globalSettings:base:update', perms: ['globalSettings:base:update'] },
{ label: t('global.settings.upload'), key: 'globalSettings:upload:update', perms: ['globalSettings:upload:update'] },
{ label: t('global.settings.customs'), key: 'globalSettings:customs:update', perms: ['globalSettings:customs:update'] },
],
},
{
label: t('menu.config.siteSettings'),
key: 'siteSettings',
perms: ['siteSettings:show'],
children: [
{ label: t('site.settings.base'), key: 'siteSettings:base:update', perms: ['siteSettings:base:update'] },
{ label: t('site.settings.watermark'), key: 'siteSettings:watermark:update', perms: ['siteSettings:watermark:update'] },
{ label: t('site.settings.customs'), key: 'siteSettings:customs:update', perms: ['siteSettings:customs:update'] },
],
},
{
label: t('menu.config.model'),
key: 'model',
perms: ['model:page', 'model:list'],
children: [
{ label: t('list'), key: 'model:page' },
{ label: t('add'), key: 'model:create', perms: ['model:create'] },
{ label: t('edit'), key: 'model:update', perms: ['model:update', 'model:show'] },
{ label: t('delete'), key: 'model:delete', perms: ['model:delete'] },
],
},
{
label: t('menu.config.block'),
key: 'block',
perms: ['block:page', 'block:list'],
children: [
{ label: t('list'), key: 'block:page' },
{ label: t('add'), key: 'block:create', perms: ['block:create'] },
{ label: t('edit'), key: 'block:update', perms: ['block:update', 'block:show'] },
{ label: t('delete'), key: 'block:delete', perms: ['block:delete'] },
],
},
{
label: t('menu.config.dictType'),
key: 'dictType',
perms: ['dictType:page', 'dictType:list'],
children: [
{ label: t('list'), key: 'dictType:page' },
{ label: t('add'), key: 'dictType:create', perms: ['dictType:create'] },
{ label: t('edit'), key: 'dictType:update', perms: ['dictType:update', 'dictType:show'] },
{ label: t('delete'), key: 'dictType:delete', perms: ['dictType:delete'] },
],
},
{
label: t('menu.config.dict'),
key: 'dict',
perms: ['dict:page', 'dict:list', 'dictType:list'],
children: [
{ label: t('list'), key: 'dict:page' },
{ label: t('add'), key: 'dict:create', perms: ['dict:create'] },
{ label: t('edit'), key: 'dict:update', perms: ['dict:update', 'dict:show'] },
{ label: t('delete'), key: 'dict:delete', perms: ['dict:delete'] },
],
},
],
},
{
label: t('menu.user'),
key: 'user',
children: [
{
label: t('menu.user.user'),
key: 'user',
perms: ['user:page', 'user:list', 'group:list', 'org:list'],
children: [
{ label: t('list'), key: 'user:page' },
{ label: t('add'), key: 'user:create', perms: ['user:create'] },
{ label: t('edit'), key: 'user:update', perms: ['user:update', 'user:show'] },
{ label: t('delete'), key: 'user:delete', perms: ['user:delete'] },
],
},
{
label: t('menu.user.role'),
key: 'role',
perms: ['role:page', 'role:list'],
children: [
{ label: t('list'), key: 'role:page' },
{ label: t('add'), key: 'role:create', perms: ['role:create'] },
{ label: t('edit'), key: 'role:update', perms: ['role:update', 'role:show'] },
{ label: t('delete'), key: 'role:delete', perms: ['role:delete'] },
],
},
{
label: t('menu.user.group'),
key: 'group',
perms: ['group:page', 'group:list'],
children: [
{ label: t('list'), key: 'group:page' },
{ label: t('add'), key: 'group:create', perms: ['group:create'] },
{ label: t('edit'), key: 'group:update', perms: ['group:update', 'group:show'] },
{ label: t('delete'), key: 'group:delete', perms: ['group:delete'] },
],
},
{
// label: t('menu.user.org'),
key: 'org',
perms: ['org:page', 'org:list'],
children: [
{ label: t('list'), key: 'org:page' },
{ label: t('add'), key: 'org:create', perms: ['org:create'] },
{ label: t('edit'), key: 'org:update', perms: ['org:update', 'org:show'] },
{ label: t('delete'), key: 'org:delete', perms: ['org:delete'] },
],
},
],
},
{
label: t('menu.system'),
key: 'system',
children: [
{
// label: t('menu.system.site'),
key: 'site',
perms: ['site:page', 'site:list', 'org:list', 'model:list', 'storage:list'],
children: [
{ label: t('list'), key: 'site:page' },
{ label: t('add'), key: 'site:create', perms: ['site:create'] },
{ label: t('edit'), key: 'site:update', perms: ['site:update', 'site:show'] },
{ label: t('delete'), key: 'site:delete', perms: ['site:delete'] },
],
},
{
label: t('menu.system.storage'),
key: 'storage',
perms: ['storage:page', 'storage:list'],
children: [
{ label: t('list'), key: 'storage:page' },
{ label: t('add'), key: 'storage:create', perms: ['storage:create'] },
{ label: t('edit'), key: 'storage:update', perms: ['storage:update', 'storage:show'] },
{ label: t('delete'), key: 'storage:delete', perms: ['storage:delete'] },
],
},
// {
// label: t('menu.system.task'),
// key: 'task',
// perms: ['task:page', 'task:list'],
// children: [
// { label: t('list'), key: 'task:page' },
// { label: t('add'), key: 'task:create', perms: ['task:create'] },
// { label: t('edit'), key: 'task:update', perms: ['task:update', 'task:show'] },
// { label: t('delete'), key: 'task:delete', perms: ['task:delete'] },
// ],
// },
],
},
],
},
];
}
export function getModelData(): any {
return {
article: {
mains: [
{ code: 'title', must: true, show: true, double: false, required: true },
{ code: 'subtitle', must: false, show: false, double: false, required: false },
{ code: 'fullTitle', must: false, show: false, double: false, required: false },
{ code: 'linkUrl', must: false, show: true, double: false, required: false },
{ code: 'seoKeywords', must: false, show: false, double: false, required: false },
{ code: 'seoDescription', must: false, show: true, double: false, required: false },
{ code: 'author', must: false, show: false, double: true, required: false },
{ code: 'editor', must: false, show: false, double: true, required: false },
{ code: 'image', must: false, show: true, double: false, required: false, type: 'image', imageWidth: 300, imageHeight: 200, imageMode: 'manual' },
{ code: 'file', must: false, show: false, double: false, required: false },
{ code: 'video', must: false, show: false, double: false, required: false },
{ code: 'doc', must: false, show: false, double: false, required: false },
{ code: 'imageList', must: false, show: false, double: false, required: false, type: 'imageList', imageMaxWidth: 1920, imageMaxHeight: 1920 },
{ code: 'fileList', must: false, show: false, double: false, required: false },
{ code: 'text', must: false, show: true, double: false, required: true },
],
asides: [
{ code: 'channel', must: true, show: true, required: true },
{ code: 'org', must: false, show: true, required: true },
{ code: 'publishDate', must: true, show: true, required: true },
// { code: 'offlineDate', must: false, show: true, required: false },
{ code: 'source', must: false, show: true, required: false },
{ code: 'articleTemplate', must: false, show: true, required: false },
{ code: 'allowComment', must: false, show: true, required: true },
{ code: 'user', must: false, show: false, required: true },
{ code: 'created', must: false, show: false, required: true },
{ code: 'modifiedUser', must: false, show: false, required: false },
{ code: 'modified', must: false, show: false, required: false },
],
},
channel: {
mains: [
{ code: 'name', must: true, show: true, double: true, required: true },
{ code: 'alias', must: true, show: true, double: true, required: true },
{ code: 'linkUrl', must: true, show: true, double: false, required: true },
{ code: 'seoTitle', must: false, show: true, double: true, required: false },
{ code: 'seoKeywords', must: false, show: true, double: true, required: false },
{ code: 'seoDescription', must: false, show: true, double: false, required: false },
{ code: 'channelTemplate', must: false, show: true, double: true, required: true },
{ code: 'articleTemplate', must: false, show: true, double: true, required: true },
{ code: 'channelModel', must: true, show: true, double: true, required: true },
{ code: 'articleModel', must: true, show: true, double: true, required: true },
{ code: 'group', must: false, show: true, double: false, required: true },
{ code: 'nav', must: false, show: true, double: true, required: true },
{ code: 'allowComment', must: false, show: true, double: true, required: true },
{ code: 'allowContribute', must: false, show: true, double: true, required: true },
{ code: 'allowSearch', must: false, show: true, double: true, required: true },
{ code: 'text', must: false, show: false, double: false, required: false },
],
asides: [
{ code: 'type', must: true, show: true, required: true },
{ code: 'parent', must: true, show: true, required: false },
{ code: 'pageSize', must: true, show: true, required: true },
],
},
};
}
export function mergeModelFields(defaultFields: any[], s: string | null | undefined, type: string): any[] {
const fields = JSON.parse(s || '[]');
const defaults = defaultFields.map((item: any) => ({ ...item, label: `${type}.${item.code}` }));
// 去除默认字段中不存在的字段
fields.filter((field: any) => defaults.findIndex((item) => item.code === field.code) !== -1);
defaults.forEach((item) => {
const index = fields.findIndex((it: any) => it.code === item.code);
if (index !== -1) {
// 加上缺失属性,覆盖不可改属性
fields[index] = { ...item, ...fields[index], must: item.must, label: item.label, type: item.type };
} else {
// 加上没有的字段
fields.push(item);
}
});
return fields;
}
export function arr2obj(arr: any[]) {
const obj: Record<string, any> = {};
arr.forEach((item: any) => {
obj[item.code] = item;
});
return obj;
}

@ -1,31 +1,12 @@
<template>
<div class="width-[100%] flex justify-between items-center w-full py-6 px-5 overflow-hidden bg-transparent">
<logo :collapse="collapse" />
<div v-if="!hidePanel"
class="inline-flex items-center">
<el-tooltip effect="light"
content="退出实训"
placement="bottom">
<img class="mr-3 cursor-pointer"
src="@/assets/images/11.png"
alt=""
@click="logout" />
<div class="width-[100%] flex justify-between items-center w-full py-6 lg:py-4 px-5 overflow-hidden bg-transparent">
<logo />
<div v-if="!hidePanel" class="inline-flex items-center">
<el-tooltip effect="light" content="退出实训" placement="bottom">
<img class="mr-3 cursor-pointer" src="@/assets/images/11.png" alt="" @click="logout" />
</el-tooltip>
<el-tooltip effect="light"
content="返回关卡"
placement="bottom">
<img class="mr-3 cursor-pointer"
src="@/assets/images/2.png"
alt=""
@click="toLevel" />
</el-tooltip>
<el-tooltip effect="light"
content="返回选择角色"
placement="bottom">
<img class="cursor-pointer"
src="@/assets/images/4.png"
alt=""
@click="toRole" />
<el-tooltip effect="light" content="返回选择角色" placement="bottom">
<img class="cursor-pointer" src="@/assets/images/4.png" alt="" @click="toRole" />
</el-tooltip>
</div>
</div>
@ -35,7 +16,7 @@
import { ref, onMounted, computed } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import Settings from '@/settings';
import { currentUser, perm, logout } from '@/store/useCurrentUser';
import { logout } from '@/store/useCurrentUser';
import Cookies from 'js-cookie';
import Logo from './Logo.vue';

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

@ -1,125 +1,75 @@
<template>
<ul class="switch px-7">
<ul class="switch px-7 lg:px-2">
<!-- 产品经理 -->
<template v-if="role == 41">
<el-badge :value="num1">
<li :class="{ active: active == 1 }"
@click="toPage('/product/bank?type=0&i=1&role=41')">
<img class="icon"
src="@/assets/images/icon5.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon5-1.png"
alt="" />
<el-badge :value="productState.stat1">
<li :class="{ active: active == 1 }" @click="toPage('/product/bank?type=0&i=1&role=41')">
<img class="icon" src="@/assets/images/icon5.png" alt="" />
<img class="icon-1" src="@/assets/images/icon5-1.png" alt="" />
<p class="text">个人产品</p>
</li>
</el-badge>
<el-badge :value="num2">
<li :class="{ active: active == 2 }"
@click="toPage('/product/bank?type=1&i=2&role=41')">
<img class="icon"
src="@/assets/images/icon6.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon6-1.png"
alt="" />
<el-badge :value="productState.stat2">
<li :class="{ active: active == 2 }" @click="toPage('/product/bank?type=1&i=2&role=41')">
<img class="icon" src="@/assets/images/icon6.png" alt="" />
<img class="icon-1" src="@/assets/images/icon6-1.png" alt="" />
<p class="text">企业产品</p>
</li>
</el-badge>
</template>
<!-- 风控经理 -->
<template v-else-if="role == 42">
<el-badge :value="num1">
<li :class="{ active: active == 1 }"
@click="toPage('/product/bank?type=&i=1&role=42')">
<img class="icon"
src="@/assets/images/icon1.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon1-1.png"
alt="" />
<el-badge :value="productState.stat1">
<li :class="{ active: active == 1 }" @click="toPage('/product/bank?type=&i=1&role=42')">
<img class="icon" src="@/assets/images/icon1.png" alt="" />
<img class="icon-1" src="@/assets/images/icon1-1.png" alt="" />
<p class="text">产品风控配置</p>
</li>
</el-badge>
<li :class="{ active: active == 2 }"
@click="toPage('/product/strategy?i=2&role=42&id=150')">
<img class="icon"
src="@/assets/images/icon2.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon2-1.png"
alt="" />
<li :class="{ active: active == 2 }" @click="toPage('/product/strategy?i=2&role=42&id=150')">
<img class="icon" src="@/assets/images/icon2.png" alt="" />
<img class="icon-1" src="@/assets/images/icon2-1.png" alt="" />
<p class="text">贷前准入模型</p>
</li>
<li :class="{ active: active == 3 }"
@click="toPage('/product/interestRate/tab1?&i=3&role=42&id=772')">
<img class="icon"
src="@/assets/images/icon3.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon3-1.png"
alt="" />
<li :class="{ active: active == 3 }" @click="toPage('/product/interestRate?&i=3&role=42&id=772')">
<img class="icon" src="@/assets/images/icon3.png" alt="" />
<img class="icon-1" src="@/assets/images/icon3-1.png" alt="" />
<p class="text">利率定价模型</p>
</li>
<li :class="{ active: active == 4 }"
@click="toPage('/product/afterLoan?&i=4&role=42&id=1029')">
<img class="icon"
src="@/assets/images/icon4.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon4-1.png"
alt="" />
<li :class="{ active: active == 4 }" @click="toPage('/product/afterLoan?&i=4&role=42&id=1029')">
<img class="icon" src="@/assets/images/icon4.png" alt="" />
<img class="icon-1" src="@/assets/images/icon4-1.png" alt="" />
<p class="text">贷后管理模型</p>
</li>
</template>
<!-- 专家委员会 -->
<el-badge v-else-if="role == 43"
:value="num1">
<el-badge v-else-if="role == 43" :value="productState.stat1">
<li class="active">
<img class="icon-1"
src="@/assets/images/icon7-1.png"
alt="" />
<img class="icon-1" src="@/assets/images/icon7-1.png" alt="" />
<p class="text">审批产品</p>
</li>
</el-badge>
<!-- 保险 -->
<li v-else-if="route.path.includes('insurance')"
class="active">
<img class="icon-1"
src="@/assets/images/icon4-1.png"
alt="" />
<li v-else-if="route.path.includes('insurance')" class="active">
<img class="icon-1" src="@/assets/images/icon4-1.png" alt="" />
<p class="text">保险产品</p>
</li>
<!-- 基金 -->
<li v-else-if="route.path.includes('fund')"
class="active">
<img class="icon-1"
src="@/assets/images/icon3-1.png"
alt="" />
<li v-else-if="route.path.includes('fund')" class="active">
<img class="icon-1" src="@/assets/images/icon3-1.png" alt="" />
<p class="text">基金产品</p>
</li>
<!-- 配置 -->
<template v-else>
<li :class="{ active: route.path === '/config/index' }"
@click="toPage('/config/index')">
<img class="icon"
src="@/assets/images/icon4.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon4-1.png"
alt="" />
<li :class="{ active: route.path === '/config/index' }" @click="toPage('/config/index')">
<img class="icon" src="@/assets/images/icon4.png" alt="" />
<img class="icon-1" src="@/assets/images/icon4-1.png" alt="" />
<p class="text">参数配置</p>
</li>
<!-- 中台进来的才需要显示关卡配置 -->
<li v-if="isAdmin"
:class="{ active: route.path === '/config/level' }"
@click="toPage('/config/level')">
<img class="icon"
src="@/assets/images/icon1.png"
alt="" />
<img class="icon-1"
src="@/assets/images/icon1-1.png"
alt="" />
<li v-if="isAdmin" :class="{ active: route.path === '/config/level' }" @click="toPage('/config/level')">
<img class="icon" src="@/assets/images/icon1.png" alt="" />
<img class="icon-1" src="@/assets/images/icon1-1.png" alt="" />
<p class="text">关卡配置</p>
</li>
</template>
@ -130,85 +80,59 @@
import { onMounted, computed, ref } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import Cookies from 'js-cookie';
import { statistics } from '@/api/bank';
import { productState, getStat } from '@/store/useProduct';
const router = useRouter();
const route = useRoute();
const active = computed(() => route.query.i);
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 num1 = ref<number | string>('');
const num2 = ref<number>(0);
//
const toPage = (path: string) => {
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(() => {
const status = role.value === '41' ? 299 : role.value === '42' ? 295 : role.value === '43' ? 296 : ''; // (1- 2-3-4-5-
if (status) {
getNum(status, role.value === '41' ? 0 : '');
role.value === '41' && getNum(status, 1);
getStat(status, role.value === '41' ? 0 : '');
role.value === '41' && getStat(status, 1);
}
});
</script>
<style lang="scss" scoped>
.switch {
:deep(.el-badge) {
@apply w-full;
}
li {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 122px;
height: 102px;
margin-bottom: 20px;
background: #ffffff;
@apply flex flex-col justify-center items-center h-[102px] mb-5 bg-white rounded-[10px] cursor-pointer;
box-shadow: 0px 0px 8px 0px rgba(162, 199, 246, 0.16);
border-radius: 10px;
cursor: pointer;
&:hover,
&.active {
background: linear-gradient(-36deg, #3c65ff, #33d1ff);
box-shadow: 0px 6px 16px 0px rgba(96, 155, 255, 0.56);
.icon {
display: none;
@apply hidden;
}
.icon-1 {
display: inline-block;
@apply inline-block;
}
.text {
color: #fff;
@apply text-white;
}
}
}
img {
margin: 0 auto;
@apply mx-auto;
}
.icon-1 {
display: none;
@apply hidden;
}
.text {
margin-top: 10px;
font-family: MiSans;
font-weight: 600;
@apply mt-[10px] font-[MiSans] font-semibold text-base lg:text-sm;
}
}
</style>

@ -1,14 +1,11 @@
<template>
<div>
<el-scrollbar wrap-style="height: calc(100% - 85px)">
<div v-if="!isConfig"
class="avatar py-3 mx-auto mb-5 text-center">
<img class="mx-auto"
src="@/assets/images/6.png"
alt="" />
<p class="text-white text-md">{{ roleName }}</p>
<p class="my-2 text-white text-sm">产品部门</p>
<div class="flex justify-center items-center text-white text-xs">
<div v-if="!isConfig" class="avatar py-3 mx-auto mb-5 text-center">
<img class="mx-auto" src="@/assets/images/6.png" alt="" />
<p class="text-white text-base lg:text-sm">{{ roleName }}</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]">
虚拟时间{{ date }}
<!-- <img class="ml-2 cursor-pointer"
src="@/assets/images/date.png"
@ -19,22 +16,14 @@
<menus></menus>
</el-scrollbar>
<el-dialog v-model="dateVisible"
title="选择交易日期"
width="400px"
center>
<el-dialog v-model="dateVisible" title="选择交易日期" width="400px" center>
<div class="text-center">
<el-date-picker v-model="diaDate"
format="YYYY/MM/DD"
value-format="YYYY-MM-DD"
type="date" />
<el-date-picker v-model="diaDate" format="YYYY/MM/DD" value-format="YYYY-MM-DD" type="date" />
</div>
<template #footer>
<span class="flex justify-center">
<div class="dia-btn mr-3 cancel"
@click="dateVisible = false">取消</div>
<div class="dia-btn"
@click="submitDate">确定</div>
<div class="dia-btn cancel" @click="dateVisible = false">取消</div>
<div class="dia-btn" @click="submitDate">确定</div>
</span>
</template>
</el-dialog>
@ -44,13 +33,11 @@
<script setup lang="ts">
import { onMounted, ref, computed } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import Menus from './Menu.vue';
import Settings from '@/settings';
import { getOperationTime, saveOperationTime } from '@/api/config';
import { appState } from '@/store/useAppState';
import Cookies from 'js-cookie';
import dayjs from 'dayjs';
import { getNow } from '@/utils/common';
import Menus from './Menu.vue';
const router = useRouter();
const route = useRoute();
@ -60,13 +47,20 @@ const levelId = +Cookies.get('sand-level');
const date = ref<string>(dayjs(new Date()).format('YYYY-MM-DD'));
const diaDate = ref<string>(dayjs(new Date()).format('YYYY-M-D'));
const dateVisible = ref<boolean>(false);
const roleIds = {
41: '产品经理',
42: '风控经理',
43: '专家委员会',
};
const roleName = computed(() => {
if (route.query.role) {
return Settings.roleIds[+route.query.role];
} else if (route.path.includes('insurance')) {
return roleIds[+route.query.role];
}
if (route.path.includes('insurance')) {
return '保险产品经理';
} else if (route.path.includes('fund')) {
}
if (route.path.includes('fund')) {
return '基金产品经理';
}
});

@ -1,7 +1,7 @@
<template>
<div class="flex items-center justify-center overflow-hidden">
<router-link class="whitespace-nowrap text-center" to="/">
<h1 v-if="!collapse" class="ml-1 text-[22px] 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>
</div>
</template>
@ -12,12 +12,6 @@ import Settings from '@/settings';
export default defineComponent({
name: 'SidebarLogo',
props: {
collapse: {
type: Boolean,
required: true,
},
},
data() {
return {
title: Settings.title,

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

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

@ -37,7 +37,7 @@ export const routes: Array<RouteRecordRaw> = [
{ path: 'strategy', component: () => import('@/views/product/strategy/CardList.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: '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/:action', component: () => import('@/views/product/fund/CardList.vue'), meta: { title: '基金产品' } },
{ path: 'afterLoan', component: () => import('@/views/product/afterLoan/CardList.vue'), meta: { title: '贷后管理' } },

@ -1,15 +1,5 @@
export default {
title: import.meta.env.VITE_APP_TITLE || '金融产品设计及数字化营销沙盘',
showSettings: true,
/**
* @type {object}
* @description id
*/
roleIds: {
41: '产品经理',
42: '风控经理',
43: '专家委员会',
},
/**
* @type {array}
* @description

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

@ -1,8 +1,11 @@
import { reactive, readonly } from 'vue';
import { statistics } from '@/api/bank';
import Cookies from 'js-cookie';
export interface Product {
status?: Record<string, any>;
stat1?: number | string;
stat2?: number | string;
}
const state = reactive<Product>({
@ -33,9 +36,12 @@ const state = reactive<Product>({
name: '审批打回',
},
],
// 左侧菜单项的右上角badge统计
stat1: '',
stat2: '',
});
export const productState = readonly(state);
export const productState = state;
// 专家委员会产品进度(去除配置风控)
export const getExpertStatus = (): Record<string, any>[] => {
const newStatus = JSON.parse(JSON.stringify(state.status));
@ -46,3 +52,18 @@ export const getExpertStatus = (): Record<string, any>[] => {
export const getStatus = (id: number | string): string => {
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 || '';
}
};

@ -32,14 +32,14 @@
}
:deep(.el-form-item__label) {
@apply font-semibold text-sm leading-[32px] text-black;
@apply font-semibold text-sm lg:text-[12px] leading-[32px] text-black;
}
.field-name {
@apply mb-3 text-sm font-semibold leading-[32px] text-[#333];
@apply mb-3 text-sm lg:text-[12px] font-semibold leading-[32px] text-[#333];
}
.tips {
@apply text-sm text-[#686868];
@apply text-sm lg:text-xs text-[#686868];
}
.num-inputs {
@apply flex items-center;
@ -53,9 +53,27 @@
@apply ml-2.5 text-sm text-[#333];
}
}
.radio-wrap {
@apply flex items-center;
.label {
@apply mr-10 lg:text-xs;
}
.whether {
@apply mr-5 text-xs text-[#666];
}
.el-radio {
margin-right: 15px;
}
}
:deep(.el-input),
:deep(.el-textarea),
:deep(.el-radio__label),
:deep(.el-checkbox__label) {
@apply lg:text-xs;
}
}
.submit {
@apply py-[15px] px-[22px] mt-5 text-sm leading-none text-white bg-[#006bff] rounded-xl cursor-pointer;
@apply py-[15px] px-[22px] lg:py-[10px] lg:px-[15px] mt-5 text-sm lg:text-xs leading-none text-white bg-[#006bff] rounded-xl cursor-pointer;
&:hover {
@apply opacity-90;
}

@ -49,9 +49,7 @@ body {
// global css
.block {
@apply p-5;
@apply rounded-lg;
@apply bg-white;
@apply p-5 rounded-lg bg-white;
}
.inline-form .el-form-item {
@ -74,12 +72,12 @@ body {
.card-list {
.left {
@apply w-[241px] min-w-[241px] pr-5 py-4 border-r border-solid border-[#e9eff2];
@apply w-[241px] min-w-[241px] lg:w-[180px] lg:min-w-[180px] pr-5 py-4 border-r border-solid border-[#e9eff2];
}
.products {
@apply max-h-[calc(100vh-150px)] pr-1 overflow-auto;
li {
@apply relative p-5 pt-7 mb-5 rounded-[10px] cursor-pointer border border-solid border-[transparent] bg-[url('@/assets/images/10.png')] bg-[length:100%_100%] bg-no-repeat;
@apply relative p-5 pt-7 lg:p-4 mb-5 rounded-[10px] cursor-pointer border border-solid border-[transparent] bg-[url('@/assets/images/10.png')] bg-[length:100%_100%] bg-no-repeat;
&.active {
@apply border-[#519aff];
}
@ -88,32 +86,46 @@ body {
@apply absolute top-0 right-0;
}
h6 {
@apply text-[#14436b] font-semibold;
@apply text-[#14436b] font-semibold lg:text-[15px];
}
.type,
.status {
@apply my-[15px] text-sm text-[#333];
@apply my-[15px] lg:mt-2 text-sm lg:text-xs text-[#333];
}
.meta {
@apply mt-[15px] text-sm text-[#8798a9];
@apply mt-[15px] lg:mt-2 text-sm lg:text-xs text-[#8798a9];
}
}
.right {
@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 {
// @apply w-[calc(100vw-533px)] max-h-[calc(100vh-160px)] overflow-auto;
// }
.c-table {
@apply rounded-[10px];
th.el-table__cell {
@apply bg-[#F8FBFC];
}
th.el-table__cell > .cell {
@apply text-[#006BFF];
}
.el-input__inner {
.cell,
.el-input {
@apply lg:text-xs;
}
.el-input__wrapper {
@apply px-2;
}
}
@ -126,7 +138,7 @@ body {
}
.el-select {
@apply w-[170px];
.el-input__inner {
.el-input__wrapper {
@apply pl-[41px] rounded-[18px] border-[#dfe9f8];
}
}
@ -145,16 +157,21 @@ body {
}
}
.dia-btn {
padding: 11px 26px;
font-size: 14px;
line-height: 1;
color: #fff;
@apply py-[11px] px-[26px] text-sm leading-[1] text-white rounded-[18px] cursor-pointer;
background: linear-gradient(-36deg, #006bff, #2ab1ff);
border-radius: 18px;
cursor: pointer;
&.cancel {
font-size: 600;
color: #333;
@apply mr-3 font-semibold text-[#333];
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) {
body {
zoom: 0.9;
}
}

@ -3,9 +3,6 @@ import Cookies from 'js-cookie';
const SAND_ACCESS_TOKEN = 'sand-token';
export const getAccessToken = (): string | undefined => Cookies.get(SAND_ACCESS_TOKEN);
export const setAccessToken = (token: string): void => {
Cookies.set(SAND_ACCESS_TOKEN, token);
};
export const removeAccessToken = (): void => Cookies.remove(SAND_ACCESS_TOKEN);
export const removeParam = (): void => {
Cookies.remove('sand-classId');
@ -24,6 +21,7 @@ export const removeParam = (): void => {
Cookies.remove('sand-systemId');
Cookies.remove('sand-level');
Cookies.remove('sand-submit');
Cookies.remove('sand-loaded');
};
export const getAuthHeaders = (): any => {

@ -1,5 +1,6 @@
import Cookies from 'js-cookie';
import { getCurrentTime } from '@/api/system';
import { getTheCurrentUserName } from '@/api/config';
const UJCMS_LOCALE = 'ujcms-locale';
const UJCMS_SITE_ID = 'ujcms-site-id';
@ -236,6 +237,7 @@ export const getFileExt = (fileName: string): string => {
*/
export const getIds = (): Record<string, any> => {
return {
cid: +Cookies.get('sand-cid'),
checkpointId: +Cookies.get('sand-level') || '',
projectId: +Cookies.get('sand-projectId') || '',
assessmentId: +Cookies.get('sand-assessmentId') || '',
@ -252,3 +254,33 @@ export const getNow = (): Promise<any> => {
resolve(new Date(res.currentTime));
});
};
/**
*
*/
export const getUsername = async (): string => {
const res = await getTheCurrentUserName();
return res.userName;
};
export const whethers = [
{
id: 795,
name: '启用',
},
{
id: 796,
name: '不启用',
},
];
export const opt1 = [
{
id: 345,
name: '是',
},
{
id: 346,
name: '否',
},
];

@ -1,14 +1,10 @@
import defaultSettings from '@/settings';
import i18n from '@/i18n';
const { title } = defaultSettings;
export default function getPageTitle(pageTitle: string | undefined): string {
if (pageTitle) {
const {
global: { t },
} = i18n;
return `${t(pageTitle)} - ${title}`;
return `${pageTitle} - ${title}`;
}
return `${title}`;
}

@ -1,15 +1,13 @@
import { h } from 'vue';
import axios from 'axios';
import { ElMessageBox, ElMessage } from 'element-plus';
import { getAuthHeaders } from '@/utils/auth';
import i18n from '@/i18n';
import { logout } from '@/store/useCurrentUser';
const service = axios.create({
baseURL: import.meta.env.VITE_BASE_API,
timeout: 10000,
timeout: 60 * 1000,
});
let logouted = 0;
service.interceptors.request.use(
(config) => {
config.headers = { ...config.headers, ...getAuthHeaders() };
@ -20,12 +18,27 @@ service.interceptors.request.use(
service.interceptors.response.use(
(res) => {
const { message, status } = res.data;
const { message, status, code, msg } = res.data;
if (status) {
if (status === 200) {
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 {
return res;
}
@ -33,24 +46,18 @@ service.interceptors.response.use(
(e) => {
const {
response: {
data: { timestamp, message, path, error, exception, trace },
data: { message, error },
status,
},
} = e;
const {
global: { t },
} = i18n;
if (status === 401) {
ElMessageBox.confirm(t('confirmLogin'), { confirmButtonText: t('loginAgain'), type: 'warning' }).then(() => {
// 未登录
logout();
});
} else if (status === 403) {
ElMessageBox({
title: status,
message: h('div', null, [h('p', { class: 'text-lg' }, t('error.forbidden')), h('p', { class: 'mt-2' }, message)]),
});
} else {
logouted ||
ElMessageBox.alert('登录状态已过期,请重新登录', { confirmButtonText: '重新登录', type: 'warning', closeOnClickModal: false, showClose: false }).then(() => {
// 未登录
logout();
});
logouted = 1;
} else if (message) {
ElMessage.error(message);
}
return Promise.reject(error);

@ -2,9 +2,9 @@
<div class="h-full p-4 bg-gray-200">
<div class="p-4 rounded shadow bg-white">
<h1 class="font-bold text-3xl">403</h1>
<p class="mt-4">{{ message }}</p>
<p class="mt-4">对不起您没有该页面的访问权限</p>
<p class="mt-4">
<el-button type="primary" @click="handleLogout()" plain>{{ $t('logout') }}</el-button>
<el-button type="primary" @click="handleLogout()" plain>退出</el-button>
</p>
</div>
</div>
@ -13,20 +13,17 @@
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { logout } from '@/store/useCurrentUser';
export default defineComponent({
name: 'Page403',
setup() {
const { t } = useI18n();
const router = useRouter();
const message = ref(t('error.forbidden'));
const handleLogout = () => {
logout();
router.push('/login');
};
return { message, handleLogout };
return { handleLogout };
},
});
</script>

@ -2,15 +2,16 @@
<div class="wscn-http404-container">
<div class="wscn-http404">
<div class="pic-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 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__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 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" />
</div>
<div class="bullshit">
<div class="bullshit__oops">OOPS!</div>
<div class="bullshit__info">All rights reserved
<a style="color:#20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a>
<div class="bullshit__info">
All rights reserved
<a style="color: #20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a>
</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>
@ -34,8 +35,8 @@ export default defineComponent({
</script>
<style lang="scss" scoped>
.wscn-http404-container{
transform: translate(-50%,-50%);
.wscn-http404-container {
transform: translate(-50%, -50%);
position: absolute;
top: 40%;
left: 50%;

@ -2,64 +2,40 @@
<div class="flex justify-between items-center h-[64px] px-5 bg-white">
<h1>金融产品设计及数字化营销沙盘系统</h1>
<div class="inline-flex items-center">
<el-tooltip effect="light"
content="退出实训"
placement="bottom">
<img class="mr-3 cursor-pointer"
src="@/assets/images/11.png"
alt=""
@click="logout" />
<el-tooltip effect="light" content="退出实训" placement="bottom">
<img class="mr-3 cursor-pointer" src="@/assets/images/11.png" alt="" @click="logout" />
</el-tooltip>
</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"
id="wrap">
<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">
<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="absolute top-5 left-40 flex items-center cursor-pointer"
@click="getLevel(1)">
<img v-if="collected"
src="@/assets/images/level/7.png"
alt="" />
<img v-else
src="@/assets/images/level/6.png"
alt="" />
<div class="absolute top-5 left-40 flex items-center cursor-pointer" @click="getLevel(1)">
<img v-if="collected" 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>
</div>
</div>
<div class="relative mt-20">
<div v-for="(item, i) in levels"
:key="i"
:class="['item', { active: curLevel === item.checkpointId }]"
@click="selecLevel(item)">
<span class="num">LV.{{ item.serialNumber }}</span>
<div v-for="(item, i) in levels" :key="i" :class="['item', { active: curLevel === item.checkpointId, disabled: !item.enableOrNot }]" @click="selecLevel(item)">
<span class="num">LV.{{ i + 1 }}</span>
<div class="texts">
<h6>{{ numToChinese(item.serialNumber) }}</h6>
<h6>{{ numToChinese(i + 1) }}</h6>
<p class="des mul-ellipsis2">{{ item.customsPassName }}</p>
<img v-if="item.collect"
class="icon"
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)" />
<img v-if="item.collect" class="icon" 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 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>
<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 bottom-0 left-[50%] translate-x-[-50%] w-[64px] h-[64px] bg-[url('@/assets/images/level/arrow-down.png')]"
@click="move('down')"></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="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 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>
<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 bottom-0 left-[50%] translate-x-[-50%] w-[64px] h-[64px] bg-[url('@/assets/images/level/arrow-down.png')]" @click="move('down')"></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="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>
<Panel />
</template>
@ -90,19 +66,21 @@ const getLevel = async (only: any = '') => {
provide('getLevel', getLevel);
//
const selecLevel = (item: Record<string, any>) => {
curLevel.value = item.checkpointId;
if (item.enableOrNot) curLevel.value = item.checkpointId;
};
//
const collectItem = async (item: Record<string, any>) => {
if (item.collect) {
await cancelCollection(item.favoriteId);
} else {
await collect({
checkPointId: item.checkpointId,
projectId,
});
if (item.enableOrNot) {
if (item.collect) {
await cancelCollection(item.favoriteId);
} else {
await collect({
checkpointId: item.checkpointId,
projectId,
});
}
getLevel();
}
getLevel();
};
//
const toRole = () => {
@ -127,9 +105,7 @@ const move = (dir: string) => {
if (dir === 'up' || dir === 'down') param.top = el.scrollTop + (dir === 'up' ? -150 : 150);
el.scrollTo(param);
};
onMounted(() => {
getLevel();
});
onMounted(getLevel);
</script>
<style lang="scss" scoped>
@ -185,6 +161,9 @@ onMounted(() => {
-webkit-text-fill-color: #fff;
}
}
&.disabled {
@apply opacity-30 cursor-not-allowed;
}
&:nth-child(2) {
@apply top-[var(--line2)] left-[160px];
@ -411,3 +390,10 @@ onMounted(() => {
}
}
</style>
<style>
@media screen and (-webkit-min-device-pixel-ratio: 1.5), screen and (min-resolution: 144dpi) {
body {
zoom: 1;
}
}
</style>

@ -41,49 +41,50 @@
<p class="text">今日渠道订单</p>
</div>
</div>
<el-tooltip effect="light"
content="退出实训"
placement="bottom">
<img class="mr-3 cursor-pointer"
src="@/assets/images/11.png"
alt=""
@click="logout" />
<el-tooltip effect="light" content="退出实训" placement="bottom">
<img class="mr-3 cursor-pointer" src="@/assets/images/11.png" alt="" @click="logout" />
</el-tooltip>
<el-tooltip effect="light"
content="返回关卡"
placement="bottom">
<img class="mr-3 cursor-pointer"
src="@/assets/images/2.png"
alt=""
@click="toLevel" />
<el-tooltip effect="light" content="返回关卡" placement="bottom">
<img class="mr-3 cursor-pointer" src="@/assets/images/2.png" alt="" @click="toLevel" />
</el-tooltip>
</div>
</div>
<div class="relative h-[calc(100vh-64px)] overflow-hidden bg-[#e5eafe]">
<img class="w-full h-full"
src="@/assets/images/role/bg.png"
alt="">
<img class="w-full h-full" 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="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 }}
</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')]"
@click="selectRole(41)"></div>
<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(43)"></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')]"
@click="selectRole(42)"></div>
<div class="role bottom-[200px] left-[100px] xl:bottom-[150px] lg:bottom-[120px] lg1:bottom-[20px] bg-[url('@/assets/images/role/insurance.png')] hover:bg-[url('@/assets/images/role/insurance1.png')]"
@click="selectRole(275)"></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
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')]"
@click="selectRole(41)"
></div>
<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(43)"
></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')]"
@click="selectRole(42)"
></div>
<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(275)"
></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 class="fixed top-[80px] right-[80px]">
<div class="flex items-center h-[60px] px-4 rounded-tl-[20px] rounded-tr-[20px]"
@ -124,20 +125,14 @@
<Panel />
<el-dialog v-model="dateVisible"
title="选择交易日期"
width="400px"
center>
<el-dialog v-model="dateVisible" title="选择交易日期" width="400px" center>
<div class="text-center">
<el-date-picker v-model="diaDate"
type="date" />
<el-date-picker v-model="diaDate" type="date" />
</div>
<template #footer>
<span class="flex justify-center">
<div class="dia-btn mr-3 cancel"
@click="dateVisible = false">取消</div>
<div class="dia-btn"
@click="submitDate">确定</div>
<div class="dia-btn cancel" @click="dateVisible = false">取消</div>
<div class="dia-btn" @click="submitDate">确定</div>
</span>
</template>
</el-dialog>
@ -155,11 +150,8 @@ import dayjs from 'dayjs';
import { getNow } from '@/utils/common';
const router = useRouter();
const route = useRoute();
const projectId = +Cookies.get('sand-projectId');
const levelId = +Cookies.get('sand-level');
const collected = ref<boolean>(false);
const curLevel = ref<number | string>('');
const dateVisible = ref<boolean>(false);
const date = ref<string>(dayjs(new Date()).format('YYYY-MM-DD'));
const diaDate = ref<string>(dayjs(new Date()).format('YYYY-M-D'));
@ -228,11 +220,7 @@ const ranks = ref<Record<string, any>[]>([
money: '沙盘名称',
},
]);
//
const getLevel = async () => {
const { data } = await checkPointList(1);
levels.value = data;
};
//
const selectRole = (id: number) => {
let path = `/product/bank?type=0&i=1&role=${id}`;
@ -332,3 +320,11 @@ onMounted(async () => {
}
}
</style>
<style>
@media screen and (-webkit-min-device-pixel-ratio: 1.5), screen and (min-resolution: 144dpi) {
body {
zoom: 1;
}
}
</style>

@ -4,54 +4,37 @@
<dl>
<dt>担保方式</dt>
<div class="vals">
<dd v-for="(item, i) in methods"
:key="i"
:class="{ active: method === item.id }"
@click="filterClick(item, 'method')">{{ item.name }}</dd>
<dd v-for="(item, i) in methods" :key="i" :class="{ active: method === item.id }" @click="filterClick(item, 'method')">{{ item.name }}</dd>
</div>
</dl>
<dl>
<dt>产品进度</dt>
<div class="vals">
<dd v-for="(item, i) in methods"
:key="i"
:class="{ active: method === item.id }"
@click="filterClick(item, 'method')">{{ item.name }}</dd>
<dd v-for="(item, i) in methods" :key="i" :class="{ active: method === item.id }" @click="filterClick(item, 'method')">{{ item.name }}</dd>
</div>
</dl>
</div>
<div class="block mt-3">
<div class="search">
<input type="text"
placeholder="搜索"
maxlength="20" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
<input type="text" placeholder="搜索" maxlength="20" />
<img src="@/assets/images/search.png" alt="" class="icon" />
</div>
<el-table ref="table"
v-loading="loading"
:data="data"
@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 ref="table" v-loading="loading" :data="data" @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-pagination v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:total="total"
:page-sizes="pageSizes"
:layout="pageLayout"
@size-change="fetchData()"
@current-change="fetchData()"
small
background
class="px-3 py-2 justify-end"></el-pagination>
<el-pagination
v-model:currentPage="currentPage"
v-model:pageSize="pageSize"
:total="total"
:page-sizes="pageSizes"
:layout="pageLayout"
@size-change="fetchData()"
@current-change="fetchData()"
small
background
class="px-3 py-2 justify-end"
></el-pagination>
</div>
</div>
</template>
@ -60,13 +43,11 @@
import { computed, onMounted, ref } from 'vue';
import { ElMessage } from 'element-plus';
import { Search } from '@element-plus/icons-vue';
import { useI18n } from 'vue-i18n';
import dayjs from 'dayjs';
import { perm } from '@/store/useCurrentUser';
import { pageSizes, pageLayout, toParams, resetParams } from '@/utils/common';
import { deleteUser, queryUserPage } from '@/api/user';
const { t } = useI18n();
const params = ref<any>({});
const sort = ref<any>();
const currentPage = ref<number>(1);
@ -129,7 +110,6 @@ const handleEdit = (id: number) => {
const handleDelete = async (ids: number[]) => {
await deleteUser(ids);
fetchData();
ElMessage.success(t('success'));
};
const deletable = (bean: any) => bean.id > 1;
</script>

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

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

@ -1,24 +1,19 @@
<template>
<div class="max-h-[calc(100vh-290px)] overflow-auto">
<el-form ref="formRef"
label-width="100px"
label-suffix=":"
class="form"
status-icon>
<el-form ref="formRef" label-width="100px" label-suffix="" class="form" status-icon>
<h6 class="title">单个银行账户</h6>
<el-form-item label="收益计算">
<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>
</el-form-item>
<el-form-item label="银行资产">
<div class="flex-1">
<div class="flex items-center">
<span class="text">起始金额</span>
<el-input class="w-[140px] mx-2"
v-model="form[0].startingAmount"></el-input>
<el-input class="w-[140px] mx-2" v-model="form[0].startingAmount"></el-input>
<span class="text">万元</span>
</div>
<p class="text mt-4">银行账户金额 = 起始金额 + 累计收益</p>
@ -28,17 +23,16 @@
<h6 class="title">单个保险账户</h6>
<el-form-item label="收益计算">
<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>
</el-form-item>
<el-form-item label="保险资产">
<div class="flex-1">
<div class="flex items-center">
<span class="text">起始金额</span>
<el-input class="w-[140px] mx-2"
v-model="form[1].startingAmount"></el-input>
<el-input class="w-[140px] mx-2" v-model="form[1].startingAmount"></el-input>
<span class="text">万元</span>
</div>
<p class="text mt-4">保险账户金额 = 起始金额 + 累计收益</p>
@ -48,23 +42,22 @@
<h6 class="title">单个基金账户</h6>
<el-form-item label="冻结账户">
<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>
</el-form-item>
<el-form-item label="收益计算">
<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>
</el-form-item>
<el-form-item label="基金资产:">
<div class="flex-1">
<div class="flex items-center">
<span class="text">起始金额</span>
<el-input class="w-[140px] mx-2"
v-model="form[2].startingAmount"></el-input>
<el-input class="w-[140px] mx-2" v-model="form[2].startingAmount"></el-input>
<span class="text">万元</span>
</div>
<p class="text mt-4">基金账户金额 = 所有基金资产净值+起始金额 + 累计收益 - 购买渠道金额</p>
@ -74,8 +67,7 @@
</div>
<div class="flex justify-end">
<div class="submit"
@click="submit">保存修改</div>
<div class="submit" @click="submit">保存修改</div>
</div>
</template>

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

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

@ -5,77 +5,42 @@
<dl>
<dt>担保方式</dt>
<div class="vals">
<dd v-for="(item, i) in productTypes"
:key="i"
:class="{ active: params.productType === item.id }"
@click="filterClick(item, 'productType')">{{ item.name }}</dd>
<dd v-for="(item, i) in productTypes" :key="i" :class="{ active: params.productType === item.id }" @click="filterClick(item, 'productType')">{{ item.name }}</dd>
</div>
</dl>
<dl>
<dt>担保方式</dt>
<div class="vals">
<dd v-for="(item, i) in guarantees"
:key="i"
:class="{ active: params.guarantyStyleId === item.id }"
@click="filterClick(item, 'guarantyStyleId')">{{ item.name }}</dd>
<dd v-for="(item, i) in guarantees" :key="i" :class="{ active: params.guarantyStyleId === item.id }" @click="filterClick(item, 'guarantyStyleId')">{{ item.name }}</dd>
</div>
</dl>
<dl>
<dt>贷款期限</dt>
<div class="vals">
<dd v-for="(item, i) in times"
:key="i"
:class="{ active: params.loanPeriod === item.name }"
@click="filterClick(item, 'loanPeriod')">{{ item.name }}</dd>
<dd v-for="(item, i) in times" :key="i" :class="{ active: params.loanPeriod === item.name }" @click="filterClick(item, 'loanPeriod')">{{ item.name }}</dd>
</div>
</dl>
<dl>
<dt>贷款额度</dt>
<div class="vals">
<dd v-for="(item, i) in moneys"
:key="i"
:class="{ active: params.loanLimit === item.name }"
@click="filterClick(item, 'loanLimit')">{{ item.name }}</dd>
<dd v-for="(item, i) in moneys" :key="i" :class="{ active: params.loanLimit === item.name }" @click="filterClick(item, 'loanLimit')">{{ item.name }}</dd>
</div>
</dl>
</div>
<div class="block mt-3">
<div class="search mb-2">
<input type="text"
v-model="params.keyWord"
placeholder="搜索"
maxlength="20" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
<input type="text" v-model="params.keyWord" placeholder="搜索" maxlength="20" />
<img src="@/assets/images/search.png" alt="" class="icon" />
</div>
<el-table ref="table"
v-loading="loading"
:data="list">
<el-table-column prop="productName"
label="贷款名称"
min-width="110"></el-table-column>
<el-table-column prop="productTypeText"
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 ref="table" v-loading="loading" :data="list">
<el-table-column prop="productName" label="贷款名称" min-width="110"></el-table-column>
<el-table-column prop="productTypeText" 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"
label="操作"
width="100">
@ -85,27 +50,28 @@
@click="toDetail(row)">查看详情</el-button>
</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-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>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, reactive, watch } from 'vue';
import { pageSizes, pageLayout, toParams } from '@/utils/common';
import { pageSizes, pageLayout, toParams, getIds } from '@/utils/common';
import { getProcessInformationBasedOnRoles } from '@/api/judgment';
import { bankingProductMarketsList } from '@/api/finance';
import { useRouter, useRoute } from 'vue-router';
import Cookies from 'js-cookie';
const router = useRouter();
const route = useRoute();
@ -171,9 +137,8 @@ const moneys = ref<Record<string, any>[]>([
name: '>1000万',
},
]);
const projectId = +Cookies.get('sand-projectId');
const levelId = +Cookies.get('sand-level');
const params = reactive({
...getIds(),
createDateSort: '',
guarantyStyleId: '',
keyWord: '',
@ -181,8 +146,6 @@ const params = reactive({
status: '',
loanPeriod: '不限',
loanLimit: '不限',
checkPointId: levelId,
projectId,
});
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);

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

@ -5,77 +5,41 @@
<dl>
<dt>申购费率</dt>
<div class="vals">
<dd v-for="(item, i) in rates"
:key="i"
:class="{ active: params.subscriptionRate === item.name }"
@click="filterClick(item, 'subscriptionRate')">{{ item.name }}</dd>
<dd v-for="(item, i) in rates" :key="i" :class="{ active: params.subscriptionRate === item.id }" @click="filterClick(item, 'subscriptionRate')">{{ item.name }}</dd>
</div>
</dl>
<dl>
<dt>成立年限</dt>
<div class="vals">
<dd v-for="(item, i) in times"
:key="i"
:class="{ active: params.establishmentPeriod === item.name }"
@click="filterClick(item, 'establishmentPeriod')">{{ item.name }}</dd>
<dd v-for="(item, i) in times" :key="i" :class="{ active: params.establishmentPeriod === item.name }" @click="filterClick(item, 'establishmentPeriod')">
{{ item.name }}
</dd>
</div>
</dl>
<dl>
<dt>基金规模</dt>
<div class="vals">
<dd v-for="(item, i) in scales"
:key="i"
:class="{ active: params.fundraisingScale === item.name }"
@click="filterClick(item, 'fundraisingScale')">{{ item.name }}</dd>
<dd v-for="(item, i) in scales" :key="i" :class="{ active: params.fundraisingScale === item.name }" @click="filterClick(item, 'fundraisingScale')">{{ item.name }}</dd>
</div>
</dl>
</div>
<div class="block mt-3">
<div class="search mb-2">
<input type="text"
v-model="params.fundName"
placeholder="搜索"
maxlength="20" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
<input type="text" v-model="params.fundName" placeholder="搜索" maxlength="20" />
<img src="@/assets/images/search.png" alt="" class="icon" />
</div>
<el-table ref="table"
v-loading="loading"
:data="list">
<el-table-column prop="fundCode"
label="基金代码"
min-width="80"></el-table-column>
<el-table-column prop="fundName"
label="基金名称"
min-width="110"></el-table-column>
<el-table-column prop="dailyNetAssetValue"
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 ref="table" v-loading="loading" :data="list">
<el-table-column prop="fundCode" label="基金代码" min-width="80"></el-table-column>
<el-table-column prop="fundName" label="基金名称" min-width="110"></el-table-column>
<el-table-column prop="dailyNetAssetValue" 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"
label="操作"
width="100">
@ -85,16 +49,18 @@
@click="toDetail(row)">查看详情</el-button>
</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-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>
</div>
</div>
</template>
@ -102,7 +68,7 @@
<script setup lang="ts">
import { onMounted, ref, reactive, watch } from 'vue';
import { ElMessage } from 'element-plus';
import { pageSizes, pageLayout, toParams } from '@/utils/common';
import { pageSizes, pageLayout, toParams, getIds } from '@/utils/common';
import { fundProductMarketList } from '@/api/finance';
import { useRouter, useRoute } from 'vue-router';
import Cookies from 'js-cookie';
@ -112,12 +78,11 @@ const route = useRoute();
const projectId = +Cookies.get('sand-projectId');
const levelId = +Cookies.get('sand-level');
const params = reactive({
...getIds(),
establishmentPeriod: '不限',
fundraisingScale: '不限',
subscriptionRate: '不限',
fundName: '',
checkPointId: levelId,
projectId,
});
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);
@ -125,15 +90,19 @@ const total = ref<number>(0);
const table = ref<any>();
const rates = ref<Record<string, any>[]>([
{
id: '不限',
name: '不限',
},
{
id: 0,
name: '0',
},
{
id: 1,
name: '0-0.5%',
},
{
id: 2,
name: '>0.5%',
},
]);
@ -197,14 +166,9 @@ onMounted(() => {
watch([params, () => route.query], initList);
//
const filterClick = (item: Record<string, any>, key: string) => {
params[key] = item.name;
};
//
const toAdd = () => {
router.push({
path: `/product/fund/add`,
});
params[key] = item[key === 'subscriptionRate' ? 'id' : 'name'];
};
//
const toDetail = async (path: string, id: number) => {
router.push(`${path}?id=${id}&name=${params.fundName}`);

@ -5,71 +5,39 @@
<dl>
<dt>险种分类</dt>
<div class="vals">
<dd v-for="(item, i) in insuranceTypes"
:key="i"
:class="{ active: params.insuranceType === item.id }"
@click="filterClick(item, 'insuranceType')">{{ item.name }}</dd>
<dd v-for="(item, i) in insuranceTypes" :key="i" :class="{ active: params.insuranceType === item.id }" @click="filterClick(item, 'insuranceType')">{{ item.name }}</dd>
</div>
</dl>
<dl v-if="params.insuranceType !== 311">
<dt>承保年龄</dt>
<div class="vals">
<dd v-for="(item, i) in ages"
:key="i"
:class="{ active: params.coverageAge === item.id }"
@click="filterClick(item, 'coverageAge')">{{ item.id }}</dd>
<dd v-for="(item, i) in ages" :key="i" :class="{ active: params.coverageAge === item.id }" @click="filterClick(item, 'coverageAge')">{{ item.id }}</dd>
</div>
</dl>
<dl>
<dt>保险期限</dt>
<div class="vals">
<dd v-for="(item, i) in times"
:key="i"
:class="{ active: params.protectionPeriod === item.id }"
@click="filterClick(item, 'protectionPeriod')">{{ item.id }}</dd>
<dd v-for="(item, i) in times" :key="i" :class="{ active: params.protectionPeriod === item.id }" @click="filterClick(item, 'protectionPeriod')">{{ item.id }}</dd>
</div>
</dl>
</div>
<div class="block mt-3">
<div class="search mb-2">
<input type="text"
v-model="params.insuranceName"
placeholder="搜索"
maxlength="20" />
<img src="@/assets/images/search.png"
alt=""
class="icon" />
<input type="text" v-model="params.insuranceName" placeholder="搜索" maxlength="20" />
<img src="@/assets/images/search.png" alt="" class="icon" />
</div>
<el-table ref="table"
v-loading="loading"
:data="list">
<el-table-column prop="insuranceName"
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">
<el-table ref="table" v-loading="loading" :data="list">
<el-table-column prop="insuranceName" 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 }">
{{ row.minimumAge ? row.minimumAge + '-' + row.maximumAge + '周岁' : '-' }}
</template>
</el-table-column>
<el-table-column prop="insuranceDeadline"
label="保险期限"
min-width="80"></el-table-column>
<el-table-column prop="premiumAmount"
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="insuranceDeadline" label="保险期限" min-width="80"></el-table-column>
<el-table-column prop="premiumAmount" 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"
label="操作"
width="100">
@ -79,38 +47,36 @@
@click="toDetail(row)">查看详情</el-button>
</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-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>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, reactive, watch } from 'vue';
import { pageSizes, pageLayout, toParams } from '@/utils/common';
import { pageSizes, pageLayout, toParams, getIds } from '@/utils/common';
import { insuranceMarketList } from '@/api/finance';
import { useRouter, useRoute } from 'vue-router';
import Cookies from 'js-cookie';
const router = useRouter();
const route = useRoute();
const projectId = +Cookies.get('sand-projectId');
const levelId = +Cookies.get('sand-level');
const params = reactive({
...getIds(),
insuranceName: '',
insuranceType: '',
coverageAge: '不限',
protectionPeriod: '不限',
checkPointId: levelId,
projectId,
});
const currentPage = ref<number>(1);
const pageSize = ref<number>(10);

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

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

@ -1,174 +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({
checkpointId: levelId,
projectId,
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(levelId, projectId);
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) => {
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,187 +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 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(1030);
const result = [];
process.map((e, i) => {
const cur = info.value.length ? info.value[i] : {};
let temp = {
checkpointId: levelId,
projectId,
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(levelId, projectId);
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>) => {
const preIds = `1,${Cookies.get('sand-level')},42,69,1030`; // 1id
const rule = [];
data.forEach((e, i) => {
rule.push(handleId(1052, '', '', preIds + ',' + e.stRecordId + ',1052', ''), handleId(1053, 282, e.checkObject, preIds + ',' + e.stRecordId + ',1053', 1));
i !== 4 && 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,347 +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 === 13">
<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 === 17">当前尚未偿还的贷款总额</template>
<template v-if="$index === 20">
平均额度使用率 =
<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 === 24">
最大用信率 =
<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 === 28">到目前为止使用额度的次数</template>
<template v-if="$index === 32">到目前为止客户可以使用的最大额度</template>
<template v-if="$index === 37">客户贷记卡已经逾期的总月数</template>
<template v-if="$index === 39">客户在行所有贷款已经逾期的总月数</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 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(1031);
const result = [
{
recordName: '基准分',
},
];
process.map((e, i) => {
let temp = {
checkpointId: levelId,
projectId,
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(levelId, projectId);
info.value = data;
getConfig();
} finally {
}
};
interface SpanMethodProps {
row: Record<string, any>;
column: TableColumnCtx<Record<string, any>>;
rowIndex: number;
columnIndex: number;
}
const rowMerge1 = [1, 32];
const rowMerge2 = [6, 17];
const rowMerge3 = [9, 13, 20, 24, 28];
const rowMerge4 = [37, 39];
//
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 === 20 || i === 24) {
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[13].formulaOne && rule.push(handleId(1083, 291, data[13].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>

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

Loading…
Cancel
Save