1 合并feature/dir分支代码

2 合并bpic/feature-ai-uw
3 注释加密解密内容
This commit is contained in:
wu.jifen
2025-09-01 16:34:59 +08:00
78 changed files with 13716 additions and 207 deletions

2
.env
View File

@@ -3,5 +3,5 @@ NODE_ENV = 'dev' // 如果是生产环境请记得切换为production
# flag
VUE_APP_FLAG='dev'
VUE_APP_ADMIN='http://39.104.123.254:7195'
VUE_APP_ADMIN='http://39.104.123.254:7196'
VUE_APP_DOCS='http://39.104.123.254:7546/'

7
.env.dat Normal file
View File

@@ -0,0 +1,7 @@
# env
NODE_ENV = 'dev' // 如果是生产环境请记得切换为production
# flag
VUE_APP_FLAG='dev'
VUE_APP_ADMIN='http://10.1.20.39:7537/api'
VUE_APP_DOCS='http://39.104.123.254:7546/'

View File

@@ -6,3 +6,4 @@ VUE_APP_FLAG='dev'
VUE_APP_ADMIN='http://39.104.123.254:7198'
VUE_APP_STATIC='http://39.104.123.254:7536/'

9
.env.prd Normal file
View File

@@ -0,0 +1,9 @@
# env
NODE_ENV = 'prd' // 如果是生产环境请记得切换为production
# flag
VUE_APP_FLAG='prd'
VUE_APP_ADMIN='http://39.104.123.254:7196'
VUE_APP_STATIC='http://39.104.123.254:7536/'

View File

@@ -7,7 +7,10 @@
"serve": "NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
"build": "vue-cli-service build",
"build:dev": "vue-cli-service build --mode dev",
"build:prd": "vue-cli-service build --mode prd",
"build:dat": "vue-cli-service build --mode dat",
"dev": "vue-cli-service serve --mode dev",
"dat": "vue-cli-service serve --mode dat",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"lint:fix": "eslint --fix --ext .js,.vue src",
@@ -19,6 +22,7 @@
"dependencies": {
"alova": "^3.2.10",
"axios": "0.18.1",
"compression-webpack-plugin": "^6.1.2",
"cropperjs": "^2.0.0",
"crypto-js": "^4.0.0",
"crypto.js": "^2.0.2",
@@ -31,10 +35,13 @@
"markdown-it": "^14.1.0",
"markdown-it-katex": "^2.0.3",
"mavon-editor": "^2.9.1",
"monaco-editor": "^0.30.0",
"monaco-editor-webpack-plugin": "^6.0.0",
"node-gyp": "^8.0.0",
"normalize.css": "7.0.0",
"nprogress": "0.2.0",
"path-to-regexp": "2.4.0",
"sm-crypto": "^0.3.13",
"sortablejs": "^1.14.0",
"swiper": "^5.4.5",
"v-emoji-picker": "^2.3.3",
@@ -46,6 +53,7 @@
},
"devDependencies": {
"@babel/core": "7.0.0",
"@babel/preset-env": "^7.28.0",
"@babel/register": "7.0.0",
"@vue/cli-plugin-babel": "3.6.0",
"@vue/cli-plugin-eslint": "^3.9.1",

206
public/bpic_eli/ajax.js Normal file
View File

@@ -0,0 +1,206 @@
function get(url, callback) {
var xhr
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest()
} else {
xhr = new ActiveXObject('Msxml2.XMLHTTP')
}
xhr.open('GET', url, true)
xhr.send('')
xhr.dataType = 'json'
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
if (callback) {
callback(xhr.responseText)
}
}
}
}
function post(url, data, callback) {
var xhr
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest()
} else {
xhr = new ActiveXObject('Msxml2.XMLHTTP')
}
xhr.open('POST', url, true)
if(data.contentType){
xhr.setRequestHeader('Content-Type', data.contentType)
} else {
xhr.setRequestHeader('Content-Type', 'application/json')
}
// xhr.setRequestHeader('Content-Type', data.contentType ?data.contentType : 'application/x-www-form-urlencoded')
xhr.send(data)
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
if (callback) {
callback(xhr.responseText)
}
}
}
}
//promise
function promise_get(url) {
var promise = new Promise(function(success, error) {
//new一个promise进行函数
get(url, function(str) {
//get 路径
success(str) //吧进行时改成完成时
})
})
return promise
}
//josnp 服务器script
function jsonp(url) {
var script = document.createElement('script') //创建一个script
document.getElementsByTagName('head')[0].appendChild(script) //在页面上获取head在下面添加script
script.src = url //script的路径
}
//
// function get(url, callback){
// var xhr;
// if( window.XMLHttpRequest ){
// xhr = new XMLHttpRequest();
// }else{
// xhr = new ActiveXObject("Msxml2.XMLHTTP");
// }
// xhr.open("GET", url, true);
// xhr.send();
// xhr.onreadystatechange = function(){
// if( xhr.readyState==4 && xhr.status==200 ){
// if( callback ){
// callback( xhr.responseText );
// }
// }
// }
// }
//
// function post(url, data, callback){
// var xhr;
// if( window.XMLHttpRequest ){
// xhr = new XMLHttpRequest();
// }else{
// xhr = new ActiveXObject("Msxml2.XMLHTTP");
// }
// xhr.open("POST", url, true);
// xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
// xhr.send(data);
// xhr.onreadystatechange = function(){
// if( xhr.readyState==4 && xhr.status==200 ){
// if( callback ){
// callback( xhr.responseText );
// }
// }
// }
// }
//
//
//promise
function promise_get(type, url) {
var promise = new Promise(function(success, error) {
//new一个promise进行函数
type(url, function(str) {
//get 路径
success(str) //吧进行时改成完成时
})
})
return promise
}
//
//
//
//josnp 服务器script
// function jsonp(url,callback){
// var script = document.createElement("script");//创建一个script
// document.getElementsByTagName("head")[0].appendChild(script);//在页面上获取head在下面添加script
// script.src = url;//script的路径
// console.log(url.data);
// callback
// }
// cookie
// 创建、修改、删除cookie
function setCookie(_name, _value, _date) {
// 设置的值无论是什么类型的数据都给他转为json对象
var json = {
value: _value
}
var str = JSON.stringify(json) // 将json对象转为字符串 '{"value":_value}'
str = encodeURIComponent(str) // 编码,解决中文乱码
// 设置cookie
if (_date) {
var dt = new Date()
dt.setDate(dt.getDate() + _date)
document.cookie =
_name + '=' + str + ';expires=' + dt.toGMTString() + ';path=/'
} else {
document.cookie = _name + '=' + str + ';path=/'
}
}
function addCookie(_name, _value, _date) {
setCookie(_name, _value, _date)
}
// 根据cookie名称删除该cookie
function removeCookie(_name) {
setCookie(_name, '', -1)
}
// 根据cookie名称获取该cookie的内容
function getCookie(_name) {
var str = document.cookie
// str = "b={"value":_value}; bc=1; ac=1; dc=1; c=1";
var arr = str.split('; ')
// arr = ["b={"value":_value}", "bc=1", "ac=1", "dc=1", "c=1"];
for (var i = 0, l = arr.length; i < l; i++) {
var tmp = arr[i] // "b={"value":_value}"
var col = tmp.split('=') // ["b", "{"value":_value}"]
// if ( "b" == "b" )
if (_name == col[0]) {
//如果找到了cookie则跳出函数并将其结果返回
var decode = decodeURIComponent(col[1]) //解码 "{"value":_value}"
var obj = JSON.parse(decode) //将字符串转换为json对象
return obj.value
}
}
return '' // 如果没有这一行如果找不到cookie则返回undefined
}
// 手动遍历对象,生成查询字符串
function objectToQueryString(obj) {
var str = ''
var first = true
for (var key in obj) {
// 确保是自身属性,不是从原型链继承的
if (obj.hasOwnProperty(key)) {
var value = obj[key] || '' // 防止 undefined
// 使用 encodeURIComponent 防止特殊字符
var part = encodeURIComponent(key) + '=' + encodeURIComponent(value)
if (first) {
str += '?' + part
first = false
} else {
str += '&' + part
}
}
}
return str
}
// 获取URL参数的工具函数
function getQueryParam(name) {
var url = window.location.href
var reg = new RegExp('[?&]' + name + '=([^&#]*)')
var results = reg.exec(url)
return results ? decodeURIComponent(results[1]) : null
}
//获取当前日期

BIN
public/bpic_eli/cai-f.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

BIN
public/bpic_eli/cai.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

BIN
public/bpic_eli/empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
public/bpic_eli/error.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 B

BIN
public/bpic_eli/loading.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

BIN
public/bpic_eli/ping.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 531 B

BIN
public/bpic_eli/right.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

File diff suppressed because it is too large Load Diff

BIN
public/bpic_eli/round.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

BIN
public/bpic_eli/toDown.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

BIN
public/bpic_eli/toRight.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

BIN
public/bpic_eli/zan-f.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
public/bpic_eli/zan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

539
public/fonts/demo.css Normal file
View File

@@ -0,0 +1,539 @@
/* Logo 字体 */
@font-face {
font-family: "iconfont logo";
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
}
.logo {
font-family: "iconfont logo";
font-size: 160px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* tabs */
.nav-tabs {
position: relative;
}
.nav-tabs .nav-more {
position: absolute;
right: 0;
bottom: 0;
height: 42px;
line-height: 42px;
color: #666;
}
#tabs {
border-bottom: 1px solid #eee;
}
#tabs li {
cursor: pointer;
width: 100px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 16px;
border-bottom: 2px solid transparent;
position: relative;
z-index: 1;
margin-bottom: -1px;
color: #666;
}
#tabs .active {
border-bottom-color: #f00;
color: #222;
}
.tab-container .content {
display: none;
}
/* 页面布局 */
.main {
padding: 30px 100px;
width: 960px;
margin: 0 auto;
}
.main .logo {
color: #333;
text-align: left;
margin-bottom: 30px;
line-height: 1;
height: 110px;
margin-top: -50px;
overflow: hidden;
*zoom: 1;
}
.main .logo a {
font-size: 160px;
color: #333;
}
.helps {
margin-top: 40px;
}
.helps pre {
padding: 20px;
margin: 10px 0;
border: solid 1px #e7e1cd;
background-color: #fffdef;
overflow: auto;
}
.icon_lists {
width: 100% !important;
overflow: hidden;
*zoom: 1;
}
.icon_lists li {
width: 100px;
margin-bottom: 10px;
margin-right: 20px;
text-align: center;
list-style: none !important;
cursor: default;
}
.icon_lists li .code-name {
line-height: 1.2;
}
.icon_lists .icon {
display: block;
height: 100px;
line-height: 100px;
font-size: 42px;
margin: 10px auto;
color: #333;
-webkit-transition: font-size 0.25s linear, width 0.25s linear;
-moz-transition: font-size 0.25s linear, width 0.25s linear;
transition: font-size 0.25s linear, width 0.25s linear;
}
.icon_lists .icon:hover {
font-size: 100px;
}
.icon_lists .svg-icon {
/* 通过设置 font-size 来改变图标大小 */
width: 1em;
/* 图标和文字相邻时,垂直对齐 */
vertical-align: -0.15em;
/* 通过设置 color 来改变 SVG 的颜色/fill */
fill: currentColor;
/* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
normalize.css 中也包含这行 */
overflow: hidden;
}
.icon_lists li .name,
.icon_lists li .code-name {
color: #666;
}
/* markdown 样式 */
.markdown {
color: #666;
font-size: 14px;
line-height: 1.8;
}
.highlight {
line-height: 1.5;
}
.markdown img {
vertical-align: middle;
max-width: 100%;
}
.markdown h1 {
color: #404040;
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
}
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
color: #404040;
margin: 1.6em 0 0.6em 0;
font-weight: 500;
clear: both;
}
.markdown h1 {
font-size: 28px;
}
.markdown h2 {
font-size: 22px;
}
.markdown h3 {
font-size: 16px;
}
.markdown h4 {
font-size: 14px;
}
.markdown h5 {
font-size: 12px;
}
.markdown h6 {
font-size: 12px;
}
.markdown hr {
height: 1px;
border: 0;
background: #e9e9e9;
margin: 16px 0;
clear: both;
}
.markdown p {
margin: 1em 0;
}
.markdown>p,
.markdown>blockquote,
.markdown>.highlight,
.markdown>ol,
.markdown>ul {
width: 80%;
}
.markdown ul>li {
list-style: circle;
}
.markdown>ul li,
.markdown blockquote ul>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown>ul li p,
.markdown>ol li p {
margin: 0.6em 0;
}
.markdown ol>li {
list-style: decimal;
}
.markdown>ol li,
.markdown blockquote ol>li {
margin-left: 20px;
padding-left: 4px;
}
.markdown code {
margin: 0 3px;
padding: 0 5px;
background: #eee;
border-radius: 3px;
}
.markdown strong,
.markdown b {
font-weight: 600;
}
.markdown>table {
border-collapse: collapse;
border-spacing: 0px;
empty-cells: show;
border: 1px solid #e9e9e9;
width: 95%;
margin-bottom: 24px;
}
.markdown>table th {
white-space: nowrap;
color: #333;
font-weight: 600;
}
.markdown>table th,
.markdown>table td {
border: 1px solid #e9e9e9;
padding: 8px 16px;
text-align: left;
}
.markdown>table th {
background: #F7F7F7;
}
.markdown blockquote {
font-size: 90%;
color: #999;
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
}
.markdown blockquote p {
margin: 0;
}
.markdown .anchor {
opacity: 0;
transition: opacity 0.3s ease;
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
.markdown h4:hover .anchor,
.markdown h5:hover .anchor,
.markdown h6:hover .anchor {
opacity: 1;
display: inline-block;
}
.markdown>br,
.markdown>p>br {
clear: both;
}
.hljs {
display: block;
background: white;
padding: 0.5em;
color: #333333;
overflow-x: auto;
}
.hljs-comment,
.hljs-meta {
color: #969896;
}
.hljs-string,
.hljs-variable,
.hljs-template-variable,
.hljs-strong,
.hljs-emphasis,
.hljs-quote {
color: #df5000;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-type {
color: #a71d5d;
}
.hljs-literal,
.hljs-symbol,
.hljs-bullet,
.hljs-attribute {
color: #0086b3;
}
.hljs-section,
.hljs-name {
color: #63a35c;
}
.hljs-tag {
color: #333333;
}
.hljs-title,
.hljs-attr,
.hljs-selector-id,
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #795da3;
}
.hljs-addition {
color: #55a532;
background-color: #eaffea;
}
.hljs-deletion {
color: #bd2c00;
background-color: #ffecec;
}
.hljs-link {
text-decoration: underline;
}
/* 代码高亮 */
/* PrismJS 1.15.0
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
/**
* prism.js default theme for JavaScript, CSS and HTML
* Based on dabblet (http://dabblet.com)
* @author Lea Verou
*/
code[class*="language-"],
pre[class*="language-"] {
color: black;
background: none;
text-shadow: 0 1px white;
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
pre[class*="language-"]::-moz-selection,
pre[class*="language-"] ::-moz-selection,
code[class*="language-"]::-moz-selection,
code[class*="language-"] ::-moz-selection {
text-shadow: none;
background: #b3d4fc;
}
pre[class*="language-"]::selection,
pre[class*="language-"] ::selection,
code[class*="language-"]::selection,
code[class*="language-"] ::selection {
text-shadow: none;
background: #b3d4fc;
}
@media print {
code[class*="language-"],
pre[class*="language-"] {
text-shadow: none;
}
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
}
:not(pre)>code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}
/* Inline code */
:not(pre)>code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #999;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #9a6e3a;
background: hsla(0, 0%, 100%, .5);
}
.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}
.token.function,
.token.class-name {
color: #DD4A68;
}
.token.regex,
.token.important,
.token.variable {
color: #e90;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

1752
public/fonts/demo_index.html Normal file

File diff suppressed because it is too large Load Diff

287
public/fonts/iconfont.css Normal file
View File

@@ -0,0 +1,287 @@
@font-face {
font-family: "iconfont"; /* Project id 4902894 */
src: url('iconfont.woff2?t=1753684205709') format('woff2'),
url('iconfont.woff?t=1753684205709') format('woff'),
url('iconfont.ttf?t=1753684205709') format('truetype');
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-youjiantou:before {
content: "\e61f";
}
.icon-shezhi:before {
content: "\e645";
}
.icon-tuichu:before {
content: "\e646";
}
.icon-yangmei:before {
content: "\e648";
}
.icon-shouye:before {
content: "\e649";
}
.icon-gongyeruanjian:before {
content: "\e64a";
}
.icon-tishici:before {
content: "\e64b";
}
.icon-zhongying:before {
content: "\e64c";
}
.icon-MCP:before {
content: "\e64d";
}
.icon-bianji:before {
content: "\e64e";
}
.icon-fabu:before {
content: "\e64f";
}
.icon-kaifa:before {
content: "\e650";
}
.icon-xiala:before {
content: "\e651";
}
.icon-shanchu:before {
content: "\e652";
}
.icon-fuzhi:before {
content: "\e653";
}
.icon-quxiaofabu:before {
content: "\e654";
}
.icon-paixu1:before {
content: "\e655";
}
.icon-tupian:before {
content: "\e656";
}
.icon-fasong1:before {
content: "\e657";
}
.icon-biaoge:before {
content: "\e658";
}
.icon-wenjian:before {
content: "\e659";
}
.icon-rongqi:before {
content: "\e65a";
}
.icon-shoucang:before {
content: "\e65b";
}
.icon-xihuan:before {
content: "\e65c";
}
.icon-dingzhi:before {
content: "\e65d";
}
.icon-yunhang:before {
content: "\e65f";
}
.icon-taolun:before {
content: "\e660";
}
.icon-xiangqing:before {
content: "\e661";
}
.icon-youse:before {
content: "\e662";
}
.icon-quanbu:before {
content: "\e663";
}
.icon-fenxiang1:before {
content: "\e664";
}
.icon-wenjianjia:before {
content: "\e665";
}
.icon-wenjian1:before {
content: "\e666";
}
.icon-jiankong:before {
content: "\e667";
}
.icon-shuaxin1:before {
content: "\e668";
}
.icon-shanchu1:before {
content: "\e669";
}
.icon-shangchuan1:before {
content: "\e66a";
}
.icon-xiazai:before {
content: "\e66b";
}
.icon-yangmei1:before {
content: "\e66c";
}
.icon-renwu:before {
content: "\e66d";
}
.icon-history:before {
content: "\e69b";
}
.icon-paixu:before {
content: "\e633";
}
.icon-shuaxin:before {
content: "\e634";
}
.icon-gengduo:before {
content: "\e635";
}
.icon-lishi:before {
content: "\e636";
}
.icon-shangchuan:before {
content: "\e637";
}
.icon-fasong:before {
content: "\e638";
}
.icon-zongjie:before {
content: "\e639";
}
.icon-laiyuan:before {
content: "\e63a";
}
.icon-qingchu:before {
content: "\e63b";
}
.icon-mengbanzu:before {
content: "\e63c";
}
.icon-fenxiang:before {
content: "\e63d";
}
.icon-xinjian:before {
content: "\e63e";
}
.icon-shenqian:before {
content: "\e63f";
}
.icon-ziyuanku:before {
content: "\e640";
}
.icon-guangchang:before {
content: "\e641";
}
.icon-geren:before {
content: "\e642";
}
.icon-zhishiku:before {
content: "\e643";
}
.icon-biaozhunku:before {
content: "\e644";
}
.icon-dingding:before {
content: "\e690";
}
.icon-chuansuoyou:before {
content: "\e647";
}
.icon-yanjingxianshi:before {
content: "\e76e";
}
.icon-zhuye:before {
content: "\e65e";
}
.icon-dingwei:before {
content: "\e629";
}
.icon-dengpao:before {
content: "\e69c";
}
.icon-dengpao1:before {
content: "\e67f";
}
.icon-guizeshezhi:before {
content: "\e6dc";
}
.icon-notebook:before {
content: "\e923";
}

1
public/fonts/iconfont.js Normal file

File diff suppressed because one or more lines are too long

485
public/fonts/iconfont.json Normal file
View File

@@ -0,0 +1,485 @@
{
"id": "4902894",
"name": "knowledge",
"font_family": "iconfont",
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "434756",
"name": "youjiantou",
"font_class": "youjiantou",
"unicode": "e61f",
"unicode_decimal": 58911
},
{
"icon_id": "44587650",
"name": "设置",
"font_class": "shezhi",
"unicode": "e645",
"unicode_decimal": 58949
},
{
"icon_id": "44587651",
"name": "退出",
"font_class": "tuichu",
"unicode": "e646",
"unicode_decimal": 58950
},
{
"icon_id": "44587652",
"name": "杨梅",
"font_class": "yangmei",
"unicode": "e648",
"unicode_decimal": 58952
},
{
"icon_id": "44587653",
"name": "首页",
"font_class": "shouye",
"unicode": "e649",
"unicode_decimal": 58953
},
{
"icon_id": "44587654",
"name": "工业软件",
"font_class": "gongyeruanjian",
"unicode": "e64a",
"unicode_decimal": 58954
},
{
"icon_id": "44587656",
"name": "提示词",
"font_class": "tishici",
"unicode": "e64b",
"unicode_decimal": 58955
},
{
"icon_id": "44587657",
"name": "中英",
"font_class": "zhongying",
"unicode": "e64c",
"unicode_decimal": 58956
},
{
"icon_id": "44587658",
"name": "MCP",
"font_class": "MCP",
"unicode": "e64d",
"unicode_decimal": 58957
},
{
"icon_id": "44587659",
"name": "编辑",
"font_class": "bianji",
"unicode": "e64e",
"unicode_decimal": 58958
},
{
"icon_id": "44587660",
"name": "发布",
"font_class": "fabu",
"unicode": "e64f",
"unicode_decimal": 58959
},
{
"icon_id": "44587661",
"name": "开发",
"font_class": "kaifa",
"unicode": "e650",
"unicode_decimal": 58960
},
{
"icon_id": "44587662",
"name": "下拉",
"font_class": "xiala",
"unicode": "e651",
"unicode_decimal": 58961
},
{
"icon_id": "44587663",
"name": "删除",
"font_class": "shanchu",
"unicode": "e652",
"unicode_decimal": 58962
},
{
"icon_id": "44587664",
"name": "复制",
"font_class": "fuzhi",
"unicode": "e653",
"unicode_decimal": 58963
},
{
"icon_id": "44587667",
"name": "取消发布",
"font_class": "quxiaofabu",
"unicode": "e654",
"unicode_decimal": 58964
},
{
"icon_id": "44587669",
"name": "排序",
"font_class": "paixu1",
"unicode": "e655",
"unicode_decimal": 58965
},
{
"icon_id": "44588125",
"name": "图片",
"font_class": "tupian",
"unicode": "e656",
"unicode_decimal": 58966
},
{
"icon_id": "44588126",
"name": "发送",
"font_class": "fasong1",
"unicode": "e657",
"unicode_decimal": 58967
},
{
"icon_id": "44588128",
"name": "表格",
"font_class": "biaoge",
"unicode": "e658",
"unicode_decimal": 58968
},
{
"icon_id": "44588207",
"name": "文件",
"font_class": "wenjian",
"unicode": "e659",
"unicode_decimal": 58969
},
{
"icon_id": "44588495",
"name": "容器",
"font_class": "rongqi",
"unicode": "e65a",
"unicode_decimal": 58970
},
{
"icon_id": "44588496",
"name": "收藏",
"font_class": "shoucang",
"unicode": "e65b",
"unicode_decimal": 58971
},
{
"icon_id": "44588497",
"name": "喜欢",
"font_class": "xihuan",
"unicode": "e65c",
"unicode_decimal": 58972
},
{
"icon_id": "44588498",
"name": "定制",
"font_class": "dingzhi",
"unicode": "e65d",
"unicode_decimal": 58973
},
{
"icon_id": "44588499",
"name": "运行",
"font_class": "yunhang",
"unicode": "e65f",
"unicode_decimal": 58975
},
{
"icon_id": "44588500",
"name": "讨论",
"font_class": "taolun",
"unicode": "e660",
"unicode_decimal": 58976
},
{
"icon_id": "44588501",
"name": "详情",
"font_class": "xiangqing",
"unicode": "e661",
"unicode_decimal": 58977
},
{
"icon_id": "44588510",
"name": "有色",
"font_class": "youse",
"unicode": "e662",
"unicode_decimal": 58978
},
{
"icon_id": "44588596",
"name": "全部",
"font_class": "quanbu",
"unicode": "e663",
"unicode_decimal": 58979
},
{
"icon_id": "44754887",
"name": "分享",
"font_class": "fenxiang1",
"unicode": "e664",
"unicode_decimal": 58980
},
{
"icon_id": "44754889",
"name": "文件夹",
"font_class": "wenjianjia",
"unicode": "e665",
"unicode_decimal": 58981
},
{
"icon_id": "44754890",
"name": "文件",
"font_class": "wenjian1",
"unicode": "e666",
"unicode_decimal": 58982
},
{
"icon_id": "44754891",
"name": "监控",
"font_class": "jiankong",
"unicode": "e667",
"unicode_decimal": 58983
},
{
"icon_id": "44754892",
"name": "刷新",
"font_class": "shuaxin1",
"unicode": "e668",
"unicode_decimal": 58984
},
{
"icon_id": "44754893",
"name": "删除",
"font_class": "shanchu1",
"unicode": "e669",
"unicode_decimal": 58985
},
{
"icon_id": "44754894",
"name": "上传",
"font_class": "shangchuan1",
"unicode": "e66a",
"unicode_decimal": 58986
},
{
"icon_id": "44754895",
"name": "下载",
"font_class": "xiazai",
"unicode": "e66b",
"unicode_decimal": 58987
},
{
"icon_id": "44754896",
"name": "杨梅",
"font_class": "yangmei1",
"unicode": "e66c",
"unicode_decimal": 58988
},
{
"icon_id": "44754897",
"name": "任务",
"font_class": "renwu",
"unicode": "e66d",
"unicode_decimal": 58989
},
{
"icon_id": "8106263",
"name": "history",
"font_class": "history",
"unicode": "e69b",
"unicode_decimal": 59035
},
{
"icon_id": "43121608",
"name": "排序",
"font_class": "paixu",
"unicode": "e633",
"unicode_decimal": 58931
},
{
"icon_id": "43121609",
"name": "刷新",
"font_class": "shuaxin",
"unicode": "e634",
"unicode_decimal": 58932
},
{
"icon_id": "43121610",
"name": "更多",
"font_class": "gengduo",
"unicode": "e635",
"unicode_decimal": 58933
},
{
"icon_id": "43121611",
"name": "历史",
"font_class": "lishi",
"unicode": "e636",
"unicode_decimal": 58934
},
{
"icon_id": "43121612",
"name": "上传",
"font_class": "shangchuan",
"unicode": "e637",
"unicode_decimal": 58935
},
{
"icon_id": "43121613",
"name": "发送",
"font_class": "fasong",
"unicode": "e638",
"unicode_decimal": 58936
},
{
"icon_id": "43121614",
"name": "总结",
"font_class": "zongjie",
"unicode": "e639",
"unicode_decimal": 58937
},
{
"icon_id": "43121615",
"name": "来源",
"font_class": "laiyuan",
"unicode": "e63a",
"unicode_decimal": 58938
},
{
"icon_id": "43121617",
"name": "清除",
"font_class": "qingchu",
"unicode": "e63b",
"unicode_decimal": 58939
},
{
"icon_id": "44524880",
"name": "蒙版组",
"font_class": "mengbanzu",
"unicode": "e63c",
"unicode_decimal": 58940
},
{
"icon_id": "44524903",
"name": "分享",
"font_class": "fenxiang",
"unicode": "e63d",
"unicode_decimal": 58941
},
{
"icon_id": "44587642",
"name": "新建",
"font_class": "xinjian",
"unicode": "e63e",
"unicode_decimal": 58942
},
{
"icon_id": "44587643",
"name": "深浅",
"font_class": "shenqian",
"unicode": "e63f",
"unicode_decimal": 58943
},
{
"icon_id": "44587644",
"name": "资源库",
"font_class": "ziyuanku",
"unicode": "e640",
"unicode_decimal": 58944
},
{
"icon_id": "44587645",
"name": "广场",
"font_class": "guangchang",
"unicode": "e641",
"unicode_decimal": 58945
},
{
"icon_id": "44587646",
"name": "个人",
"font_class": "geren",
"unicode": "e642",
"unicode_decimal": 58946
},
{
"icon_id": "44587647",
"name": "知识库",
"font_class": "zhishiku",
"unicode": "e643",
"unicode_decimal": 58947
},
{
"icon_id": "44587649",
"name": "nadou",
"font_class": "biaozhunku",
"unicode": "e644",
"unicode_decimal": 58948
},
{
"icon_id": "9307592",
"name": "钉钉",
"font_class": "dingding",
"unicode": "e690",
"unicode_decimal": 59024
},
{
"icon_id": "43551849",
"name": "穿梭右",
"font_class": "chuansuoyou",
"unicode": "e647",
"unicode_decimal": 58951
},
{
"icon_id": "33131587",
"name": "眼睛显示",
"font_class": "yanjingxianshi",
"unicode": "e76e",
"unicode_decimal": 59246
},
{
"icon_id": "4320362",
"name": "主页",
"font_class": "zhuye",
"unicode": "e65e",
"unicode_decimal": 58974
},
{
"icon_id": "8765144",
"name": "定位",
"font_class": "dingwei",
"unicode": "e629",
"unicode_decimal": 58921
},
{
"icon_id": "9652678",
"name": "技术支持",
"font_class": "dengpao",
"unicode": "e69c",
"unicode_decimal": 59036
},
{
"icon_id": "13277451",
"name": "灯泡",
"font_class": "dengpao1",
"unicode": "e67f",
"unicode_decimal": 59007
},
{
"icon_id": "13584358",
"name": "规则设置",
"font_class": "guizeshezhi",
"unicode": "e6dc",
"unicode_decimal": 59100
},
{
"icon_id": "18169542",
"name": "笔记本电脑",
"font_class": "notebook",
"unicode": "e923",
"unicode_decimal": 59683
}
]
}

BIN
public/fonts/iconfont.ttf Normal file

Binary file not shown.

View File

BIN
public/fonts/iconfont.woff2 Normal file

Binary file not shown.

View File

@@ -6,7 +6,8 @@ export function login(data) {
return request({
url: getUrl('/sysUserEx/baseLogin'),
method: 'post',
data
data,
back: true
})
}
@@ -40,3 +41,28 @@ export function indexUser() {
method: 'get'
})
}
export function sendPhoneCodeLogin(data) {
return request({
url: getUrl('/sysUserEx/send_sms_4_login'),
method: 'post',
data
})
}
export function send_sms() {
return request({
url: getUrl('/sysUserEx/send_sms'),
method: 'get'
})
}
export function verify_login(data) {
return request({
url: getUrl('/sysUserEx/verify_login'),
method: 'post',
data
})
}
export function getCaptchaImage(data) {
return getUrl(`/captcha/getCaptchaImage?captchaKey=${data.captchaKey}`)
}

View File

@@ -62,6 +62,23 @@ export function updatePassword(data) {
return request({
url: getUrl(`/sysUserEx/updatePassword`),
method: 'post',
data,
back: true
})
}
export function externalUpdatePassword(data) {
return request({
url: getUrl(`/sysUserEx/externalUpdatePassword`),
method: 'post',
data
// back: true
})
}
export function verifyUpdatePassword(data) {
return request({
url: getUrl(`/sysUserEx/verifyUpdatePassword`),
method: 'post',
data
})
}

View File

@@ -0,0 +1,35 @@
import request from '@/assets/js/utils/request'
import getUrl from '@/assets/js/utils/get-url'
// 导出规则相关API
export * from './rule'
// 导出记录相关API
export * from './record'
// 查询审批单风险筛查结果
export function queryResult(data) {
return request({
url: getUrl('/riskCheckRecordEx/queryResult'),
method: 'get',
params: data
})
}
// 查询筛查结果得明细
export function queryResultDetail(data) {
return request({
url: getUrl('/riskCheckRecordEx/queryDetail'),
method: 'get',
params: data
})
}
export function taDataSubmit(data) {
return request({
url: getUrl('/bpic/ta/data_test'),
method: 'post',
data,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}

View File

@@ -0,0 +1,34 @@
import request from '@/assets/js/utils/request'
import getUrl from '@/assets/js/utils/get-url'
// 记录page页
export function getRecordPage(data) {
return request({
url: getUrl('/riskCheckRecordEx/page'),
method: 'post',
data
})
}
// 查询历史筛查结果
export function queryResult(params) {
return request({
url: getUrl('/riskCheckRecordEx/queryResult'),
method: 'get',
params
})
}
// 根据筛查结果查看明细
export function queryResultDetail(params) {
return request({
url: getUrl('/iskCheckRecordEx/queryDetail'),
method: 'get',
params
})
}
// 返回result.html内容
export function getResultHtml(params) {
return getUrl(`/result.html?taCode=${params.taCode}`)
}

185
src/api/riskCheck/rule.js Normal file
View File

@@ -0,0 +1,185 @@
import request from '@/assets/js/utils/request'
import getUrl from '@/assets/js/utils/get-url'
// 分页查询
export function getRulePage(data) {
return request({
url: getUrl('/riskCheckRuleEx/page'),
method: 'post',
data
})
}
// 查看详情
export function queryRuleDetail(params) {
return request({
url: getUrl('/risk/check/rule/query'),
method: 'get',
params
})
}
// 新增
export function createRule(data) {
return request({
// url: getUrl('/risk/check/rule/create'),
url: getUrl('/riskCheckRuleEx/create'),
method: 'post',
data
})
}
// 编辑
export function updateRule(data) {
return request({
// url: getUrl('/risk/check/rule/update'),
url: getUrl('/riskCheckRuleEx/update'),
method: 'post',
data
})
}
// 删除
export function deleteRule(data) {
return request({
url: getUrl('/risk/check/rule/delete'),
method: 'post',
data
})
}
// 批量启用/停用
export function batchSwitchStatus(status, data) {
return request({
url: getUrl(`/riskCheckRuleEx/batch/${status}`),
method: 'post',
data
})
}
// 全部启用/停用
export function allSwitchStatus(status, data) {
return request({
url: getUrl(`/riskCheckRuleEx/all/${status}`),
method: 'post',
data
})
}
// 导入Excel
export function importFromExcel(data) {
return request({
url: getUrl('/riskCheckRuleEx/importFromExcel'),
method: 'post',
data,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
// 导出Excel
export function exportToExcel(params) {
return request({
url: getUrl('/riskCheckRuleEx/export'),
method: 'get',
params,
responseType: 'blob'
})
}
// 列表查询
export function getRuleList(data) {
return request({
url: getUrl('/risk/check/rule/list'),
method: 'post',
data
})
}
// 规则类型的批量插入
export function batchAddRuleType(data) {
return request({
url: getUrl('/dictionary/batchAddRuleType'),
method: 'post',
data
})
}
// 字段的批量插入
export function batchAddField(data) {
return request({
url: getUrl('/dictionary/batchAddField'),
method: 'post',
data
})
}
// 风险类型的批量插入
export function batchAddRiskType(data) {
return request({
url: getUrl('/dictionary/batchAddRiskType'),
method: 'post',
data
})
}
/**
* 获取规则类型字典列表
* @param data 查询参数
* @returns {Promise}
*/
export function getRuleTypeList(data) {
return request({
url: getUrl('/risk/check/rule/type/list'),
method: 'post',
data
})
}
/**
* 获取字段类型字典列表
* @param data 查询参数
* @returns {Promise}
*/
export function getFieldTypeList(data) {
return request({
url: getUrl('/risk/check/field/list'),
method: 'post',
data
})
}
/**
* 获取风险类型字典列表
* @param data 查询参数
* @returns {Promise}
*/
export function getRiskTypeList(data) {
return request({
url: getUrl('/risk/types/list'),
method: 'post',
data
})
}
/**
* 获取所有归属机构
* @returns {Promise}
*/
export function getOrganizationList(data) {
return request({
url: getUrl('/organization/info/list'),
method: 'post',
data
})
}
/**
* 影像件下载
* @returns {Promise}
*/
export function downloadOrgFile(params) {
return getUrl(`/bpic/image/download?fileId=${params.fileId}`)
}

18
src/api/safety/index.js Normal file
View File

@@ -0,0 +1,18 @@
import request from '@/assets/js/utils/request'
import getUrl from '@/assets/js/utils/get-url'
export function getPublicKeyHex() {
return request({
url: getUrl('/keyPair/getPublicKey'),
method: 'get',
noLoading: true
})
}
export function getPrivateKeyHex() {
return request({
url: getUrl('/keyPair/getPrivateKey'),
method: 'get',
noLoading: true
})
}

View File

@@ -1,52 +1,275 @@
//encrypt.js
// sm2-utils.js
import { sm2 } from 'sm-crypto'
import { getPrivateKeyHex, getPublicKeyHex } from '@/api/safety'
// 不加密的URL列表
const ENCRYPT_EXCLUDE_URLS = [
'/bpic/ta/*',
'/keyPair/*',
'/riskCheckRecordEx/queryDetail',
'/riskCheckRecordEx/queryResult',
'/riskCheckRecordEx/saveOpinion'
]
// 将ENCRYPT_EXCLUDE_URLS通配符模式转换为正则表达式
const excludePatterns = ENCRYPT_EXCLUDE_URLS.map(pattern => {
// 将 * 转换为 .* 用于正则匹配
const regexPattern = pattern.replace(/\*/g, '.*')
return new RegExp('^' + regexPattern + '$')
})
// 检查是否需要加密
export function shouldEncrypt(url) {
// // 获取url eg:/sysUserEx/baseLogin
// const url = config.url.substring(config.url.lastIndexOf(':')).substring(6)
// 排除不加密的url
const isExcluded = excludePatterns.some(pattern => pattern.test(url))
return !isExcluded
}
/**
* 通过crypto-js实现 加解密工具
* AES
* @author: wmz
* 从 DER 编码的 SM2 公钥hex中提取原始未压缩公钥04 开头)
* @param {string} derHex - DER 格式的公钥(十六进制字符串)
* @returns {string} 原始公钥 hex 字符串04 开头130位
*/
import CryptoJS from 'crypto-js'
const KP = {
key: 'AJDBW8D2zdDq3b5U', // 秘钥 16*n:
iv: '' // 偏移量
function extractSm2RawPublicKey(derHex) {
if (cachedRawPublicKey) {
return cachedRawPublicKey
}
let derBuffer
try {
derBuffer =
typeof Buffer !== 'undefined'
? Buffer.from(derHex, 'hex')
: new Uint8Array(derHex.match(/[\da-f]{2}/gi).map(h => parseInt(h, 16)))
} catch (error) {
console.error('公钥 hex 格式无效', error)
throw new Error('系统安全异常,请联系管理员')
}
// 查找 03 42 00 04 模式
const pattern = [0x03, 0x42, 0x00, 0x04]
let offset = -1
for (let i = 0; i < derBuffer.length - pattern.length; i++) {
if (
derBuffer[i] === pattern[0] &&
derBuffer[i + 1] === pattern[1] &&
derBuffer[i + 2] === pattern[2] &&
derBuffer[i + 3] === pattern[3]
) {
offset = i + 4 // 跳过 03 42 00 04指向后面 65 字节的起点
break
}
}
if (offset === -1) {
throw new Error('系统安全异常,请联系管理员')
}
// 提取 65 字节04 + X + Y
const publicKeyRaw = derBuffer.slice(offset, offset + 65)
const hex =
typeof Buffer !== 'undefined'
? publicKeyRaw.toString('hex')
: Array.from(publicKeyRaw)
.map(b => b.toString(16).padStart(2, '0'))
.join()
return hex
}
function getAesString(data, key, iv) {
// 加密
key = CryptoJS.enc.Utf8.parse(key)
iv = CryptoJS.enc.Utf8.parse(iv)
let encrypted = CryptoJS.AES.encrypt(data, key, {
// iv: iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
return encrypted.toString() // 返回的是base64格式的密文
/**
* SM2 加密函数(支持选择性加密)
* @param {any} data - 待加密的数据
* @param {string} url - 请求 URL用于判断是否加密
* @returns {any|string} 加密后的 hex 字符串(带 04 前缀),或原数据
*/
export function encrypt(data) {
try {
const plaintext = typeof data === 'string' ? data : JSON.stringify(data)
var publicKeyHex = parseSM2PublicKey(
sessionStorage.getItem('derPublicKeyHex')
)
publicKeyHex = publicKeyHex.startsWith('04')
? publicKeyHex
: '04' + publicKeyHex
// 执行标准 SM2 加密C1C3C2 模式)
const ciphertext = sm2.doEncrypt(plaintext, publicKeyHex, 1)
// 🔥 必须加 '04' 前缀(适配后端)
const finalCiphertext = ciphertext.startsWith('04')
? ciphertext
: '04' + ciphertext
return finalCiphertext
} catch (error) {
throw new Error(`系统安全异常,请联系管理员`)
}
}
function getDAesString(encrypted, key, iv) {
// 解密
key = CryptoJS.enc.Utf8.parse(key)
iv = CryptoJS.enc.Utf8.parse(iv)
let decrypted = CryptoJS.AES.decrypt(encrypted, key, {
// iv: iv,
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
return decrypted.toString(CryptoJS.enc.Utf8) //
/**
* SM2 解密函数(支持解密带 '04' 前缀的密文)
* @param {string} cipherHex - 密文(可能带 04 前缀)
* @param {string} privateKeyHex - 私钥64位 HEX
* @param {number} mode - 加密模式1=C1C3C20=C1C2C3
* @returns {string|null} 明文 或 null失败
*/
export function decryptWithPrivateKey(cipherHex) {
try {
var privateKey = parseSM2PrivateKey(sessionStorage.getItem('privateKeyHex'))
// 校验私钥
if (!/^[0-9a-fA-F]{64}$/.test(privateKey)) {
throw new Error('系统安全异常,请联系管理员')
}
let cleanCipher = cipherHex.trim()
// 🔥 关键修复:如果以 '04' 开头,且长度异常,自动去除
if (cleanCipher.startsWith('04')) {
// 判断是否是人为添加的 04标准 C1C3C2 密文长度约 512~520加 04 后变 514+
const expectedMinLen = 512
if (cleanCipher.length > expectedMinLen) {
cleanCipher = cleanCipher.substring(2)
}
}
// 执行解密
const plaintext = sm2.doDecrypt(cleanCipher, privateKey, 1)
if (plaintext === false || plaintext === undefined) {
throw new Error('系统安全异常,请联系管理员')
}
return plaintext
} catch (error) {
return null
}
}
// AES 对称秘钥加密
const aes = {
en: data => getAesString(data, KP.key, KP.iv),
de: data => getDAesString(data, KP.key, KP.iv)
/**
* 获取原始公钥(用于调试)
*/
export function getPublicKey() {
return sessionStorage.getItem('derPublicKeyHex')
}
// BASE64
const base64 = {
en: data => CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(data)),
de: data => CryptoJS.enc.Base64.parse(data).toString(CryptoJS.enc.Utf8)
export function getPrivateKey() {
return sessionStorage.getItem('privateKeyHex')
}
// SHA256
const sha256 = data => {
return CryptoJS.SHA256(data).toString()
// 向后端接口获取未解析的公钥
export function fetchPublicKey() {
getPublicKeyHex()
.then(res => {
if (res.success) {
sessionStorage.setItem('derPublicKeyHex', res.content.content)
}
})
.catch(err => {
console.log('系统安全异常', err)
})
}
// MD5
const md5 = data => {
return CryptoJS.MD5(data).toString()
// 向后端接口获取未解析的私钥
export function fetchPrivateKey() {
getPrivateKeyHex()
.then(res => {
if (res.success) {
sessionStorage.setItem('privateKeyHex', res.content.content)
}
})
.catch(err => {
console.log('系统安全异常', err)
})
}
export function parseSM2PublicKey(publicKeyHex) {
try {
const cleanKey = publicKeyHex.replace(/\s/g, '')
// 查找公钥数据开始位置, 公钥数据在 "03420004" 之后03是BIT STRING42是66字节长度04是未压缩格式标识
const publicKeyDataIndex = cleanKey.indexOf('03420004')
if (publicKeyDataIndex !== -1) {
const publicKeyStart = publicKeyDataIndex + 8 // 跳过"03420004"
const publicKeyHex = cleanKey.substring(publicKeyStart)
// SM2公钥应该是130字符65字节04 + 32字节X + 32字节Y
if (publicKeyHex.length >= 130) {
const fullPublicKey = publicKeyHex.substring(0, 130)
if (
fullPublicKey.startsWith('04') &&
/^04[0-9a-fA-F]{128}$/.test(fullPublicKey)
) {
return fullPublicKey.toLowerCase()
}
}
}
// 如果找不到标准格式尝试直接提取130字符
if (cleanKey.length >= 130) {
// 查找04开头的130字符公钥
for (let i = 0; i <= cleanKey.length - 130; i++) {
const potentialKey = cleanKey.substring(i, i + 130)
if (
potentialKey.startsWith('04') &&
/^04[0-9a-fA-F]{128}$/.test(potentialKey)
) {
return potentialKey.toLowerCase()
}
}
}
throw new Error('系统安全异常,请联系管理员')
} catch (error) {
throw new Error(`系统安全异常,请联系管理员`)
}
}
/**
* 解析PKCS#8格式的SM2私钥
* @param {string} pkcs8PrivateKeyHex - PKCS#8格式的私钥16进制
* @returns {string} - 可直接使用的SM2私钥64字符16进制
*/
export function parseSM2PrivateKey(pkcs8PrivateKeyHex) {
try {
// 移除可能的空格和换行
const cleanKey = pkcs8PrivateKeyHex.replace(/\s/g, '')
// PKCS#8私钥结构通常包含版本号、算法标识和私钥数据
// 直接提取(适用于标准格式) 私钥通常在"0420"之后04表示OCTET STRING20表示32字节长度
const privateKeyIndex = cleanKey.indexOf('0420')
if (privateKeyIndex !== -1) {
const start = privateKeyIndex + 4
const privateKeyHex = cleanKey.substring(start, start + 64)
if (/^[0-9a-fA-F]{64}$/.test(privateKeyHex)) {
return privateKeyHex.toLowerCase()
}
}
// 从末尾提取64字符
if (cleanKey.length >= 64) {
const privateKeyHex = cleanKey.slice(-64)
if (/^[0-9a-fA-F]{64}$/.test(privateKeyHex)) {
return privateKeyHex.toLowerCase()
}
}
// 手动解析ASN.1结构(更精确)
const asn1PrivateKeyIndex = cleanKey.indexOf('0420')
if (asn1PrivateKeyIndex !== -1) {
const privateKeyStart = asn1PrivateKeyIndex + 4
const privateKeyHex = cleanKey.substring(
privateKeyStart,
privateKeyStart + 64
)
if (/^[0-9a-fA-F]{64}$/.test(privateKeyHex)) {
return privateKeyHex.toLowerCase()
}
}
throw new Error('系统安全异常,请联系管理员')
} catch (error) {
throw new Error(`系统安全异常,请联系管理员`)
}
}
export { aes, md5, sha256, base64 }

View File

@@ -4,10 +4,26 @@ import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { getToken, removeToken } from '@/assets/js/utils/auth' // get token from cookie
import { Message } from 'element-ui'
import {
fetchPrivateKey,
fetchPublicKey,
getPrivateKey,
getPublicKey
} from '@/assets/js/utils/encrypt'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login', '/authentication', '/404'] // no redirect whitelist
router.beforeEach((to, from, next) => {
router.beforeEach(async (to, from, next) => {
// 获取SM2公私钥
// if (getPrivateKey() === '' || getPrivateKey() === null) {
// await fetchPrivateKey()
// }
// if (getPublicKey() === '' || getPublicKey() === null) {
// await fetchPublicKey()
// }
routerEach(to, from, next)
})
function routerEach(to, from, next) {
NProgress.start()
if (getToken()) {
/* has token*/
@@ -45,7 +61,7 @@ router.beforeEach((to, from, next) => {
NProgress.done()
}
}
})
}
router.afterEach(() => {
// finish progress bar
NProgress.done()

View File

@@ -1,8 +1,15 @@
import axios from 'axios'
import { MessageBox, Message, Loading } from 'element-ui'
import { Loading, Message, MessageBox } from 'element-ui'
import store from '@/store'
import { getToken, removeToken } from '@/assets/js/utils/auth'
import router from '@/router'
import { logger } from 'runjs/lib/common'
import {
decryptWithPrivateKey,
encrypt,
shouldEncrypt
} from '@/assets/js/utils/encrypt'
// create an axios instance
const service = axios.create({
@@ -36,6 +43,38 @@ service.interceptors.request.use(
endLoading()
}
let deviceId = localStorage.getItem('deviceId')
if (deviceId) {
config.headers['deviceId'] = localStorage.getItem('deviceId')
}
// 3. 判断是否需要加密:跳过非 JSON 请求、OPTIONS 请求、自定义排除项
// const shouldSkipEncryption = () => {
// // 跳过 Content-Type 不是 application/json 的请求
// const contentType =
// config.headers['Content-Type'] || config.headers['content-type']
// if (contentType && !contentType.includes('application/json')) {
// return true
// }
//
// // // 跳过自定义标记不加密的请求 (在encrypt.js中已写这部分逻辑)
// const url = config.url.substring(config.url.lastIndexOf(':')).substring(6)
// return !shouldEncrypt(url)
// }
// 4. 执行加密逻辑
// if (!shouldSkipEncryption()) {
// // 添加加密标识(便于调试)
// config.headers['X-Encrypted'] = 'true'
//
// if (config.data) {
// // 保存原始数据用于调试
// config.originalData = config.data
//
// // 加密数据,包装成 { content: "encryptedString" }
// config.data = { content: encrypt(config.data, config.url) }
// }
// }
// config.type 可以从api的接口地址定义 可以不触发loading
if (config.noLoading !== true) {
startLoading()
@@ -49,9 +88,24 @@ service.interceptors.request.use(
// response interceptor
service.interceptors.response.use(
response => {
let res = response.data
// 解密处理
// if (
// response.config.headers['X-Encrypted'] === 'true' &&
// typeof res === 'string'
// ) {
// try {
// res = decryptWithPrivateKey(res)
// } catch (e) {
// logger.error('解密响应失败', e)
// }
// }
// if (res !== '' && typeof res === 'string') {
// res = JSON.parse(res)
// }
endLoading()
if (response.config.back) {
return response.data
return res
}
// 二进制数据则直接返回
if (
@@ -60,7 +114,6 @@ service.interceptors.response.use(
) {
return response.data
}
const res = response.data
res.code = Number(res.code)
if (res.code === 401) {
MessageBox.confirm('登录状态已过期,请重新登录', '系统提示', {

View File

@@ -42,6 +42,44 @@
}
}
.el-input {
&.el-input-group--append {
border-radius: 8px;
//border: 1px solid #dcdfe6; // 添加默认边框
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); // 添加过渡效果
& .el-input__inner {
//border-right: none;
border-radius: 8px 0 0 8px;
&:focus {
outline: 0;
border-color: $--color-primary;
//border-right: 1px solid $--color-primary;
}
&:hover {
border-color: $--color-primary;
border-color: $--color-primary;
//border-right: 1px solid $--color-primary;
}
}
// 当输入框获得焦点时,更新父元素边框颜色
& .el-input__inner:focus,
& .el-input__inner:focus ~ .el-input-group__append {
//border-color: $--color-primary;
}
//& .el-input__inner:hover ~ .el-input-group__append {
// border-color: $--color-primary;
//}
& .el-input-group__append {
border-radius: 0 8px 8px 0;
border-left: none;
transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); // 添加过渡效果
}
}
}
.el-cascader {
width: 100%;
& .el-input {

View File

@@ -103,3 +103,24 @@
}
}
}
.el-table {
& .descending {
.sort-caret {
&.descending {
border-top-color: $--color-primary;
}
}
}
& .ascending {
.sort-caret {
&.ascending {
border-bottom-color: $--color-primary;
}
}
}
}
.el-checkbox__input.is-checked .el-checkbox__inner,
.el-checkbox__input.is-indeterminate .el-checkbox__inner {
background-color: $--color-primary;
border-color: $--color-primary;
}

View File

@@ -1,5 +1,5 @@
// 主题色
$--color-primary: #4f47f5ff; // 主题色
$--color-primary: #4f47f5ff !default; // 主题色
$--color-primary-light: lighten($--color-primary, 5%); // 主题色的高亮版本
$--color-primary-button-gradient: linear-gradient(
311deg,
@@ -71,8 +71,8 @@ $--message-info-border: #cecece; // 信息消息框的边框色
// 根变量
:root {
--swiper-theme-color: #4f47f5ff; // Swiper 组件的主题色
--color-primary: #4f47f5ff; // 主题色
--swiper-theme-color: #4f47f5ff !important; // Swiper 组件的主题色
--color-primary: #4f47f5ff !important; // 主题色
--color-primary-disabled: #155aef24; // 主题色的禁用版本
--color-primary-danger: #ff0000; // 危险色
--color-primary-label: #70778d; // 主题色的标签颜色

View File

@@ -237,3 +237,22 @@ body,
outline: none;
border: none;
}
.employ-table {
.el-table--border td,
.el-table--border th,
.el-table__body-wrapper
.el-table--border.is-scrolling-left
~ .el-table__fixed {
border-right: none;
}
&:hover {
.el-table--border td,
.el-table--border th,
.el-table__body-wrapper
.el-table--border.is-scrolling-left
~ .el-table__fixed {
border-right: 1px solid #ebeef5;
}
}
}

View File

@@ -7,13 +7,14 @@ export default {
return scope.row[item.prop] ? (
<div class="toolBox">
<el-tooltip
class="tips"
content={
scope.row[item.prop] && scope.row[item.prop] != ''
? scope.row[item.prop]
: '2'
}
placement="right"
effect="dark"
effect="light"
>
<div class="ellipsis">{scope.row[item.prop]}</div>
</el-tooltip>
@@ -29,4 +30,7 @@ export default {
.toolBox {
display: inline-grid;
}
.tips {
max-width: 800px;
}
</style>

View File

@@ -18,8 +18,8 @@ const RenderSlot = {
{
props: {
placement: 'bottom',
content: first[0].data.props.title
// effect: 'light'
content: first[0].data.props.title,
effect: 'light'
}
},
first

View File

@@ -212,6 +212,9 @@ export default {
}
},
defaultSort: {
type: Object
},
//是否拖拽
drag: {
type: Boolean,

View File

@@ -1,7 +1,7 @@
let envInfo = process.env
let [admin, jifen, zixi, hz] = [
envInfo.VUE_APP_ADMIN,
'http://192.168.8.58:7196/',
'http://10.48.30.143:7196/',
'http://192.168.8.165:7196/',
'http://10.147.17.161:7196/'
]

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
@font-face {
font-family: 'iconfont'; /* Project id 4902894 */
src: url('iconfont.woff2?t=1745918237045') format('woff2'),
url('iconfont.woff?t=1745918237045') format('woff'),
url('iconfont.ttf?t=1745918237045') format('truetype');
src: url('iconfont.woff2?t=1753409323031') format('woff2'),
url('iconfont.woff?t=1753409323031') format('woff'),
url('iconfont.ttf?t=1753409323031') format('truetype');
}
.iconfont {
@@ -13,6 +13,242 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-shezhi:before {
content: '\e645';
}
.icon-tuichu:before {
content: '\e646';
}
.icon-yangmei:before {
content: '\e648';
}
.icon-shouye:before {
content: '\e649';
}
.icon-gongyeruanjian:before {
content: '\e64a';
}
.icon-tishici:before {
content: '\e64b';
}
.icon-zhongying:before {
content: '\e64c';
}
.icon-MCP:before {
content: '\e64d';
}
.icon-bianji:before {
content: '\e64e';
}
.icon-fabu:before {
content: '\e64f';
}
.icon-kaifa:before {
content: '\e650';
}
.icon-xiala:before {
content: '\e651';
}
.icon-shanchu:before {
content: '\e652';
}
.icon-fuzhi:before {
content: '\e653';
}
.icon-quxiaofabu:before {
content: '\e654';
}
.icon-paixu1:before {
content: '\e655';
}
.icon-tupian:before {
content: '\e656';
}
.icon-fasong1:before {
content: '\e657';
}
.icon-biaoge:before {
content: '\e658';
}
.icon-wenjian:before {
content: '\e659';
}
.icon-rongqi:before {
content: '\e65a';
}
.icon-shoucang:before {
content: '\e65b';
}
.icon-xihuan:before {
content: '\e65c';
}
.icon-dingzhi:before {
content: '\e65d';
}
.icon-yunhang:before {
content: '\e65f';
}
.icon-taolun:before {
content: '\e660';
}
.icon-xiangqing:before {
content: '\e661';
}
.icon-youse:before {
content: '\e662';
}
.icon-quanbu:before {
content: '\e663';
}
.icon-fenxiang1:before {
content: '\e664';
}
.icon-wenjianjia:before {
content: '\e665';
}
.icon-wenjian1:before {
content: '\e666';
}
.icon-jiankong:before {
content: '\e667';
}
.icon-shuaxin1:before {
content: '\e668';
}
.icon-shanchu1:before {
content: '\e669';
}
.icon-shangchuan1:before {
content: '\e66a';
}
.icon-xiazai:before {
content: '\e66b';
}
.icon-yangmei1:before {
content: '\e66c';
}
.icon-renwu:before {
content: '\e66d';
}
.icon-history:before {
content: '\e69b';
}
.icon-paixu:before {
content: '\e633';
}
.icon-shuaxin:before {
content: '\e634';
}
.icon-gengduo:before {
content: '\e635';
}
.icon-lishi:before {
content: '\e636';
}
.icon-shangchuan:before {
content: '\e637';
}
.icon-fasong:before {
content: '\e638';
}
.icon-zongjie:before {
content: '\e639';
}
.icon-laiyuan:before {
content: '\e63a';
}
.icon-qingchu:before {
content: '\e63b';
}
.icon-mengbanzu:before {
content: '\e63c';
}
.icon-fenxiang:before {
content: '\e63d';
}
.icon-xinjian:before {
content: '\e63e';
}
.icon-shenqian:before {
content: '\e63f';
}
.icon-ziyuanku:before {
content: '\e640';
}
.icon-guangchang:before {
content: '\e641';
}
.icon-geren:before {
content: '\e642';
}
.icon-zhishiku:before {
content: '\e643';
}
.icon-biaozhunku:before {
content: '\e644';
}
.icon-dingding:before {
content: '\e690';
}
.icon-chuansuoyou:before {
content: '\e647';
}

File diff suppressed because one or more lines are too long

View File

@@ -5,6 +5,419 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "44587650",
"name": "设置",
"font_class": "shezhi",
"unicode": "e645",
"unicode_decimal": 58949
},
{
"icon_id": "44587651",
"name": "退出",
"font_class": "tuichu",
"unicode": "e646",
"unicode_decimal": 58950
},
{
"icon_id": "44587652",
"name": "杨梅",
"font_class": "yangmei",
"unicode": "e648",
"unicode_decimal": 58952
},
{
"icon_id": "44587653",
"name": "首页",
"font_class": "shouye",
"unicode": "e649",
"unicode_decimal": 58953
},
{
"icon_id": "44587654",
"name": "工业软件",
"font_class": "gongyeruanjian",
"unicode": "e64a",
"unicode_decimal": 58954
},
{
"icon_id": "44587656",
"name": "提示词",
"font_class": "tishici",
"unicode": "e64b",
"unicode_decimal": 58955
},
{
"icon_id": "44587657",
"name": "中英",
"font_class": "zhongying",
"unicode": "e64c",
"unicode_decimal": 58956
},
{
"icon_id": "44587658",
"name": "MCP",
"font_class": "MCP",
"unicode": "e64d",
"unicode_decimal": 58957
},
{
"icon_id": "44587659",
"name": "编辑",
"font_class": "bianji",
"unicode": "e64e",
"unicode_decimal": 58958
},
{
"icon_id": "44587660",
"name": "发布",
"font_class": "fabu",
"unicode": "e64f",
"unicode_decimal": 58959
},
{
"icon_id": "44587661",
"name": "开发",
"font_class": "kaifa",
"unicode": "e650",
"unicode_decimal": 58960
},
{
"icon_id": "44587662",
"name": "下拉",
"font_class": "xiala",
"unicode": "e651",
"unicode_decimal": 58961
},
{
"icon_id": "44587663",
"name": "删除",
"font_class": "shanchu",
"unicode": "e652",
"unicode_decimal": 58962
},
{
"icon_id": "44587664",
"name": "复制",
"font_class": "fuzhi",
"unicode": "e653",
"unicode_decimal": 58963
},
{
"icon_id": "44587667",
"name": "取消发布",
"font_class": "quxiaofabu",
"unicode": "e654",
"unicode_decimal": 58964
},
{
"icon_id": "44587669",
"name": "排序",
"font_class": "paixu1",
"unicode": "e655",
"unicode_decimal": 58965
},
{
"icon_id": "44588125",
"name": "图片",
"font_class": "tupian",
"unicode": "e656",
"unicode_decimal": 58966
},
{
"icon_id": "44588126",
"name": "发送",
"font_class": "fasong1",
"unicode": "e657",
"unicode_decimal": 58967
},
{
"icon_id": "44588128",
"name": "表格",
"font_class": "biaoge",
"unicode": "e658",
"unicode_decimal": 58968
},
{
"icon_id": "44588207",
"name": "文件",
"font_class": "wenjian",
"unicode": "e659",
"unicode_decimal": 58969
},
{
"icon_id": "44588495",
"name": "容器",
"font_class": "rongqi",
"unicode": "e65a",
"unicode_decimal": 58970
},
{
"icon_id": "44588496",
"name": "收藏",
"font_class": "shoucang",
"unicode": "e65b",
"unicode_decimal": 58971
},
{
"icon_id": "44588497",
"name": "喜欢",
"font_class": "xihuan",
"unicode": "e65c",
"unicode_decimal": 58972
},
{
"icon_id": "44588498",
"name": "定制",
"font_class": "dingzhi",
"unicode": "e65d",
"unicode_decimal": 58973
},
{
"icon_id": "44588499",
"name": "运行",
"font_class": "yunhang",
"unicode": "e65f",
"unicode_decimal": 58975
},
{
"icon_id": "44588500",
"name": "讨论",
"font_class": "taolun",
"unicode": "e660",
"unicode_decimal": 58976
},
{
"icon_id": "44588501",
"name": "详情",
"font_class": "xiangqing",
"unicode": "e661",
"unicode_decimal": 58977
},
{
"icon_id": "44588510",
"name": "有色",
"font_class": "youse",
"unicode": "e662",
"unicode_decimal": 58978
},
{
"icon_id": "44588596",
"name": "全部",
"font_class": "quanbu",
"unicode": "e663",
"unicode_decimal": 58979
},
{
"icon_id": "44754887",
"name": "分享",
"font_class": "fenxiang1",
"unicode": "e664",
"unicode_decimal": 58980
},
{
"icon_id": "44754889",
"name": "文件夹",
"font_class": "wenjianjia",
"unicode": "e665",
"unicode_decimal": 58981
},
{
"icon_id": "44754890",
"name": "文件",
"font_class": "wenjian1",
"unicode": "e666",
"unicode_decimal": 58982
},
{
"icon_id": "44754891",
"name": "监控",
"font_class": "jiankong",
"unicode": "e667",
"unicode_decimal": 58983
},
{
"icon_id": "44754892",
"name": "刷新",
"font_class": "shuaxin1",
"unicode": "e668",
"unicode_decimal": 58984
},
{
"icon_id": "44754893",
"name": "删除",
"font_class": "shanchu1",
"unicode": "e669",
"unicode_decimal": 58985
},
{
"icon_id": "44754894",
"name": "上传",
"font_class": "shangchuan1",
"unicode": "e66a",
"unicode_decimal": 58986
},
{
"icon_id": "44754895",
"name": "下载",
"font_class": "xiazai",
"unicode": "e66b",
"unicode_decimal": 58987
},
{
"icon_id": "44754896",
"name": "杨梅",
"font_class": "yangmei1",
"unicode": "e66c",
"unicode_decimal": 58988
},
{
"icon_id": "44754897",
"name": "任务",
"font_class": "renwu",
"unicode": "e66d",
"unicode_decimal": 58989
},
{
"icon_id": "8106263",
"name": "history",
"font_class": "history",
"unicode": "e69b",
"unicode_decimal": 59035
},
{
"icon_id": "43121608",
"name": "排序",
"font_class": "paixu",
"unicode": "e633",
"unicode_decimal": 58931
},
{
"icon_id": "43121609",
"name": "刷新",
"font_class": "shuaxin",
"unicode": "e634",
"unicode_decimal": 58932
},
{
"icon_id": "43121610",
"name": "更多",
"font_class": "gengduo",
"unicode": "e635",
"unicode_decimal": 58933
},
{
"icon_id": "43121611",
"name": "历史",
"font_class": "lishi",
"unicode": "e636",
"unicode_decimal": 58934
},
{
"icon_id": "43121612",
"name": "上传",
"font_class": "shangchuan",
"unicode": "e637",
"unicode_decimal": 58935
},
{
"icon_id": "43121613",
"name": "发送",
"font_class": "fasong",
"unicode": "e638",
"unicode_decimal": 58936
},
{
"icon_id": "43121614",
"name": "总结",
"font_class": "zongjie",
"unicode": "e639",
"unicode_decimal": 58937
},
{
"icon_id": "43121615",
"name": "来源",
"font_class": "laiyuan",
"unicode": "e63a",
"unicode_decimal": 58938
},
{
"icon_id": "43121617",
"name": "清除",
"font_class": "qingchu",
"unicode": "e63b",
"unicode_decimal": 58939
},
{
"icon_id": "44524880",
"name": "蒙版组",
"font_class": "mengbanzu",
"unicode": "e63c",
"unicode_decimal": 58940
},
{
"icon_id": "44524903",
"name": "分享",
"font_class": "fenxiang",
"unicode": "e63d",
"unicode_decimal": 58941
},
{
"icon_id": "44587642",
"name": "新建",
"font_class": "xinjian",
"unicode": "e63e",
"unicode_decimal": 58942
},
{
"icon_id": "44587643",
"name": "深浅",
"font_class": "shenqian",
"unicode": "e63f",
"unicode_decimal": 58943
},
{
"icon_id": "44587644",
"name": "资源库",
"font_class": "ziyuanku",
"unicode": "e640",
"unicode_decimal": 58944
},
{
"icon_id": "44587645",
"name": "广场",
"font_class": "guangchang",
"unicode": "e641",
"unicode_decimal": 58945
},
{
"icon_id": "44587646",
"name": "个人",
"font_class": "geren",
"unicode": "e642",
"unicode_decimal": 58946
},
{
"icon_id": "44587647",
"name": "知识库",
"font_class": "zhishiku",
"unicode": "e643",
"unicode_decimal": 58947
},
{
"icon_id": "44587649",
"name": "nadou",
"font_class": "biaozhunku",
"unicode": "e644",
"unicode_decimal": 58948
},
{
"icon_id": "9307592",
"name": "钉钉",
"font_class": "dingding",
"unicode": "e690",
"unicode_decimal": 59024
},
{
"icon_id": "43551849",
"name": "穿梭右",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,61 @@
<template>
<div :id="id" style="height: 100%;width:100%"></div>
</template>
<script>
import uuid from 'uuid'
import * as monaco from 'monaco-editor'
export default {
name: 'render-monaco-editor',
data() {
return {
id: 'monaco' + uuid.v4(),
standaloneEditorConstructionOptions: {
value: this.monacoValue, // 编辑器的值
language: 'javascript', //语言
theme: 'vs-dark', // 编辑器主题vs, hc-black, or vs-dark
autoIndent: true, // 自动缩进
readOnly: false // 是否只读
}
}
},
props: {
settings: {
type: Object,
default: () => {
return {}
}
},
monacoValue:{
type: String,
default: ''
}
},
watch: {},
components: {},
filters: {},
created() {},
mounted() {
this.createMonacoEditor()
},
methods: {
createMonacoEditor() {
const container = document.getElementById(this.id)
this.monacoEditor = monaco.editor.create(container, {
...this.standaloneEditorConstructionOptions,
...this.settings
})
this.monacoEditor.onDidChangeModelContent(event => {
// 格式化
// this.monacoEditor.getAction('editor.action.formatDocument').run()
this.$emit('update:value', this.monacoEditor.getValue())
})
}
},
computed: {}
}
</script>
<style scoped lang="scss">
#render-monaco-editor-container {
}
</style>

View File

@@ -0,0 +1,195 @@
<template>
<r-dialog
:visible.sync="visible"
title="发送短信验证码"
width="550px"
append-to-body
class="send-chat-phone-dialog"
>
<el-form
label-width="100px"
:model="phoneForm"
:rules="phoneRules"
class="phone-form"
ref="phoneForm"
>
<!-- <el-form-item label="手机号" prop="phone">-->
<!-- <div class="flex">-->
<!-- <el-input-->
<!-- v-model="phoneForm.phone"-->
<!-- placeholder="请输入手机号"-->
<!-- style="color:#000"-->
<!-- ></el-input>-->
<!-- <el-button-->
<!-- class="ml10 render-button pv5 ph10"-->
<!-- type="primary"-->
<!-- size="medium"-->
<!-- @click="sendPhoneCode"-->
<!-- :disabled="!sendCode"-->
<!-- >{{ !sendCode ? minute + '秒后重新发送' : '发送验证码' }}-->
<!-- </el-button>-->
<!-- </div>-->
<!-- </el-form-item>-->
<el-form-item label="短信验证码" prop="code" class="mr30">
<div class="flex">
<el-input
v-model="phoneForm.code"
placeholder="请输入短信验证码"
style="color:#000"
size="medium"
>
<template slot="append">
<el-button
class="ml10"
type="primary"
size="medium"
@click="sendPhoneCode"
:disabled="!sendCode"
>{{ !sendCode ? minute + '秒后重新发送' : '发送短信验证码' }}
</el-button>
</template>
</el-input>
</div>
<!-- <el-input-->
<!-- v-model="phoneForm.code"-->
<!-- placeholder="请输入验证码"-->
<!-- ></el-input>-->
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="cancel" size="medium">取消</el-button>
<el-button type="primary" @click="handleSubmit" size="medium"
>确定</el-button
>
</div>
</r-dialog>
</template>
<script>
import { sendPhoneCodeLogin, send_sms } from '@/api/app/user'
import { setToken } from '@/assets/js/utils/auth'
export default {
name: 'send-phone-code',
data() {
const validatePhone = (rule, value, callback) => {
// 手机号正则
const validPhone = phone => {
return /^1[3456789]\d{9}$/.test(phone)
}
if (!validPhone(value)) {
callback(new Error('请输入正确的手机号'))
} else {
callback()
}
}
return {
sendCode: true,
phoneRules: {
phone: [
{ required: true, message: '请输入手机号', trigger: 'change' },
{ validator: validatePhone, trigger: 'change' }
],
code: [{ required: true, message: '请输入验证码', trigger: 'change' }]
},
phoneForm: {
phone: '',
code: ''
},
minute: 120 // 默认120秒 发送间隔
}
},
props: {
visible: {
type: Boolean,
default: false
},
userName: {
type: String,
default: ''
},
resetPassword: {
type: Boolean,
default: false
}
},
watch: {
visible(newVal) {
if (!newVal) {
// 重置表单
this.phoneForm = {
phone: '',
code: ''
}
// this.sendCode = true
// clearInterval(this.timer)
}
}
},
components: {},
filters: {},
methods: {
sendCodeText() {
// 倒计时 60S
this.minute = 120
this.timer = setInterval(() => {
this.minute--
if (this.minute <= 0) {
this.sendCode = true
clearInterval(this.timer)
}
}, 1000)
return this.minute
},
sendPhoneCode() {
let api = this.resetPassword ? send_sms : sendPhoneCodeLogin
api({
userName: this.userName ? this.userName : undefined
}).then(res => {
if (Number(res.code) === 0) {
this.sendCode = false
this.sendCodeText()
}
})
},
handleSubmit() {
this.$refs.phoneForm.validate(valid => {
if (valid) {
this.$emit('handleSubmit', this.phoneForm.code)
}
})
},
cancel() {
this.$emit('update:visible', false)
}
},
created() {},
mounted() {},
computed: {}
}
</script>
<style lang="scss">
@import '../assets/sass/renderSass/theme.scss';
.send-chat-phone-dialog {
.phone-form {
& .el-input-group__append {
background: $--color-primary;
color: #fff;
border-color: $--color-primary;
& .el-button {
&.is-disabled {
& ~ .el-input-group__append {
background: $--color-primary-disabled;
}
}
}
}
}
}
</style>

View File

@@ -0,0 +1 @@
<svg t="1753174280510" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9768" width="200" height="200"><path d="M512 0a512 512 0 1 0 512 512 512 512 0 0 0-512-512z m0 938.688A426.688 426.688 0 1 1 938.688 512 427.136 427.136 0 0 1 512 938.688z m217.856-574.528a42.688 42.688 0 0 1 0 60.352l-241.28 241.344a42.688 42.688 0 0 1-60.416 0L307.52 545.28a42.688 42.688 0 0 1 60.352-60.352L458.368 575.36l211.2-211.2a42.688 42.688 0 0 1 60.288 0z" fill="#0bde91" p-id="9769"></path></svg>

After

Width:  |  Height:  |  Size: 525 B

BIN
src/icons/svg/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

1
src/icons/svg/waring.svg Normal file
View File

@@ -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="1753173443768" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4576" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 0C229.2 0 0 229.2 0 512s229.2 512 512 512 512-229.3 512-512S794.8 0 512 0z" fill="#F99B52" p-id="4577"></path><path d="M512 832.7c-29.6 0-53.5-24-53.5-53.6s24-53.6 53.6-53.5c29.6 0 53.5 24 53.5 53.6 0 14.2-5.6 27.8-15.7 37.9-10.1 9.9-23.7 15.6-37.9 15.6zM561.7 258.5v369.7c0 33.2-16.6 49.7-49.7 49.7s-49.7-16.6-49.7-49.7V258.5c0-33.2 16.6-49.7 49.7-49.7 33.1-0.1 49.7 16.5 49.7 49.7z" fill="#FFFFFF" p-id="4578"></path></svg>

After

Width:  |  Height:  |  Size: 763 B

View File

@@ -0,0 +1,50 @@
import layout from '@/views/app/layout/index.vue'
const applicationManagementRouter = [
{
path: '/applicationManagement',
component: layout,
redirect: '/applicationManagement/employRule',
name: 'ApplicationManagement',
meta: { title: '应用管理', icon: 'el-icon-s-management' },
children: [
{
path: 'employRule',
name: 'EmployRule',
component: () =>
import('@/views/applicationManagement/employRule/index.vue'),
meta: { title: '雇则风筛规则', icon: 'el-icon-setting' }
},
{
path: 'employRecord',
name: 'EmployRecord',
component: () =>
import('@/views/applicationManagement/employRecord/index.vue'),
meta: { title: '雇则风筛记录', icon: 'el-icon-document' }
},
{
path: 'employRecord/detail',
name: 'EmployRecordDetail',
component: () =>
import('@/views/applicationManagement/employRecord/detail.vue'),
meta: { title: '风筛记录详情' },
hidden: true // 隐藏在菜单中显示
},
{
path: 'taDataSubmit',
name: 'taDataSubmit',
component: () => import('@/views/riskCheck/taDataSubmit.vue'),
meta: { title: '模拟表单提交', icon: 'el-icon-document' }
},
{
path: 'riskResult',
name: 'RiskResult',
component: () => import('@/views/riskCheck/riskResult.vue'),
meta: { title: '模拟风险筛查结果' },
hidden: true // 隐藏在菜单中显示
}
]
}
]
export default applicationManagementRouter

View File

@@ -2,10 +2,15 @@ import Vue from 'vue'
import Router from 'vue-router'
import App from './app/index'
import generatedRouter from './generatedRouter'
import applicationManagementRouter from './generatedRouter/applicationManagement'
Vue.use(Router)
export const constantRouterMap = [...App, ...generatedRouter] // 静态路由
export const constantRouterMap = [
...App,
...generatedRouter,
...applicationManagementRouter
] // 静态路由
export default new Router({
mode: 'hash', //路由模式
base: process.env.BASE_URL,

View File

@@ -38,14 +38,59 @@ const actions = {
},
// user login
login({ commit }, userInfo) {
const { userName, password } = userInfo
const { userName, password, captcha, captchaKey } = userInfo
return new Promise((resolve, reject) => {
login({ userName: userName.trim(), password: password })
login({
userName: userName.trim(),
password: password,
captcha: captcha ? captcha : undefined,
captchaKey: captchaKey ? captchaKey : undefined
})
.then(res => {
setToken(res.content.content)
commit('SET_TOKEN', res.content.content)
// getInfo()
resolve()
let numberResult = Number(res.content.result)
if (numberResult !== 0) {
switch (numberResult) {
case 51001:
// 需要发送 短信验证码
resolve({
code: numberResult
})
break
case 50024:
// 需要验证码
resolve({
code: numberResult,
message: res.content.resultMessage
})
break
case 51003:
// 需要验证码
resolve({
code: numberResult,
message: res.content.resultMessage
})
break
case 51004:
setToken(res.content.content)
commit('SET_TOKEN', res.content.content)
// 临期提示
resolve({
...res.content,
code: numberResult
})
break
default:
reject(res.content)
break
}
} else {
setToken(res.content.content)
commit('SET_TOKEN', res.content.content)
resolve({
...res.content,
code: 0
})
}
})
.catch(error => {
reject(error)

View File

@@ -3,7 +3,12 @@
<div class="home-container">
<div class="home-top-container flex align-items-c justify-content-b">
<div class="left-container">
<span class="title">你好{{ userInfo.realName }}</span>
<span class="title"
>你好{{ userInfo.realName }}
<span class="role-info ml10" v-if="tipMessage" style="color:red">
{{ tipMessage }}
</span></span
>
<div class="subtitle">欢迎使用{{ title }}</div>
<div class="role-info">
当前角色{{
@@ -161,6 +166,7 @@ export default {
name: 'Home',
data() {
return {
tipMessage: sessionStorage.getItem('tipMessage') || '',
MatchId: 0,
options: {
title: {
@@ -454,6 +460,9 @@ export default {
height: 100%;
overflow-y: auto;
overflow-x: hidden;
&::-webkit-scrollbar {
display: none;
}
.home-top-container {
margin-bottom: 10px;
padding: 20px;

View File

@@ -59,6 +59,34 @@
<!-- />-->
</span>
</el-form-item>
<el-form-item class="login-input" prop="captcha" v-if="captchaImage">
<div class="flex">
<el-input
v-model="loginForm.captcha"
type="text"
tabindex="1"
auto-complete="on"
placeholder="请输入验证码"
>
<template slot="append">
<div
class="flex align-items-c justify-content-c text-center"
style="width: 100px;height: 100%"
>
<img
:src="captchaImage"
alt=""
width="100%"
@click="getCaptChaCode()"
/>
<!-- <img src="" alt="" width="100%" />-->
</div>
</template>
</el-input>
</div>
</el-form-item>
</el-form>
<div style="height: 127px"></div>
<div>
@@ -83,15 +111,38 @@
</p>
<!-- <p>京公网安备 ICP许可证号津ICP备14004859号-4</p>-->
</div>
<send-phone-code
:visible.sync="dialogVisible"
:user-name="loginForm.userName"
@handleSubmit="handleSubmit"
></send-phone-code>
<reset-password-dialog
:visible.sync="resetPasswordVisible"
:hideDialog="true"
:isLogin="true"
:user-name="loginForm.userName"
@getResult="getResult"
></reset-password-dialog>
</div>
</template>
<script>
import { validUsername } from '@/assets/js/utils/validate.js'
import xing from '@/assets/images/xing.png'
import {
sendPhoneCodeLogin,
verify_login,
getCaptchaImage
} from '@/api/app/user'
import { setToken } from '@/assets/js/utils/auth'
import uuid from 'uuid'
import ResetPasswordDialog from '@/views/system/user/components/ResetPasswordDialog.vue'
// import { indexUser } from '@/api/app/user'
export default {
name: 'Login',
components: { ResetPasswordDialog },
data() {
const validateuserName = (rule, value, callback) => {
if (!validUsername(value)) {
@@ -107,11 +158,39 @@ export default {
callback()
}
}
const validatePhone = (rule, value, callback) => {
// 手机号正则
const validPhone = phone => {
return /^1[3456789]\d{9}$/.test(phone)
}
if (!validPhone(value)) {
callback(new Error('请输入正确的手机号'))
} else {
callback()
}
}
return {
xing,
captchaImage: '',
sendCode: true,
captchaKey: '',
phoneRules: {
phone: [
{ required: true, message: '请输入手机号', trigger: 'change' },
{ validator: validatePhone, trigger: 'change' }
],
code: [{ required: true, message: '请输入验证码', trigger: 'change' }]
},
phoneForm: {
phone: '',
code: ''
},
dialogVisible: false,
loginForm: {
userName: '',
password: ''
password: '',
captcha: ''
},
loginRules: {
userName: [
@@ -119,11 +198,14 @@ export default {
],
password: [
{ required: true, trigger: 'blur', validator: validatePassword }
]
],
captcha: [{ required: true, trigger: 'blur', message: '请输入验证码' }]
},
loading: false,
passwordType: 'password',
redirect: undefined
redirect: undefined,
resetPasswordVisible: false,
minute: 120 // 默认120秒 发送间隔
}
},
watch: {
@@ -149,6 +231,56 @@ export default {
}
},
methods: {
getCaptChaCode() {
this.captchaKey = uuid.v4()
this.captchaImage = getCaptchaImage({ captchaKey: this.captchaKey })
},
sendCodeText() {
// 倒计时 60S
this.minute = 120
this.timer = setInterval(() => {
this.minute--
if (this.minute <= 0) {
this.sendCode = true
clearInterval(this.timer)
}
}, 1000)
return this.minute
},
sendPhoneCode() {
sendPhoneCodeLogin({
userName: this.loginForm.userName
}).then(res => {
if (Number(res.code) === 0) {
this.sendCode = false
this.sendCodeText()
}
})
},
getResult() {
this.getCaptChaCode()
this.loginForm.password = ''
this.loginForm.captcha = ''
},
handleSubmit(code) {
verify_login({
smsCode: code,
userName: this.loginForm.userName
}).then(vali => {
if (Number(vali.code) === 0) {
this.$store.commit('user/SET_TOKEN', vali.content.content.sid)
setToken(vali.content.content.sid)
localStorage.setItem('deviceId', vali.content.content.deviceId)
this.$router.push({ path: '/home' })
this.loading = false
}
})
},
showPwd() {
if (this.passwordType === 'password') {
this.passwordType = ''
@@ -171,13 +303,54 @@ export default {
this.$refs.loginForm.validate(valid => {
if (valid) {
this.loading = true
if (this.captchaKey) {
this.loginForm.captchaKey = this.captchaKey
}
this.$store
.dispatch('user/login', this.loginForm)
.then(() => {
this.$router.push({ path: '/home' })
this.loading = false
.then(res => {
console.log(res)
if (res.code === 0 || res.code === 51004) {
sessionStorage.setItem('tipMessage', '')
if (res.code === 51004) {
sessionStorage.setItem(
'tipMessage',
res.resultMessage ? res.resultMessage : ''
)
}
this.$router.push({ path: '/home' })
this.loading = false
return
}
// 发送短信验证码
if (res.code === 51001) {
this.dialogVisible = true
this.loading = false
// this.sendPhoneCode()
}
// 展示验证码
if (res.code === 50024) {
this.loading = false
if (res.message) {
this.$message.error(res.message)
}
this.getCaptChaCode()
}
// 强制修改密码
if (res.code === 51003) {
this.loading = false
this.resetPasswordVisible = true
}
})
.catch(() => {
.catch(err => {
if (this.captchaKey) {
this.getCaptChaCode()
}
this.$message.error(
err.resultMessage
? err.resultMessage
: '当前网络繁忙,请稍后再试'
)
this.loading = false
})
} else {
@@ -185,6 +358,9 @@ export default {
}
})
}
},
created() {
// this.getCaptChaCode()
}
}
</script>
@@ -192,13 +368,14 @@ export default {
<style lang="scss">
/* 修复input 背景不协调 和光标变色 */
/* Detail see https://github.com/PanJiaChen/vue-element-admin/pull/927 */
@import '../../../assets/sass/renderSass/theme.scss';
$bg: #283443;
$light_gray: #fff;
$cursor: #fff;
@supports (-webkit-mask: none) and (not (cater-color: $cursor)) {
.login-container .el-input input {
.login-form .el-input input {
color: $cursor;
}
}
@@ -258,8 +435,17 @@ $cursor: #fff;
&:focus {
border: 1px solid #4f47f5;
~ .el-input-group__append {
//border: 1px solid #4f47f5;
//border-left: none;
}
}
}
& .el-input-group__append {
border-radius: 0 10px 10px 0;
background: transparent;
border: none;
}
}
// 添加 :focus-within 伪类来改变 el-form-item__label 的颜色
@@ -270,6 +456,8 @@ $cursor: #fff;
</style>
<style lang="scss" scoped>
@import '../../../assets/sass/renderSass/theme.scss';
$bg: #2d3a4b;
$dark_gray: #889aa4;
$light_gray: #eee;

View File

@@ -0,0 +1,123 @@
<template>
<div class="render-container employ-record-detail">
<div class="header flex align-items-c">
<BackButton></BackButton>
<div class="ml10 fs14 fw600">风筛记录详情</div>
<!-- <el-page-header @back="goBack" content="风筛记录详情"> </el-page-header>-->
</div>
<div class="iframe-container">
<!-- 使用iframe展示详情内容 -->
<iframe
v-if="detailUrl"
:src="detailUrl"
frameborder="0"
width="100%"
height="800px"
>
</iframe>
<!-- 加载提示 -->
<div v-if="loading" class="loading">
<i class="el-icon-loading"></i>
<p>正在加载详情内容...</p>
</div>
<!-- 无数据提示 -->
<div v-if="!detailUrl && !loading" class="no-data">
<p>暂无详情内容</p>
</div>
</div>
</div>
</template>
<script>
import { getResultHtml } from '@/api/riskCheck'
export default {
name: 'EmployRecordDetail',
data() {
return {
// 详情页面URL
detailUrl: getResultHtml({ taCode: this.$route.query.taCode }),
// 加载状态
loading: true,
// 记录ID
recordId: ''
}
},
created() {
// 获取路由参数
// 模拟设置详情URL实际项目中应该根据recordId从API获取真实URL
if (this.$route.query.taCode) {
// 示例URL实际应根据recordId获取对应的详情页面URL
this.detailUrl = `${this.iframeSrc}/bpic_eli/risk_history.html?taCode=${
this.$route.query.taCode
}&ip=${process.env.VUE_APP_ADMIN}&noPT=true`
}
// 模拟加载完成
setTimeout(() => {
this.loading = false
}, 500)
},
props: {
iframeSrc: {
type: String,
default: () => window.location.origin
}
},
methods: {
// 返回上一页
goBack() {
this.$router.go(-1)
}
}
}
</script>
<style lang="scss" scoped>
.employ-record-detail {
//padding: 20px;
background-color: #fff;
display: flex;
flex-direction: column;
.header {
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #ebeef5;
}
.iframe-container {
position: relative;
background: #f0f4fa;
padding: 10px;
border-radius: 10px;
flex: 1;
iframe {
height: 100%;
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
color: #909399;
.el-icon-loading {
font-size: 30px;
margin-bottom: 10px;
}
}
.no-data {
text-align: center;
color: #909399;
padding: 50px 0;
}
}
}
</style>

View File

@@ -0,0 +1,350 @@
<!--
雇则风筛记录页面
功能包括
1. 记录列表展示支持分页
2. 多条件查询审批单号被保险人名称名称归属机构提交时间
3. 记录操作查看详情
-->
<template>
<div class="render-container employ-record">
<!-- 查询条件区域 -->
<div class="filter-container">
<div class="flex align-items-c justify-content-b">
<el-form
:model="queryParams"
label-width="100px"
label-position="top"
ref="queryParams"
inline
>
<!-- 审批单号输入框 -->
<el-form-item label="审批单号" prop="approvalNo">
<el-input
v-model="queryParams.approvalNo"
size="medium"
placeholder="请输入审批单号"
></el-input>
</el-form-item>
<!-- 被保险人名称名称输入框 -->
<el-form-item label="被保险人名称" prop="insuredNameLike">
<el-input
v-model="queryParams.insuredNameLike"
size="medium"
placeholder="请输入被保险人名称"
></el-input>
</el-form-item>
<!-- 归属机构下拉选择 -->
<el-form-item label="归属机构" prop="institution">
<el-select
v-model="queryParams.institution"
size="medium"
clearable
placeholder="请选择归属机构"
>
<el-option
v-for="item in institutionList"
:label="item.label"
:value="item.value"
:key="item.value"
></el-option>
</el-select>
</el-form-item>
<!-- 提交时间范围选择 -->
<el-form-item label="提交时间" prop="submitTime">
<el-date-picker
v-model="queryParams.submitTime"
size="medium"
type="datetimerange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="yyyy-MM-dd HH:mm:ss"
>
</el-date-picker>
</el-form-item>
</el-form>
<!-- 查询操作按钮 -->
<div class="mt15 flex align-items-c justify-content-b">
<el-button size="medium" type="primary" @click="handleQuery"
>查询</el-button
>
<el-button size="medium" @click="resetQuery">重置</el-button>
</div>
</div>
</div>
<!-- 记录列表表格 -->
<r-table
@sort-change="sortChange"
:columns="tableConfig.columns"
:data="tableData"
border
class="employ-table"
:deletion="false"
:total="tableConfig.total"
@currentChange="handleCurrentChange"
@sizeChange="handleSizeChange"
:currentPage="tableConfig.currentPage"
:pageSize="tableConfig.pageSize"
/>
</div>
</template>
<script>
import { getRecordPage } from '@/api/riskCheck/record'
import { getOrganizationList } from '@/api/riskCheck/rule'
export default {
name: 'EmployRecord',
data() {
return {
loading: false,
// 查询参数
queryParams: {
page: 1,
pageSize: 10,
approvalNo: '',
insuredNameLike: '',
institution: '',
submitTimeStart: '',
submitTimeEnd: '',
submitTime: []
},
// 归属机构选项列表
institutionList: [],
// 表格配置项
tableConfig: {
total: 0,
currentPage: 1,
pageSize: 10,
columns: [
{ type: 'index', key: '序号', width: 60 },
{ prop: 'taCode', key: '审批单号', sortable: 'custom', width: '150' },
{
prop: 'insuredName',
key: '被保险人名称',
sortable: 'custom',
width: '150'
},
{
prop: 'orgName',
key: '归属机构',
sortable: 'custom',
width: '150'
},
{ prop: 'insurePeriod', key: '保险期限' },
{ prop: 'taLatestSubmitDate', key: '提交时间', sortable: 'custom' },
{
key: '操作',
isRedraw: true,
width: '100',
fixed: 'right',
render: (h, params) => {
return h('div', [
// 查看详情按钮
h(
'el-button',
{
props: {
type: 'text',
size: 'mini',
icon: 'el-icon-view',
title: '查看详情'
},
class: 'normal-button',
on: { click: () => this.handleView(params.row) }
},
''
),
// 编辑按钮
h('el-button', {
props: {
type: 'text',
size: 'mini',
icon: 'el-icon-paperclip',
title: '打开风险结果'
},
class: 'normal-button',
on: {
click: p => {
window.open(
`${
window.location.origin
}/bpic_eli/risk_history.html?taCode=${
params.row.taCode
}`
)
}
}
})
])
}
}
]
},
// 表格数据
tableData: []
}
},
created() {
this.getList()
this.getInstitutionList()
},
methods: {
sortChange(val) {
// 处理排序逻辑
const { prop, order } = val
let orderDTOs = [
{
columnName: prop,
orderType: order === 'ascending' ? 1 : 2
}
]
this.getList(orderDTOs)
},
// 获取归属机构数据
// getAllOrgNames() {
// getAllOrgNames()
// .then(response => {
// if (response && response.content && response.content.content) {
// // 根据实际API返回结构调整
// const orgData = response.content.content || []
// // 将返回的数据转换为下拉选项需要的格式
// this.institutionList = orgData.map(item => {
// return {
// label: item,
// value: item
// }
// })
// }
// })
// .catch(error => {
// this.$message.error(
// '获取归属机构数据失败: ' + (error.message || '未知错误')
// )
// })
// },
// 获取记录列表数据
getList(orderDTOs) {
this.loading = true
const params = Object.assign({}, this.queryParams)
// 处理时间范围参数
if (params.submitTime && params.submitTime.length === 2) {
params.startTaLatestSubmitDate = params.submitTime[0]
params.endTaLatestSubmitDate = params.submitTime[1]
}
params.orgNameLike = params.institution
// params.insuredNameLike = params.insuredName
params.taCodeLike = params.approvalNo
delete params.submitTime
delete params.institution
delete params.approvalNo
params.orderDTOs = orderDTOs ? orderDTOs : []
getRecordPage(params)
.then(response => {
if (response) {
// 根据实际API返回结构调整兼容Vue2语法
const content = response.content.content || {}
this.tableData = content.list || []
this.tableConfig.total = content.total || 0
this.tableData.forEach(v => {
const startDate = v.insureStartDate
const endDate = v.insureEndDate
let insurePeriod = ''
if (startDate && endDate) {
const startStr =
typeof startDate === 'string'
? startDate.substring(0, 10)
: ''
const endStr =
typeof endDate === 'string' ? endDate.substring(0, 10) : ''
insurePeriod = `${startStr} - ${endStr}`
}
v.insurePeriod = insurePeriod
})
}
})
.catch(error => {
this.$message.error(
'获取记录列表失败: ' + (error.message || '未知错误')
)
})
.finally(() => {
this.loading = false
})
},
// 查询按钮点击事件
handleQuery() {
this.queryParams.page = 1
this.getList()
},
// 重置按钮点击事件
resetQuery() {
this.$refs.queryParams.resetFields()
this.handleQuery()
},
// 查看详情按钮点击事件
handleView(row) {
// 打开新页面展示详情使用iframe方式
this.$router.push({
path: '/applicationManagement/employRecord/detail',
query: { taCode: row.taCode }
})
// window.open(routeData.href, '_blank')
},
// 分页大小改变事件
handleSizeChange(val) {
this.queryParams.pageSize = val
this.getList()
},
// 当前页码改变事件
handleCurrentChange(val) {
this.queryParams.page = val
this.getList()
},
// 获取归属机构列表
getInstitutionList() {
getOrganizationList({}).then(response => {
if (response) {
const orgData = response.content.content || []
this.institutionList = orgData.map(item => ({
label: item.orgName,
value: item.orgName
}))
}
})
}
}
}
</script>
<style lang="scss" scoped>
.employ-record {
padding: 20px;
.filter-container {
margin-bottom: 20px;
.el-form-item {
margin-bottom: 10px;
margin-right: 10px;
.el-form-item__label {
padding-right: 8px;
}
}
}
}
</style>

View File

@@ -0,0 +1,404 @@
<template>
<el-dialog
:title="dialogTitle"
:visible.sync="dialogVisible"
width="800px"
@close="handleClose"
>
<el-form
ref="ruleForm"
:model="ruleForm"
:rules="rules"
label-width="120px"
v-loading="loading"
>
<!-- 规则类型下拉选择 -->
<el-form-item label="规则类型" prop="ruleType">
<el-select
v-model="ruleForm.ruleType"
placeholder="请选择规则类型"
style="width: 100%"
@change="handleRuleTypeChange"
>
<el-option
v-for="item in ruleTypeList"
:key="item.typeCode"
:label="item.typeName"
:value="item.typeName"
>
</el-option>
</el-select>
</el-form-item>
<!-- 字段类型下拉选择 -->
<el-form-item label="字段类型" prop="ruleField">
<el-select
v-model="ruleForm.ruleField"
placeholder="请选择字段类型"
style="width: 100%"
@visible-change="clickRuleField"
>
<el-option
v-for="item in filteredFieldTypeList"
:key="item.fieldName"
:label="item.fieldComment"
:value="item.fieldName"
>
</el-option>
</el-select>
</el-form-item>
<!-- 规则描述文本域 -->
<el-form-item label="规则描述" prop="ruleDesc">
<el-input
type="textarea"
v-model="ruleForm.ruleDesc"
placeholder="请输入规则描述"
:rows="3"
></el-input>
</el-form-item>
<!-- 风险提示话术输入框 -->
<el-form-item label="风险提示话术" prop="riskScript">
<el-input
v-model="ruleForm.riskScript"
placeholder="请输入风险提示话术"
></el-input>
</el-form-item>
<!-- 校验内容类型 -->
<!-- <el-form-item label="校验内容类型" prop="checkType">-->
<!-- <el-select -->
<!-- v-model="ruleForm.checkType" -->
<!-- placeholder="请选择校验内容类型" -->
<!-- style="width: 100%"-->
<!-- >-->
<!-- <el-option label="表单信息" :value="1"></el-option>-->
<!-- <el-option label="文本文件" :value="2"></el-option>-->
<!-- <el-option label="图片" :value="3"></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- &lt;!&ndash; 风险类型 &ndash;&gt;-->
<!-- <el-form-item label="风险类型" prop="riskType">-->
<!-- <el-select -->
<!-- v-model="ruleForm.riskType" -->
<!-- placeholder="请选择风险类型" -->
<!-- style="width: 100%"-->
<!-- >-->
<!-- <el-option-->
<!-- v-for="item in riskTypeList"-->
<!-- :key="item.riskTypeCode"-->
<!-- :label="item.riskType"-->
<!-- :value="item.riskTypeCode">-->
<!-- </el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- &lt;!&ndash; 运行类型 &ndash;&gt;-->
<!-- <el-form-item label="运行类型" prop="runType">-->
<!-- <el-radio-group v-model="ruleForm.runType">-->
<!-- <el-radio label="ai">AI</el-radio>-->
<!-- <el-radio label="func">函数</el-radio>-->
<!-- </el-radio-group>-->
<!-- </el-form-item>-->
</el-form>
<span slot="footer" class="dialog-footer">
<el-button
type="primary"
@click="handleSubmit"
:loading="submitLoading"
size="medium"
> </el-button
>
<el-button @click="handleClose" size="medium"> </el-button>
</span>
</el-dialog>
</template>
<script>
import { createRule, updateRule, queryRuleDetail } from '@/api/riskCheck/rule'
export default {
name: 'RuleEditDialog',
props: {
// 对话框是否可见
visible: {
type: Boolean,
default: false
},
// 是否为编辑模式
isEdit: {
type: Boolean,
default: false
},
// 当前规则数据
ruleData: {
type: Object,
default: () => ({})
},
// 规则类型选项列表
ruleTypeOptions: {
type: Array,
default: () => []
},
// 字段类型选项列表
fieldTypeOptions: {
type: Array,
default: () => []
},
// 风险类型选项列表
riskTypeOptions: {
type: Array,
default: () => []
}
},
data() {
return {
loading: false,
submitLoading: false,
// 表单数据
ruleForm: {
id: '',
ruleType: '',
ruleField: '',
ruleDesc: '',
riskScript: '',
checkType: 1,
riskType: '',
ruleStatus: 1,
runType: 'ai'
},
filteredFieldTypeList: [],
// 表单验证规则
rules: {
ruleType: [
{ required: true, message: '请选择规则类型', trigger: 'change' }
],
ruleField: [
{ required: true, message: '请选择字段类型', trigger: 'change' }
],
ruleDesc: [
{ required: true, message: '请输入规则描述', trigger: 'blur' },
{
min: 1,
max: 1000,
message:
'规则描述支持录入汉字、大写字母、小写字母、数字、符号不超过1000个字请重新输入',
trigger: 'blur'
}
],
riskScript: [
{ required: true, message: '请输入风险提示话术', trigger: 'blur' },
{
min: 1,
max: 100,
message:
'风险提示话术支持录入汉字、大写字母、小写字母、数字、符号不超过100个字请重新输入',
trigger: 'blur'
}
],
checkType: [
{ required: true, message: '请选择校验内容类型', trigger: 'change' }
],
riskType: [
{ required: true, message: '请选择风险类型', trigger: 'change' }
],
runType: [
{ required: true, message: '请选择运行类型', trigger: 'change' }
]
}
}
},
computed: {
// 对话框标题
dialogTitle() {
return this.isEdit ? '编辑规则' : '新增规则'
},
// 对话框可见性
dialogVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
},
// 规则类型选项列表
ruleTypeList() {
return this.ruleTypeOptions.length > 0
? this.ruleTypeOptions
: [
{ typeName: '基本信息', typeCode: 'basic_rule' },
{ typeName: '投保信息', typeCode: 'insurance_rule' }
]
},
// 字段类型选项列表
fieldTypeList() {
return this.fieldTypeOptions.length > 0
? this.fieldTypeOptions
: [
{ fieldComment: '保险期限(天)', fieldName: 'insurance_period' },
{ fieldComment: '投保金额', fieldName: 'insurance_amount' }
]
},
// 风险类型选项列表
riskTypeList() {
return this.riskTypeOptions.length > 0
? this.riskTypeOptions
: [
{
riskType: '费率与投保方案不合理风险',
riskTypeCode: 'rate_plan_risk'
},
{
riskType: '保险责任不明确风险',
riskTypeCode: 'insurance_liability_risk'
}
]
}
},
watch: {
// 监听规则数据变化
ruleData: {
handler(val) {
if (val && Object.keys(val).length > 0) {
this.ruleForm = Object.assign({}, val)
console.log(this.ruleForm)
} else {
this.ruleForm = {
id: '',
ruleType: '',
ruleField: '',
ruleDesc: '',
riskScript: '',
checkType: 1,
riskType: '',
ruleStatus: 1,
runType: 'ai'
}
}
},
immediate: true
},
// 监听规则类型列表变化
ruleTypeList: {
handler() {
this.updateFieldTypeList()
},
immediate: true
},
// 监听规则类型选择变化
'ruleForm.ruleType': {
handler() {
this.updateFieldTypeList()
},
immediate: true,
deep: true
}
},
methods: {
clickRuleField(v) {
console.log(v)
if (v) {
if (!this.ruleForm.ruleType) {
this.$message.error('请先选择规则类型')
}
}
},
// 更新字段类型列表
updateFieldTypeList() {
// 如果规则类型列表为空,设置字段类型列表为空数组
if (!this.ruleTypeList || this.ruleTypeList.length === 0) {
this.filteredFieldTypeList = []
return
}
// 如果未选择规则类型,返回所有字段类型
if (!this.ruleForm.ruleType) {
this.filteredFieldTypeList = []
return
}
const ruleType = this.ruleTypeList.find(
item => item.typeName === this.ruleForm.ruleType
)
if (ruleType) {
console.log(ruleType, 1)
this.filteredFieldTypeList = this.fieldTypeList.filter(item => {
console.log(item)
return item.ruleTypeId === ruleType.id
})
console.log(this.filteredFieldTypeList)
} else {
this.filteredFieldTypeList = []
}
},
// 关闭对话框
handleClose() {
this.$refs.ruleForm.resetFields()
this.$emit('update:visible', false)
},
// 处理规则类型变更事件,与主页面保持一致效果
handleRuleTypeChange(value) {
this.ruleForm.ruleField = ''
// 更新已由watch处理无需额外操作
this.updateFieldTypeList()
},
// 提交表单
handleSubmit() {
this.$refs.ruleForm.validate(valid => {
if (valid) {
this.submitLoading = true
// 根据是否为编辑模式调用不同接口
const request = this.isEdit ? updateRule : createRule
// 创建提交参数的副本
const params = Object.assign({}, this.ruleForm)
// 将ruleType的值转换为对应的中文typeName
const selectedRuleType = this.ruleTypeList.find(
item => item.typeCode === params.ruleType
)
if (selectedRuleType) {
params.ruleType = selectedRuleType.typeName
}
// 将ruleField的值转换为对应的中文fieldComment
const selectedFieldType = this.fieldTypeList.find(
item => item.fieldName === params.ruleField
)
if (selectedFieldType) {
params.ruleField = selectedFieldType.fieldComment
}
request(params)
.then(response => {
this.$message.success(`${this.dialogTitle}成功`)
this.$emit('success', response)
this.handleClose()
})
.catch(error => {
this.$message.error(
`${this.dialogTitle}失败: ` + (error.message || '未知错误')
)
})
.finally(() => {
this.submitLoading = false
})
}
})
}
}
}
</script>
<style lang="scss" scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,246 @@
<template>
<el-dialog
title="查看规则"
:visible.sync="dialogVisible"
width="800px"
@close="handleClose"
>
<el-form
ref="ruleForm"
:model="ruleForm"
label-width="120px"
v-loading="loading"
>
<!-- 规则类型 -->
<el-form-item label="规则类型">
<el-select
v-model="ruleForm.ruleType"
placeholder="请选择规则类型"
style="width: 100%"
disabled
>
<el-option
v-for="item in ruleTypeList"
:key="item.typeCode"
:label="item.typeName"
:value="item.typeCode"
>
</el-option>
</el-select>
</el-form-item>
<!-- 字段类型 -->
<el-form-item label="字段类型">
<el-select
v-model="ruleForm.ruleField"
placeholder="请选择字段类型"
style="width: 100%"
disabled
>
<el-option
v-for="item in fieldTypeList"
:key="item.fieldName"
:label="item.fieldComment"
:value="item.fieldName"
>
</el-option>
</el-select>
</el-form-item>
<!-- 规则描述 -->
<el-form-item label="规则描述">
<el-input
type="textarea"
v-model="ruleForm.ruleDesc"
placeholder="请输入规则描述"
:rows="3"
disabled
></el-input>
</el-form-item>
<!-- 风险提示话术 -->
<el-form-item label="风险提示话术">
<el-input
v-model="ruleForm.riskScript"
placeholder="请输入风险提示话术"
disabled
></el-input>
</el-form-item>
<!-- &lt;!&ndash; 校验内容类型 &ndash;&gt;-->
<!-- <el-form-item label="校验内容类型">-->
<!-- <el-select -->
<!-- v-model="ruleForm.checkType" -->
<!-- placeholder="请选择校验内容类型" -->
<!-- style="width: 100%"-->
<!-- disabled-->
<!-- >-->
<!-- <el-option label="表单信息" :value="1"></el-option>-->
<!-- <el-option label="文本文件" :value="2"></el-option>-->
<!-- <el-option label="图片" :value="3"></el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- &lt;!&ndash; 风险类型 &ndash;&gt;-->
<!-- <el-form-item label="风险类型">-->
<!-- <el-select -->
<!-- v-model="ruleForm.riskType" -->
<!-- placeholder="请选择风险类型" -->
<!-- style="width: 100%"-->
<!-- disabled-->
<!-- >-->
<!-- <el-option-->
<!-- v-for="item in riskTypeList"-->
<!-- :key="item.riskTypeCode"-->
<!-- :label="item.riskType"-->
<!-- :value="item.riskTypeCode">-->
<!-- </el-option>-->
<!-- </el-select>-->
<!-- </el-form-item>-->
<!-- &lt;!&ndash; 运行类型 &ndash;&gt;-->
<!-- <el-form-item label="运行类型">-->
<!-- <el-radio-group v-model="ruleForm.runType" disabled>-->
<!-- <el-radio label="ai">AI</el-radio>-->
<!-- <el-radio label="func">函数</el-radio>-->
<!-- </el-radio-group>-->
<!-- </el-form-item>-->
<!-- 规则状态 -->
<!-- <el-form-item label="规则状态">-->
<!-- <el-switch-->
<!-- v-model="ruleForm.ruleStatus"-->
<!-- :active-value="1"-->
<!-- :inactive-value="0"-->
<!-- active-text="启用"-->
<!-- inactive-text="未启用"-->
<!-- disabled-->
<!-- >-->
<!-- </el-switch>-->
<!-- </el-form-item>-->
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handleClose" size="medium"> </el-button>
</span>
</el-dialog>
</template>
<script>
import { queryRuleDetail } from '@/api/riskCheck/rule'
export default {
name: 'RuleViewDialog',
props: {
// 对话框是否可见
visible: {
type: Boolean,
default: false
},
// 当前规则数据
ruleData: {
type: Object,
default: () => ({})
},
// 规则类型选项列表
ruleTypeOptions: {
type: Array,
default: () => []
},
// 字段类型选项列表
fieldTypeOptions: {
type: Array,
default: () => []
},
// 风险类型选项列表
riskTypeOptions: {
type: Array,
default: () => []
}
},
data() {
return {
loading: false,
// 表单数据
ruleForm: {
id: '',
ruleType: '',
ruleField: '',
ruleDesc: '',
riskScript: '',
checkType: 1,
riskType: '',
ruleStatus: 0,
runType: 'ai'
}
}
},
computed: {
// 对话框可见性
dialogVisible: {
get() {
return this.visible
},
set(val) {
this.$emit('update:visible', val)
}
},
// 规则类型选项列表
ruleTypeList() {
return this.ruleTypeOptions.length > 0
? this.ruleTypeOptions
: [
{ typeName: '基本信息', typeCode: 'basic_rule' },
{ typeName: '投保信息', typeCode: 'insurance_rule' }
]
},
// 字段类型选项列表
fieldTypeList() {
return this.fieldTypeOptions.length > 0
? this.fieldTypeOptions
: [
{ fieldComment: '保险期限(天)', fieldName: 'insurance_period' },
{ fieldComment: '投保金额', fieldName: 'insurance_amount' }
]
},
// 风险类型选项列表
riskTypeList() {
return this.riskTypeOptions.length > 0
? this.riskTypeOptions
: [
{
riskType: '费率与投保方案不合理风险',
riskTypeCode: 'rate_plan_risk'
},
{
riskType: '保险责任不明确风险',
riskTypeCode: 'insurance_liability_risk'
}
]
}
},
watch: {
// 监听规则数据变化
ruleData: {
handler(val) {
if (val && Object.keys(val).length > 0) {
this.ruleForm = Object.assign({}, val)
}
},
immediate: true
}
},
methods: {
// 关闭对话框
handleClose() {
this.$emit('update:visible', false)
}
}
}
</script>
<style lang="scss" scoped>
.dialog-footer {
text-align: right;
}
</style>

View File

@@ -0,0 +1,727 @@
<!--
雇则风筛规则管理页面
功能包括
1. 规则列表展示支持分页
2. 多条件查询规则类型字段类型规则描述规则状态
3. 规则操作查看详情编辑删除启用/停用
-->
<template>
<div class="render-container employ-rule">
<!-- 查询条件区域 -->
<div class="filter-container">
<div class="flex align-items-c justify-content-b">
<el-form
:model="queryParams"
label-width="100px"
label-position="top"
ref="queryParams"
inline
>
<!-- 规则类型下拉选择 -->
<el-form-item label="规则类型" prop="ruleType">
<el-select
v-model="queryParams.ruleType"
size="medium"
clearable
placeholder="请选择规则类型"
@change="handleRuleTypeChange"
>
<el-option value="" label="全部"></el-option>
<el-option
v-for="item in ruleTypeList"
:label="item.typeName"
:value="item.typeCode"
:key="item.typeCode"
></el-option>
</el-select>
</el-form-item>
<!-- 字段类型下拉选择 -->
<el-form-item label="字段类型" prop="ruleField">
<el-select
v-model="queryParams.ruleField"
size="medium"
clearable
placeholder="请选择字段类型"
>
<el-option value="" label="全部"></el-option>
<el-option
v-for="item in fieldTypeListCopy"
:label="item.fieldComment"
:value="item.fieldName"
:key="item.id"
></el-option>
</el-select>
</el-form-item>
<!-- 规则描述输入框 -->
<el-form-item label="规则描述" prop="ruleDescLike">
<el-input
v-model="queryParams.ruleDescLike"
size="medium"
placeholder="请输入规则描述"
></el-input>
</el-form-item>
<!-- 规则状态下拉选择 -->
<el-form-item label="规则状态" prop="ruleStatus">
<el-select
v-model="queryParams.ruleStatus"
size="medium"
clearable
placeholder="请选择规则状态"
>
<el-option
v-for="item in statusList"
:label="item.label"
:value="item.value"
:key="item.value"
></el-option>
</el-select>
</el-form-item>
</el-form>
<!-- 查询操作按钮 -->
<div class="mt15 flex align-items-c justify-content-b">
<el-button size="medium" type="primary" @click="handleQuery"
>查询</el-button
>
<el-button size="medium" @click="resetQuery">重置</el-button>
<el-button
size="medium"
type="primary"
@click="handleAdd"
v-if="!isChildrenView"
>新增</el-button
>
</div>
</div>
</div>
<!-- 规则列表表格 -->
<r-table
class="employ-table"
border
:columns="tableConfig.columns"
:data="tableData"
:deletion="false"
:total="tableConfig.total"
@currentChange="handleCurrentChange"
@sizeChange="handleSizeChange"
:currentPage="tableConfig.currentPage"
:pageSize="tableConfig.pageSize"
@selection-change="$event => handleSelectionChange($event)"
ref="rTable"
@sort-change="sortChange"
:defaultSort="{ prop: 'ruleType' }"
/>
<!-- 规则编辑对话框 -->
<rule-edit-dialog
:visible.sync="editDialogVisible"
:is-edit="isEdit"
:rule-data="currentRuleData"
:rule-type-options="ruleTypeList"
:field-type-options="fieldTypeList"
:risk-type-options="riskTypeList"
@success="handleEditSuccess"
/>
<!-- 规则查看对话框 -->
<rule-view-dialog
:visible.sync="viewDialogVisible"
:rule-data="currentRuleData"
:rule-type-options="ruleTypeList"
:field-type-options="fieldTypeList"
:risk-type-options="riskTypeList"
/>
</div>
</template>
<script>
import {
getRulePage,
deleteRule,
batchSwitchStatus,
queryRuleDetail,
getRuleTypeList,
getFieldTypeList,
getRiskTypeList
} from '@/api/riskCheck/rule'
import RuleEditDialog from './components/RuleEditDialog.vue'
import RuleViewDialog from './components/RuleViewDialog.vue'
import _ from 'lodash'
export default {
name: 'EmployRule',
components: {
RuleEditDialog,
RuleViewDialog
},
props: {
isChildrenView: {
type: Boolean,
default: false
},
selectedRules: {
type: Array,
default: () => []
}
},
data() {
return {
loading: false,
// 编辑对话框是否可见
editDialogVisible: false,
// 查看对话框是否可见
viewDialogVisible: false,
// 是否为编辑模式
isEdit: false,
// 当前规则数据
currentRuleData: {},
// 查询参数
queryParams: {
page: 1,
pageSize: 10,
ruleType: '',
ruleField: '',
ruleDescLike: '',
ruleStatus: ''
},
// 规则类型选项列表
ruleTypeList: [],
// 字段类型选项列表
fieldTypeList: [],
fieldTypeListCopy: [],
// 风险类型选项列表
riskTypeList: [],
// 规则状态选项列表
statusList: [
{ label: '全部', value: '' },
{ label: '启用', value: 0 },
{ label: '停用', value: 1 }
],
// 表格配置项
tableConfig: {
total: 0,
currentPage: 1,
pageSize: 10,
columns: this.getColumnsConfig()
},
// 表格数据
tableData: []
}
},
watch: {
'queryParams.ruleType': {
handler: function(n) {
if (!n) {
this.fieldTypeListCopy = []
}
this.queryParams.ruleField = ''
}
}
},
created() {
this.getList()
this.getRuleTypeList()
this.getFieldTypeList()
this.getRiskTypeList()
},
methods: {
handleRuleTypeChange(value) {
let ruleType = this.ruleTypeList.filter(
item => item.typeCode === value
)[0]
if (ruleType) {
this.fieldTypeListCopy = this.fieldTypeList.filter(item => {
return item.ruleTypeId === ruleType.id
})
} else {
this.fieldTypeListCopy = []
}
},
// 获取规则列表数据
getList(orderDTOs) {
const queryParams = Object.assign({}, this.queryParams)
this.loading = true
// 如果ruleType是中文转换为编码值
if (queryParams && queryParams.ruleType) {
const ruleTypeItem = this.ruleTypeList.find(
item => item.typeCode === queryParams.ruleType
)
if (queryParams && ruleTypeItem) {
queryParams.ruleType = ruleTypeItem.typeName
}
}
// 如果ruleField是中文转换为编码值
if (queryParams && queryParams.ruleField) {
const fieldTypeItem = this.fieldTypeList.find(
item => item.fieldName === queryParams.ruleField
)
if (queryParams && fieldTypeItem) {
queryParams.ruleField = fieldTypeItem.fieldComment
}
}
queryParams.orderDTOs = orderDTOs ? orderDTOs : []
getRulePage(queryParams)
.then(response => {
// 根据实际API返回结构调整兼容Vue2语法
var content = response.content.content || {}
this.tableData = content.list || []
this.tableConfig.total = content.total || 0
this.$nextTick(() => {
if (this.selectedRules.length > 0) {
let arrays = []
this.tableData.map((item, Findex) => {
if (this.selectedRules[this.tableConfig.currentPage - 1]) {
this.selectedRules[this.tableConfig.currentPage - 1].map(
filt => {
if (filt.id === item.id) {
arrays.push(this.tableData[Findex])
}
}
)
}
})
setTimeout(() => {
this.$refs.rTable.toggleRowSelection(arrays)
}, 100)
} else {
this.$refs.rTable.clearSelection()
}
})
})
.catch(error => {
this.$message.error(
'获取规则列表失败: ' + (error.message || '未知错误')
)
})
.finally(() => {
this.loading = false
})
},
// 获取规则类型选项列表
getRuleTypeList() {
getRuleTypeList({})
.then(response => {
// 根据实际API返回结构调整兼容Vue2语法
const content = response.content || {}
this.ruleTypeList = content.content || []
})
.catch(error => {
this.$message.error(
'获取规则类型列表失败: ' + (error.message || '未知错误')
)
})
},
// 获取字段类型选项列表
getFieldTypeList() {
getFieldTypeList({})
.then(response => {
// 根据实际API返回结构调整兼容Vue2语法
const content = response.content || {}
this.fieldTypeList = content.content || []
})
.catch(error => {
this.$message.error(
'获取字段类型列表失败: ' + (error.message || '未知错误')
)
})
},
// 获取风险类型选项列表
getRiskTypeList() {
getRiskTypeList({})
.then(response => {
// 根据实际API返回结构调整兼容Vue2语法
const content = response.content || {}
this.riskTypeList = content.content || []
})
.catch(error => {
this.$message.error(
'获取风险类型列表失败: ' + (error.message || '未知错误')
)
})
},
// 查询按钮点击事件
handleQuery() {
this.queryParams.page = 1
// 创建查询参数的副本
// const queryParams = Object.assign({}, this.queryParams)
// 使用转换后的参数进行查询
// this.queryParams = queryParams
this.getList()
},
// 重置按钮点击事件
resetQuery() {
this.$refs.queryParams.resetFields()
this.handleQuery()
},
// 新增按钮点击事件
handleAdd() {
this.isEdit = false
this.currentRuleData = {}
this.editDialogVisible = true
},
// 查看详情按钮点击事件
handleView(row) {
this.loading = true
this.viewDialogVisible = true
// 获取规则详情
queryRuleDetail({ id: row.id })
.then(response => {
this.currentRuleData = response.content.content || {}
})
.catch(error => {
this.$message.error(
'获取规则详情失败: ' + (error.message || '未知错误')
)
this.viewDialogVisible = false
})
.finally(() => {
this.loading = false
})
},
// 编辑按钮点击事件
handleEdit(row) {
this.isEdit = true
this.loading = true
// 获取规则详情
queryRuleDetail({ id: row.id })
.then(response => {
this.currentRuleData = response.content.content || {}
this.editDialogVisible = true
})
.catch(error => {
this.$message.error(
'获取规则详情失败: ' + (error.message || '未知错误')
)
})
.finally(() => {
this.loading = false
})
},
// 编辑成功回调
handleEditSuccess() {
this.getList() // 刷新列表
},
// 启用/停用按钮点击事件
handleToggleStatus(row) {
// 1 停用 0 启用
// 启用的数据能停用,停用的数据反之
const newStatus = row.ruleStatus === 1 ? 'enable' : 'disabled'
const statusText = row.ruleStatus === 0 ? '停用' : '启用'
this.$messageBox(
() => {
// 调用批量启用/停用接口传入当前行的ID
batchSwitchStatus(newStatus, [row.id])
.then(() => {
this.$message.success(`${statusText}成功`)
// 更新当前行的状态
row.ruleStatus = row.ruleStatus === 1 ? 0 : 1
})
.catch(error => {
this.$message.error(
`${statusText}失败: ` + (error.message || '未知错误')
)
})
},
`确认${statusText}该规则吗?`,
'warning',
'提示'
)
},
// 分页大小改变事件
handleSizeChange(val) {
this.queryParams.pageSize = val
this.getList()
},
// 当前页码改变事件
async handleCurrentChange(val) {
this.queryParams.page = val
this.tableConfig.currentPage = val
await this.getList()
},
// 删除按钮点击事件
handleDelete(row) {
this.$messageBox(
() => {
// 调用删除接口
deleteRule([row.id])
.then(() => {
this.$message.success('删除成功')
this.getList()
})
.catch(error => {
this.$message.error('删除失败: ' + (error.message || '未知错误'))
})
},
'确认删除该规则吗?',
'warning',
'警告'
)
},
sortChange(val) {
// 处理排序逻辑
const { prop, order } = val
let orderDTOs = [
{
columnName: prop,
orderType: order === 'ascending' ? 1 : 2
}
]
this.getList(orderDTOs)
},
getColumnsConfig() {
const baseColumns = [
{ type: 'index', key: '序号', width: 60 },
{
prop: 'ruleType',
key: '规则类型',
sortable: 'custom',
width: '100',
render: (h, params) => {
// 将ruleType编码转换为中文显示
const ruleTypeItem = this.ruleTypeList.find(
item =>
item.typeCode === params.row.ruleType ||
item.typeName === params.row.ruleType
)
return h(
'span',
ruleTypeItem ? ruleTypeItem.typeName : params.row.ruleType
)
}
},
{
prop: 'ruleField',
key: '字段类型',
sortable: 'custom',
width: '100',
render: (h, params) => {
// 将ruleField编码转换为中文显示
const fieldTypeItem = this.fieldTypeList.find(
item =>
item.fieldName === params.row.ruleField ||
item.fieldComment === params.row.ruleField
)
return h(
'span',
fieldTypeItem ? fieldTypeItem.fieldComment : params.row.ruleField
)
}
},
{ prop: 'ruleDesc', key: '规则描述', width: '200', sortable: 'custom' },
{
prop: 'riskScript',
key: '风险提示话术',
width: '200',
sortable: 'custom'
},
{
prop: 'hitCount',
key: '触发次数',
sortable: 'custom',
render: (h, params) => {
return h(
'span',
{
props: {
type: 'info',
size: 'small'
}
},
params.row.hitCount ? params.row.hitCount + '次' : '0次'
)
}
},
{
prop: 'approvedCount',
key: '审批通过次数',
sortable: 'custom',
render: (h, params) => {
return h(
'span',
{
props: {
type: 'success',
size: 'small'
}
},
params.row.approvedCount ? params.row.approvedCount + '次' : '0次'
)
}
},
{
prop: 'refusedCount',
sortable: 'custom',
key: '审批不通过次数',
render: (h, params) => {
return h(
'span',
{
props: {
type: 'danger',
size: 'small'
}
},
params.row.refusedCount ? params.row.refusedCount + '次' : '0次'
)
}
},
{
prop: 'ruleStatus',
key: '规则状态',
sortable: 'custom',
render: (h, params) => {
return h(
'el-tag',
{
props: {
type: params.row.ruleStatus === 0 ? 'success' : 'info',
size: 'small'
}
},
params.row.ruleStatus === 0 ? '启用' : '停用'
)
}
}
]
// 如果不是子组件,添加操作列
if (this.isChildrenView) {
baseColumns.unshift({
type: 'selection',
key: '序号',
width: 60
})
}
if (!this.isChildrenView) {
baseColumns.push({
key: '操作',
isRedraw: true,
fixed: 'right',
width: '150',
render: (h, params) => {
const buttons = []
// 所有状态都显示查看详情按钮
buttons.push(
h(
'el-button',
{
props: {
type: 'text',
size: 'mini',
icon: 'el-icon-view',
title: '查看详情'
},
class: 'normal-button',
on: { click: () => this.handleView(params.row) }
},
''
)
)
// 规则状态为"停用"(ruleStatus === 1)时显示编辑和删除按钮
if (params.row.ruleStatus === 1) {
buttons.push(
h(
'el-button',
{
props: {
type: 'text',
size: 'mini',
icon: 'el-icon-edit-outline',
title: '编辑'
},
class: 'normal-button',
on: { click: () => this.handleEdit(params.row) }
},
''
),
h(
'el-button',
{
props: {
type: 'text',
size: 'mini',
style: 'color: #F56C6C',
icon: 'el-icon-delete',
title: '删除'
},
on: { click: () => this.handleDelete(params.row) }
},
''
)
)
}
// 显示启用/停用按钮(根据当前状态显示不同图标)
buttons.push(
h(
'el-button',
{
props: {
type: 'text',
size: 'mini',
icon:
params.row.ruleStatus === 0
? 'el-icon-remove-outline'
: 'el-icon-circle-check',
title: params.row.ruleStatus === 0 ? '停用' : '启用'
},
on: { click: () => this.handleToggleStatus(params.row) }
},
''
)
)
return h('div', buttons)
}
})
}
return baseColumns
},
handleSelectionChange(selectedRows) {
if (selectedRows.length > 0) {
this.selectedRules.splice(
this.tableConfig.currentPage - 1,
1,
selectedRows
)
}
}
}
}
</script>
<style lang="scss" scoped>
.employ-rule {
padding: 20px;
.filter-container {
margin-bottom: 20px;
.el-form-item {
margin-bottom: 10px;
margin-right: 10px;
.el-form-item__label {
padding-right: 8px;
}
}
}
}
</style>

View File

@@ -170,7 +170,7 @@ export default {
data() {
return {
uloadPng,
fileList: [], // 文件列表
fileList: [], //列表 文件
uploadLoading: false,
headers: {},
fieldList: [],

View File

@@ -0,0 +1,49 @@
<template>
<div>
<h3>审批单录入</h3>
<!-- 审批单基本信息 -->
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>审批单基本信息</span>
</div>
<el-row :gutter="20">
<el-col :span="12">
<el-form ref="form" :model="formData" label-width="120px">
<el-form-item label="审批单号">
<el-input
v-model="formData.orderCode"
placeholder="请输入审批单号"
></el-input>
</el-form-item>
<el-form-item label="审批单出单时间">
<el-date-picker
v-model="formData.orderTime"
type="datetime"
placeholder="选择日期时间"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
></el-date-picker>
</el-form-item>
</el-form>
</el-col>
<el-col :span="12">
<!-- 右侧留空保持对称 -->
</el-col>
</el-row>
</el-card>
</div>
</template>
<script>
export default {
name: 'ApprovalForm',
props: {
formData: {
type: Object,
default: () => ({})
}
}
}
</script>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,169 @@
<template>
<!-- 基本信息 -->
<el-card class="box-card" shadow="never">
<div slot="header" class="clearfix">
<span>基本信息</span>
</div>
<el-row :gutter="20">
<el-col :span="12">
<el-form ref="form" :model="formData.data.baseInfo" label-width="140px">
<el-form-item label="客户名称">
<el-input
size="medium"
v-model="formData.data.baseInfo.customerName"
placeholder="请输入客户名称"
></el-input>
</el-form-item>
<el-form-item label="起保日期">
<el-date-picker
size="medium"
v-model="formData.data.baseInfo.insureStartDate"
type="date"
placeholder="选择起保日期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
></el-date-picker>
</el-form-item>
<el-form-item label="归属机构">
<el-input
size="medium"
type="text"
placeholder="输入归属机构"
v-model="formData.data.baseInfo.orgName"
></el-input>
</el-form-item>
<el-form-item label="是否续保">
<el-input
size="medium"
type="text"
placeholder="输入归属机构"
v-model="formData.data.baseInfo.isRenew"
></el-input>
<!-- <el-radio-group v-model="formData.data.baseInfo.isRenew">-->
<!-- <el-radio label="是"></el-radio>-->
<!-- <el-radio label="否"></el-radio>-->
<!-- </el-radio-group>-->
</el-form-item>
<el-form-item label="业务来源">
<el-input
size="medium"
type="text"
placeholder="输入业务来源"
v-model="formData.data.baseInfo.bizSource"
></el-input>
</el-form-item>
<el-form-item label="签报有效起期">
<el-date-picker
size="medium"
v-model="formData.data.baseInfo.signStartDate"
type="date"
placeholder="选择签报有效起期"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
></el-date-picker>
</el-form-item>
<el-form-item label="业务详细说明">
<el-input
size="medium"
type="textarea"
:rows="3"
placeholder="说明业务来源、背景及分公司初步风险判断"
v-model="formData.data.baseInfo.bizDescription"
></el-input>
</el-form-item>
</el-form>
</el-col>
<el-col :span="12">
<el-form ref="form" :model="formData.data.baseInfo" label-width="140px">
<el-form-item label="终保日期">
<el-date-picker
size="medium"
v-model="formData.data.baseInfo.insureEndDate"
placeholder="选择终保日期"
type="date"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
></el-date-picker>
</el-form-item>
<el-form-item label="共保标志">
<!-- <el-select
size="medium"
v-model="formData.data.baseInfo.isCoUnderwriting"
placeholder="请选择共保标志"
>
<el-option label="独家承保" value="独家承保"></el-option>
<el-option label="共保" value="共保"></el-option>
</el-select>-->
<el-input
size="medium"
v-model="formData.data.baseInfo.isCoUnderwriting"
placeholder="请输入共保标志"
></el-input>
</el-form-item>
<el-form-item label="业务细分">
<el-input
size="medium"
type="text"
placeholder="输入业务细分"
v-model="formData.data.baseInfo.bizDetailSource"
></el-input>
</el-form-item>
<el-form-item label="签报有效止期">
<el-date-picker
size="medium"
v-model="formData.data.baseInfo.signEndDate"
placeholder="选择签报有效止期"
type="datetime"
format="yyyy-MM-dd HH:mm:ss"
value-format="yyyy-MM-dd HH:mm:ss"
></el-date-picker>
</el-form-item>
<!-- 补充的字段 -->
<el-form-item label="主险代码">
<el-input
size="medium"
v-model="formData.data.baseInfo.mainRiskCode"
placeholder="请输入主险代码"
></el-input>
</el-form-item>
<el-form-item label="总保额">
<el-input
size="medium"
v-model="formData.data.baseInfo.totalAmt"
placeholder="请输入总保额"
></el-input>
</el-form-item>
<el-form-item label="总签单保费">
<el-input
size="medium"
v-model="formData.data.baseInfo.totalPrem"
placeholder="请输入总签单保费"
></el-input>
</el-form-item>
<el-form-item label="币别">
<el-input
size="medium"
v-model="formData.data.baseInfo.currency"
placeholder="如CNY"
></el-input>
</el-form-item>
</el-form>
</el-col>
</el-row>
</el-card>
</template>
<script>
export default {
name: 'BaseForm',
props: {
formData: {
type: Object,
default: () => ({})
}
}
}
</script>
<style scoped lang="scss"></style>

View File

@@ -0,0 +1,579 @@
<template>
<div class="main" id="main">
<div class="left-nav">
<div class="nav-header">历史风险筛查结果</div>
<div class="nav-body" id="navBody">
<div v-if="loadingNav" class="loading">
<span class="loading-spinner"></span>
数据加载中...
</div>
<div v-else-if="navList.length === 0" class="empty-message">
暂无历史记录
</div>
<a
v-else
v-for="(navItem, i) in navList"
:key="i"
href="javascript:void(0)"
:class="['link', { active: activeNavIndex === i }]"
@click="handleNavClick(i)"
>
<img
:src="navItem.hasRisk === 1 ? errorIcon : rightIcon"
class="png-icon"
/>
{{ navItem.taSubmitDate }}
<span>{{ navItem.hasRisk === 1 ? '【有风险】' : '【无风险】' }}</span>
</a>
</div>
</div>
<div class="right-container">
<div class="top-container">
<div class="custom-container">
<span id="custom">{{ navCheckRecord.orgName || '未知客户' }}</span>
<span id="time">{{ detailTimeInfo }}</span>
</div>
<h4 id="insured">
被保险人名称{{ navCheckRecord.insuredName || '未知' }}
</h4>
<div id="docs" v-html="currentCheckSummary"></div>
</div>
<div style="overflow: auto;">
<div id="detail-container">
<div v-if="detailLoading" class="loading">
<span class="loading-spinner"></span>
正在加载详情...
</div>
<div v-else-if="arrs.length === 0" class="empty-message">
<img
src="@/assets/images/empty.png"
alt=""
style="width:200px;margin: 0 auto"
/>
<p>暂无风险</p>
</div>
<template v-else>
<div v-for="(resultDetail, ind) in arrs" :key="ind">
<h4 v-if="resultDetail.tabName" class="section-title">
{{ resultDetail.tabName }}
</h4>
<div
:class="['tree-item-header', { expanded: expandedItems[ind] }]"
@click="toggleItem(ind)"
>
{{
resultDetail.typeName
? resultDetail.typeName
: resultDetail.dictLabel
}}
</div>
<div
:id="'result-container-' + ind"
class="result-container-item"
:style="{ display: expandedItems[ind] ? 'block' : 'none' }"
>
<ul class="result-container-item-child-ul">
<li
v-if="
!(
resultDetail.children &&
resultDetail.children.length > 0
)
"
class="result-container-item-child"
style="color: #95a5a6; font-style: italic;"
>
暂无数据
</li>
<li
v-for="(child, childIndex) in resultDetail.children"
:key="childIndex"
class="result-container-item-child"
@click="handleChildClick(child)"
>
<span class="index">{{ childIndex + 1 }}</span>
{{
(child.ruleName ? child.ruleName : child.fileName) ||
'未知项目'
}}
</li>
</ul>
</div>
</div>
</template>
</div>
</div>
</div>
<div style="clear: both"></div>
</div>
</template>
<script>
import { queryResult, queryResultDetail } from '@/api/riskCheck/record'
import errorIcon from '@/assets/images/error.png'
import rightIcon from '@/assets/images/right.png'
export default {
name: 'RiskHistory',
data() {
return {
errorIcon,
rightIcon,
loadingNav: true,
detailLoading: false,
navList: [],
navCheckRecord: {},
activeNavIndex: -1,
arrs: [],
expandedItems: {},
ipConfig: {
ip: this.$route.query.ip || 'http://39.104.123.256:7196'
},
serviceUrl: {
download: {
url: '/bpic/image/download'
}
}
}
},
computed: {
currentCheckSummary() {
if (this.activeNavIndex >= 0 && this.navList[this.activeNavIndex]) {
return (
this.navList[this.activeNavIndex].checkSummary ||
'<p>暂无风险摘要信息</p>'
)
}
return '<p>请选择左侧记录查看详细信息</p>'
},
detailTimeInfo() {
if (this.activeNavIndex >= 0 && this.navList[this.activeNavIndex]) {
return (
(this.navCheckRecord.taLatestSubmitDate || '未知时间') +
' 共【' +
(this.arrs ? this.arrs.length : 0) +
'】条风险提示'
)
}
return ''
}
},
mounted() {
// 处理noPT参数
if (this.$route.query.noPT) {
const main = document.getElementById('main')
if (main) {
main.style.padding = '0'
}
}
this.getNavList()
},
methods: {
getNavList() {
const taCode = this.$route.query.taCode || 'C123504032025600027'
queryResult({ taCode })
.then(response => {
this.loadingNav = false
if (response.code !== 200) {
this.$message.error(response.message || '请求失败')
throw new Error(response.message || '请求失败')
}
const data = response.content || response.data
this.navList = data.resultList || []
this.navCheckRecord = data.riskCheckRecord || {}
// 默认点击第一个导航项
if (this.navList.length > 0) {
this.$nextTick(() => {
this.handleNavClick(0)
})
}
})
.catch(error => {
this.loadingNav = false
this.$message.error('获取数据失败: ' + error.message)
this.navList = []
})
},
handleNavClick(index) {
// 更新活动索引
this.activeNavIndex = index
// 格式化checkSummary
if (
this.navList[index].checkSummary &&
typeof this.navList[index].checkSummary === 'string'
) {
let text = this.navList[index].checkSummary
text = text.replace(/\n\n/g, '</p><p>') // 段落
text = text.replace(/\n/g, '<br/>') // 剩余单换行
text = '<p>' + text + '</p>'
text = text.replace(/<p><\/p>/g, '<p>&nbsp;</p>') // 防止空段落出错
this.navList[index].checkSummary = text
} else {
this.navList[index].checkSummary = '<p>暂无风险摘要信息</p>'
}
// 获取详情
this.getDetail(this.navList[index])
},
getDetail(navItem) {
this.detailLoading = true
const taCode = this.$route.query.taCode || this.navCheckRecord.taCode
const params = {
resultId: navItem.id,
recordId: navItem.recordId,
taCode: taCode
}
queryResultDetail(params)
.then(response => {
this.detailLoading = false
if (response.code !== 200) {
this.$message.error(response.message || '请求失败')
throw new Error(response.message || '请求失败')
}
const data = response.content || response.data
const result = data.ruleTypeList || []
const fileStorageInfoList = data.fileBizTypeDictList || []
this.arrs = []
if (result && result.length > 0) {
result[0].tabName = '风险筛查结果'
for (let i = 0; i < result.length; i++) {
this.arrs.push(result[i])
}
}
if (fileStorageInfoList && fileStorageInfoList.length > 0) {
fileStorageInfoList[0].tabName = '影像件'
for (let i = 0; i < fileStorageInfoList.length; i++) {
this.arrs.push(fileStorageInfoList[i])
}
}
// 默认展开第一个项目
if (this.arrs.length > 0) {
this.$set(this.expandedItems, 0, true)
}
})
.catch(error => {
this.detailLoading = false
this.$message.error('获取详情失败: ' + error.message)
this.arrs = []
})
},
toggleItem(index) {
this.$set(this.expandedItems, index, !this.expandedItems[index])
},
handleChildClick(item) {
if (item.filePath) {
window.open(
this.ipConfig.ip + this.serviceUrl.download.url + '?fileId=' + item.id
)
}
}
}
}
</script>
<style scoped lang="scss">
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.main {
width: 100%;
height: 100%;
padding: 1%;
font-size: 0; /* 消除 inline-block 间隙 */
}
.left-nav {
width: 20%;
float: left;
height: 100%;
display: inline-block;
vertical-align: top;
background: #fff;
border-radius: 10px;
font-size: 16px; /* 恢复字体 */
border: 1px solid #ddd;
/* IE8兼容的阴影效果 */
filter: progid:DXImageTransform.Microsoft.Shadow(color='#cccccc', Direction=135, Strength=3);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
.nav-header {
font-size: 18px;
font-weight: bold;
text-align: center;
padding: 20px 0;
border-bottom: 1px solid #eee;
background: #f8f9fa;
color: #2c3e50;
border-radius: 10px 10px 0 0;
}
.link {
display: block;
margin: 15px auto;
text-align: center;
background: #fff;
text-decoration: none;
color: #000;
font-size: 14px;
border-radius: 4px;
padding: 12px 10px;
width: 85%;
transition: all 0.3s ease;
/* IE8兼容样式 */
border: 1px solid transparent;
}
.link:hover {
background: #f5f9ff;
border-color: #3498db;
color: #000;
}
.link.active {
background: #f0f4fa;
color: #3498db;
}
.right-container {
width: 79%;
height: 100%;
display: inline-block;
float: right;
background: #fff;
border-radius: 10px;
font-size: 16px;
overflow-y: auto;
overflow-x: hidden;
border: 1px solid #ddd;
/* IE8兼容的阴影效果 */
filter: progid:DXImageTransform.Microsoft.Shadow(color='#cccccc', Direction=135, Strength=3);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
.top-container,
#detail-container {
width: 100%;
background: #fff;
margin-bottom: 10px;
border: 1px solid #eee;
}
.top-container {
border-bottom: 1px solid #eee;
padding: 20px;
background: #fafbfc;
}
#detail-container {
padding: 20px;
}
#custom {
display: inline-block;
font-size: 22px;
font-weight: bold;
margin-right: 15px;
color: #2c3e50;
}
#time {
font-size: 14px;
margin-top: 8px;
color: #7f8c8d;
}
.custom-container {
display: block;
margin: 10px 0 20px 0;
}
#docs {
padding: 15px 20px;
font-size: 14px;
line-height: 1.6;
background: #2c3e50;
color: #ecf0f1;
border-radius: 4px;
margin: 15px 0;
}
#insured {
padding: 10px 0;
font-weight: bold;
color: #2c3e50;
border-bottom: 1px solid #eee;
}
.tree-item-header {
padding: 15px 20px;
background: #f0f4fa;
margin: 15px 0;
cursor: pointer;
border-radius: 4px;
border: 1px solid #d6dde6;
font-weight: bold;
color: #2c3e50;
transition: background 0.3s;
/* IE8兼容样式 */
background: #e3e9f2;
}
.tree-item-header:hover {
background: #e3e9f2;
}
.tree-item-header::before {
content: '';
margin-right: 10px;
transition: transform 0.3s;
/* IE8不支持::before伪元素和transform */
}
.tree-item-header.expanded::before {
content: '';
/* IE8不支持 */
}
.result-container-item {
padding: 0 10px;
margin-bottom: 20px;
}
.result-container-item-child-ul {
list-style: none;
}
ul {
list-style: none;
}
li {
list-style: none;
}
.index {
margin: 0 10px;
display: inline-block;
width: 25px;
height: 25px;
line-height: 25px;
text-align: center;
border-radius: 50%;
color: #fff;
background-color: #9fa8da;
border: 1px solid #9fa8da;
}
.result-container-item-child-ul li {
font-size: 14px;
line-height: 1.8;
padding: 10px 15px;
margin: 8px 0;
background: #fff;
border: 1px solid #eee;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
/* IE8兼容样式 */
border: 1px solid #ddd;
}
.result-container-item-child-ul li:hover {
background: #f8f9ff;
border-color: #3498db;
}
/* 添加降级样式 */
.no-js-warning {
color: #e74c3c;
text-align: center;
padding: 30px;
font-weight: bold;
font-size: 16px;
background: #fadbd8;
border: 1px solid #f5b7b1;
border-radius: 4px;
margin: 20px;
}
/* 为不支持flex的浏览器提供备选方案 */
.custom-container > * {
display: inline-block;
vertical-align: top;
}
/* 添加加载状态提示 */
.loading {
text-align: center;
padding: 30px;
color: #7f8c8d;
}
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid #f3f3f3;
border-top: 3px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
/* IE8不支持动画 */
border: 3px solid #3498db;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.section-title {
font-size: 18px;
font-weight: bold;
margin: 25px 0 15px 0;
padding-bottom: 10px;
border-bottom: 2px solid #3498db;
color: #2c3e50;
}
.empty-message {
text-align: center;
padding: 40px 20px;
color: #95a5a6;
}
.png-icon {
vertical-align: middle;
margin: -2px 10px 0 10px;
outline: none;
border: none;
display: inline-block;
}
</style>

View File

@@ -0,0 +1,185 @@
<template>
<div class="risk-screening">
<!-- 左侧历史风险筛选结果 -->
<div class="left-panel">
<h6 class="history-text">历史风险筛查结果</h6>
<el-divider class="mt15 mb0"></el-divider>
<ul>
<li
v-for="(result, index) in riskResults"
:key="index"
:class="{ active: currentResultId === result.id }"
@click="selectRecord(result)"
>
<svg-icon
class="svg-icon"
:icon-class="result.hasRisk === 0 ? 'circle_tick' : 'waring'"
></svg-icon>
{{ result.taOrderTime }} {{
result.hasRisk === 0 ? '无风险' : '有风险'
}}
</li>
</ul>
</div>
<!-- 右侧风险筛查结果详情 -->
<div class="right-panel">
<div>
<h6>{{ currentRecord.insuredName }}</h6>
<span>
{{ currentResult.taOrderTime }} &nbsp;&nbsp;{{
riskResults.length
}}条风险提示
</span>
</div>
<div>
<el-card shadow="always">
<h4 class="mb20">被保险人名称{{ currentRecord.insuredName }}</h4>
<p style="white-space: pre-line">{{ currentResult.checkSummary }}</p>
</el-card>
</div>
<section class="mt30">
<h6>风险筛查结果</h6>
<details>
<summary>基本信息</summary>
<ul>
<ul v-for="(item, index) in resultDetails" :key="index">
<span :style="{ backgroundColor: item.color }">{{
index + 1
}}</span>
{{
item.warning
}}
</ul>
</ul>
</details>
<details>
<summary>标的基本信息</summary>
<ul>
<li v-for="(item, index) in resultDetails" :key="index">
<span :style="{ backgroundColor: item.color }">{{
index + 6
}}</span>
{{ item.warning }}
</li>
</ul>
</details>
</section>
<footer>
<button>返回</button>
</footer>
</div>
</div>
</template>
<script>
import { queryResult, queryResultDetail } from '@/api/riskCheck'
export default {
name: 'riskCheck',
data() {
return {
// 审批单号
taCode: 'C123504032025600027',
// 风险筛查记录
currentRecord: '',
// 筛查结果集合(含历史筛查结果)
riskResults: [],
// 筛查结果的明细
resultDetails: [],
// 影像件信息
fileStorageInfos: [],
// 当前选择筛查结果的id
currentResultId: '',
currentResult: null
}
},
methods: {
// 获取
selectRecord(result) {
this.currentResult = result
this.currentResultId = result.id
let params = { recordId: result.recordId, resultId: result.id }
queryResultDetail(params).then(res => {
if (res.success) {
this.resultDetails = res.content.content.resultDetailList
this.fileStorageInfos = res.content.content.fileStorageInfoList
}
})
},
// 获取审批单风筛结果
fetchRecordDetail(taCode) {
queryResult(taCode).then(res => {
if (res.success) {
this.currentRecord = res.content.content.riskCheckRecord
this.riskResults = res.content.content.resultList
this.riskResults = this.riskResults.sort(
(a, b) => new Date(a.taOrderTime) - new Date(b.taOrderTime)
)
this.currentResultId =
this.riskResults.length > 0 ? this.riskResults[0].id : ''
this.selectRecord(this.riskResults[0])
}
})
}
},
mounted() {
this.fetchRecordDetail({ taCode: this.taCode })
}
}
</script>
<style scoped lang="scss">
/* 基本样式 */
.risk-screening {
display: flex;
gap: 20px;
padding: 10px;
}
.left-panel {
width: 250px;
background-color: #ffffff;
}
.right-panel {
flex: 1;
background-color: #fff;
padding: 20px;
}
.left-panel h6 {
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
margin-top: 15px;
}
ul {
list-style: none;
}
.left-panel li {
height: 50px;
text-align: center;
padding: 15px 0;
font-size: 12px;
}
.right-panel h6 {
font-size: 14px;
margin-right: 30px;
display: inline;
}
.left-panel li.active {
background-color: #e0e0e0;
}
.svg-icon {
font-size: 20px;
margin-right: 10px;
}
</style>

View File

@@ -0,0 +1,579 @@
<template>
<div class="main" id="main">
<div class="left-nav">
<div class="nav-header">历史风险筛查结果</div>
<div class="nav-body" id="navBody">
<div v-if="loadingNav" class="loading">
<span class="loading-spinner"></span>
数据加载中...
</div>
<div v-else-if="navList.length === 0" class="empty-message">
暂无历史记录
</div>
<a
v-else
v-for="(navItem, i) in navList"
:key="i"
href="javascript:void(0)"
:class="['link', { active: activeNavIndex === i }]"
@click="handleNavClick(i)"
>
<!-- <img-->
<!-- :src="navItem.hasRisk === 1 ? errorIcon : rightIcon"-->
<!-- class="png-icon"-->
<!-- />-->
{{ navItem.taSubmitDate }}
<span>{{ navItem.hasRisk === 1 ? '【有风险】' : '【无风险】' }}</span>
</a>
</div>
</div>
<div class="right-container">
<div class="top-container">
<div class="custom-container">
<span id="custom">{{ navCheckRecord.orgName || '未知客户' }}</span>
<span id="time">{{ detailTimeInfo }}</span>
</div>
<h4 id="insured">
被保险人名称{{ navCheckRecord.insuredName || '未知' }}
</h4>
<div id="docs" v-html="currentCheckSummary"></div>
</div>
<div style="overflow: auto;">
<div id="detail-container">
<div v-if="detailLoading" class="loading">
<span class="loading-spinner"></span>
正在加载详情...
</div>
<div v-else-if="arrs.length === 0" class="empty-message">
<!-- <img-->
<!-- src="@/assets/images/empty.png"-->
<!-- alt=""-->
<!-- style="width:200px;margin: 0 auto"-->
<!-- />-->
<p>暂无风险</p>
</div>
<template v-else>
<div v-for="(resultDetail, ind) in arrs" :key="ind">
<h4 v-if="resultDetail.tabName" class="section-title">
{{ resultDetail.tabName }}
</h4>
<div
:class="['tree-item-header', { expanded: expandedItems[ind] }]"
@click="toggleItem(ind)"
>
{{
resultDetail.typeName
? resultDetail.typeName
: resultDetail.dictLabel
}}
</div>
<div
:id="'result-container-' + ind"
class="result-container-item"
:style="{ display: expandedItems[ind] ? 'block' : 'none' }"
>
<ul class="result-container-item-child-ul">
<li
v-if="
!(
resultDetail.children &&
resultDetail.children.length > 0
)
"
class="result-container-item-child"
style="color: #95a5a6; font-style: italic;"
>
暂无数据
</li>
<li
v-for="(child, childIndex) in resultDetail.children"
:key="childIndex"
class="result-container-item-child"
@click="handleChildClick(child)"
>
<span class="index">{{ childIndex + 1 }}</span>
{{
(child.ruleName ? child.ruleName : child.fileName) ||
'未知项目'
}}
</li>
</ul>
</div>
</div>
</template>
</div>
</div>
</div>
<div style="clear: both"></div>
</div>
</template>
<script>
import { queryResult, queryResultDetail } from '@/api/riskCheck/record'
// import errorIcon from '@/assets/images/error.png'
// import rightIcon from '@/assets/images/right.png'
export default {
name: 'RiskHistory',
data() {
return {
// errorIcon,
// rightIcon,
loadingNav: true,
detailLoading: false,
navList: [],
navCheckRecord: {},
activeNavIndex: -1,
arrs: [],
expandedItems: {},
ipConfig: {
ip: this.$route.query.ip || 'http://39.104.123.256:7196'
},
serviceUrl: {
download: {
url: '/bpic/image/download'
}
}
}
},
computed: {
currentCheckSummary() {
if (this.activeNavIndex >= 0 && this.navList[this.activeNavIndex]) {
return (
this.navList[this.activeNavIndex].checkSummary ||
'<p>暂无风险摘要信息</p>'
)
}
return '<p>请选择左侧记录查看详细信息</p>'
},
detailTimeInfo() {
if (this.activeNavIndex >= 0 && this.navList[this.activeNavIndex]) {
const navItem = this.navList[this.activeNavIndex]
return (
(this.navCheckRecord.taLatestSubmitDate || '未知时间') +
' 共【' +
(this.arrs ? this.arrs.length : 0) +
'】条风险提示'
)
}
return ''
}
},
mounted() {
// 处理noPT参数
if (this.$route.query.noPT) {
const main = document.getElementById('main')
if (main) {
main.style.padding = '0'
}
}
this.getNavList()
},
methods: {
getNavList() {
const taCode = this.$route.query.taCode || 'C123504032025600027'
queryResult({ taCode })
.then(response => {
this.loadingNav = false
if (response.code !== 200) {
throw new Error(response.message || '请求失败')
}
const data = response.content || response.data
this.navList = data.resultList || []
this.navCheckRecord = data.riskCheckRecord || {}
// 默认点击第一个导航项
if (this.navList.length > 0) {
this.$nextTick(() => {
this.handleNavClick(0)
})
}
})
.catch(error => {
this.loadingNav = false
this.$message.error('获取数据失败: ' + error.message)
this.navList = []
})
},
handleNavClick(index) {
// 更新活动索引
this.activeNavIndex = index
// 格式化checkSummary
if (
this.navList[index].checkSummary &&
typeof this.navList[index].checkSummary === 'string'
) {
let text = this.navList[index].checkSummary
text = text.replace(/\n\n/g, '</p><p>') // 段落
text = text.replace(/\n/g, '<br/>') // 剩余单换行
text = '<p>' + text + '</p>'
text = text.replace(/<p><\/p>/g, '<p>&nbsp;</p>') // 防止空段落出错
this.navList[index].checkSummary = text
} else {
this.navList[index].checkSummary = '<p>暂无风险摘要信息</p>'
}
// 获取详情
this.getDetail(this.navList[index])
},
getDetail(navItem) {
this.detailLoading = true
const taCode = this.$route.query.taCode || this.navCheckRecord.taCode
const params = {
resultId: navItem.id,
recordId: navItem.recordId,
taCode: taCode
}
queryResultDetail(params)
.then(response => {
this.detailLoading = false
if (response.code !== 200) {
throw new Error(response.message || '请求失败')
}
const data = response.content || response.data
const result = data.ruleTypeList || []
const fileStorageInfoList = data.fileBizTypeDictList || []
this.arrs = []
if (result && result.length > 0) {
result[0].tabName = '风险筛查结果'
for (let i = 0; i < result.length; i++) {
this.arrs.push(result[i])
}
}
if (fileStorageInfoList && fileStorageInfoList.length > 0) {
fileStorageInfoList[0].tabName = '影像件'
for (let i = 0; i < fileStorageInfoList.length; i++) {
this.arrs.push(fileStorageInfoList[i])
}
}
// 默认展开第一个项目
if (this.arrs.length > 0) {
this.$set(this.expandedItems, 0, true)
}
})
.catch(error => {
this.detailLoading = false
this.$message.error('获取详情失败: ' + error.message)
this.arrs = []
})
},
toggleItem(index) {
this.$set(this.expandedItems, index, !this.expandedItems[index])
},
handleChildClick(item) {
if (item.filePath) {
window.open(
this.ipConfig.ip + this.serviceUrl.download.url + '?fileId=' + item.id
)
}
}
}
}
</script>
<style scoped lang="scss">
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.main {
width: 100%;
height: 100%;
padding: 1%;
font-size: 0; /* 消除 inline-block 间隙 */
}
.left-nav {
width: 20%;
float: left;
height: 100%;
display: inline-block;
vertical-align: top;
background: #fff;
border-radius: 10px;
font-size: 16px; /* 恢复字体 */
border: 1px solid #ddd;
/* IE8兼容的阴影效果 */
filter: progid:DXImageTransform.Microsoft.Shadow(color='#cccccc', Direction=135, Strength=3);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
.nav-header {
font-size: 18px;
font-weight: bold;
text-align: center;
padding: 20px 0;
border-bottom: 1px solid #eee;
background: #f8f9fa;
color: #2c3e50;
border-radius: 10px 10px 0 0;
}
.link {
display: block;
margin: 15px auto;
text-align: center;
background: #fff;
text-decoration: none;
color: #000;
font-size: 14px;
border-radius: 4px;
padding: 12px 10px;
width: 85%;
transition: all 0.3s ease;
/* IE8兼容样式 */
border: 1px solid transparent;
}
.link:hover {
background: #f5f9ff;
border-color: #3498db;
color: #000;
}
.link.active {
background: #f0f4fa;
color: #3498db;
}
.right-container {
width: 79%;
height: 100%;
display: inline-block;
float: right;
background: #fff;
border-radius: 10px;
font-size: 16px;
overflow-y: auto;
overflow-x: hidden;
border: 1px solid #ddd;
/* IE8兼容的阴影效果 */
filter: progid:DXImageTransform.Microsoft.Shadow(color='#cccccc', Direction=135, Strength=3);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}
.top-container,
#detail-container {
width: 100%;
background: #fff;
margin-bottom: 10px;
border: 1px solid #eee;
}
.top-container {
border-bottom: 1px solid #eee;
padding: 20px;
background: #fafbfc;
}
#detail-container {
padding: 20px;
}
#custom {
display: inline-block;
font-size: 22px;
font-weight: bold;
margin-right: 15px;
color: #2c3e50;
}
#time {
font-size: 14px;
margin-top: 8px;
color: #7f8c8d;
}
.custom-container {
display: block;
margin: 10px 0 20px 0;
}
#docs {
padding: 15px 20px;
font-size: 14px;
line-height: 1.6;
background: #2c3e50;
color: #ecf0f1;
border-radius: 4px;
margin: 15px 0;
}
#insured {
padding: 10px 0;
font-weight: bold;
color: #2c3e50;
border-bottom: 1px solid #eee;
}
.tree-item-header {
padding: 15px 20px;
background: #f0f4fa;
margin: 15px 0;
cursor: pointer;
border-radius: 4px;
border: 1px solid #d6dde6;
font-weight: bold;
color: #2c3e50;
transition: background 0.3s;
/* IE8兼容样式 */
background: #e3e9f2;
}
.tree-item-header:hover {
background: #e3e9f2;
}
.tree-item-header::before {
content: '';
margin-right: 10px;
transition: transform 0.3s;
/* IE8不支持::before伪元素和transform */
}
.tree-item-header.expanded::before {
content: '';
/* IE8不支持 */
}
.result-container-item {
padding: 0 10px;
margin-bottom: 20px;
}
.result-container-item-child-ul {
list-style: none;
}
ul {
list-style: none;
}
li {
list-style: none;
}
.index {
margin: 0 10px;
display: inline-block;
width: 25px;
height: 25px;
line-height: 25px;
text-align: center;
border-radius: 50%;
color: #fff;
//background-image: url('~@/assets/images/round.png');
background-repeat: no-repeat;
background-size: cover;
}
.result-container-item-child-ul li {
font-size: 14px;
line-height: 1.8;
padding: 10px 15px;
margin: 8px 0;
background: #fff;
border: 1px solid #eee;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s;
/* IE8兼容样式 */
border: 1px solid #ddd;
}
.result-container-item-child-ul li:hover {
background: #f8f9ff;
border-color: #3498db;
}
/* 添加降级样式 */
.no-js-warning {
color: #e74c3c;
text-align: center;
padding: 30px;
font-weight: bold;
font-size: 16px;
background: #fadbd8;
border: 1px solid #f5b7b1;
border-radius: 4px;
margin: 20px;
}
/* 为不支持flex的浏览器提供备选方案 */
.custom-container > * {
display: inline-block;
vertical-align: top;
}
/* 添加加载状态提示 */
.loading {
text-align: center;
padding: 30px;
color: #7f8c8d;
}
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid #f3f3f3;
border-top: 3px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
/* IE8不支持动画 */
border: 3px solid #3498db;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.section-title {
font-size: 18px;
font-weight: bold;
margin: 25px 0 15px 0;
padding-bottom: 10px;
border-bottom: 2px solid #3498db;
color: #2c3e50;
}
.empty-message {
text-align: center;
padding: 40px 20px;
color: #95a5a6;
}
.png-icon {
vertical-align: middle;
margin: -2px 10px 0 10px;
outline: none;
border: none;
display: inline-block;
}
</style>

View File

@@ -0,0 +1,86 @@
export default {
name: 'index',
components: {},
data() {
return {
}
},
methods:{
// 映射外部数据到formData结构的函数
mapExternalDataToFormData(externalData) {
// 确保目标数据结构存在
const formData = {
orderCode: externalData.ordercode || externalData.orderCode || '',
orderTime: externalData.ordertime || externalData.orderTime || '',
data: {
baseInfo: {},
targetInfo: {},
specAgreement: [],
mainRisk: {},
additionalRisk: [],
targetListInfo: [],
sellingCosts: [],
commission: []
}
};
// 映射基础信息
if (externalData.data && externalData.data.baseInfo) {
formData.data.baseInfo = { ...externalData.data.baseInfo };
}
// 映射标的物信息
if (externalData.data && externalData.data.targetInfo) {
formData.data.targetInfo = { ...externalData.data.targetInfo };
}
// 映射特别约定
if (externalData.data && externalData.data.specAgreement) {
formData.data.specAgreement = [...externalData.data.specAgreement];
}
// 映射主险信息
if (externalData.data && externalData.data.mainRisk) {
formData.data.mainRisk = { ...externalData.data.mainRisk };
}
// 映射附加险信息
if (externalData.data && externalData.data.additionalRisk) {
formData.data.additionalRisk = [...externalData.data.additionalRisk];
}
// 映射销售成本信息
if (externalData.data && externalData.data.sellingCosts) {
formData.data.sellingCosts = [...externalData.data.sellingCosts];
}
// 映射佣金信息
if (externalData.data && externalData.data.commission) {
formData.data.commission = [...externalData.data.commission];
}
// 关键转换将targetList转换为targetListInfo
if (externalData.data && externalData.data.targetList) {
formData.data.targetListInfo = externalData.data.targetList.map(item => ({ ...item }));
} else if (externalData.data && externalData.data.targetListInfo) {
formData.data.targetListInfo = externalData.data.targetListInfo.map(item => ({ ...item }));
}
return formData;
},
saveMonaco(){
try {
const parsedData = JSON.parse(this.monacoValue);
// 使用映射函数转换数据结构
this.formData = this.mapExternalDataToFormData(parsedData);
this.chooseImpart = false;
this.$message.success('数据导入成功');
} catch (error) {
this.$message.error('JSON格式错误请检查后重试');
console.error('JSON解析错误:', error);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -128,6 +128,11 @@
<script>
import { addMenu, getMenuList, updateMenu } from '@/api/system/menu'
import icons from '@/fonts/iconfont.json'
const iconList = icons.glyphs.map(item => 'icon-' + item.font_class)
console.log(iconList)
export default {
name: 'MenuDialog',
props: {
@@ -209,9 +214,7 @@ export default {
'el-icon-remove',
'el-icon-remove-outline',
'el-icon-circle-check',
'el-icon-circle-check-solid',
'el-icon-circle-close',
'el-icon-circle-close-solid',
'el-icon-top',
'el-icon-bottom',
'el-icon-right',
@@ -221,12 +224,7 @@ export default {
'el-icon-sort',
'el-icon-sort-up',
'el-icon-sort-down',
'icon-zhuye',
'icon-dingwei',
'icon-notebook',
'el-icon-s-custom',
'icon-dengpao1',
'icon-guizeshezhi'
...iconList
]
}
},

View File

@@ -1,68 +1,82 @@
<template>
<el-dialog
title="修改密码"
:visible.sync="visible"
width="500px"
append-to-body
@close="handleClose"
>
<el-form
ref="form"
:model="form"
:rules="rules"
label-width="120px"
status-icon
label-position="top"
<div>
<r-dialog
title="修改密码"
:visible.sync="visible"
width="500px"
append-to-body
@close="handleClose"
>
<el-form-item label="旧密码" prop="userPassword">
<el-input
v-model="form.userPassword"
placeholder="请输入旧密码"
type="password"
show-password
clearable
size="small"
/>
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input
v-model="form.newPassword"
placeholder="请输入新密码"
type="password"
show-password
clearable
size="small"
/>
</el-form-item>
<el-form-item label="确认新密码" prop="confirmPassword">
<el-input
v-model="form.confirmPassword"
placeholder="请再次输入新密码"
type="password"
show-password
clearable
size="small"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button
type="primary"
size="small"
:loading="loading"
@click="submitForm"
> </el-button
<el-form
ref="form"
:model="form"
:rules="rules"
label-width="120px"
status-icon
label-position="top"
>
<el-button size="small" @click="handleClose"> </el-button>
</div>
</el-dialog>
<el-form-item label="旧密码" prop="userPassword">
<el-input
v-model="form.userPassword"
placeholder="请输入旧密码"
type="password"
show-password
clearable
size="small"
/>
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input
v-model="form.newPassword"
placeholder="请输入新密码"
type="password"
show-password
clearable
size="small"
/>
</el-form-item>
<el-form-item label="确认新密码" prop="confirmPassword">
<el-input
v-model="form.confirmPassword"
placeholder="请再次输入新密码"
type="password"
show-password
clearable
size="small"
/>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button
type="primary"
size="medium"
:loading="loading"
@click="submitForm"
> </el-button
>
<el-button size="medium" @click="handleClose"> </el-button>
</div>
</r-dialog>
<send-phone-code
:visible.sync="phoneVisabled"
:resetPassword="!isLogin"
@handleSubmit="handleSubmit"
:user-name="userName"
></send-phone-code>
</div>
</template>
<script>
import { updatePassword } from '@/api/generatedApi/system'
import {
externalUpdatePassword,
updatePassword,
verifyUpdatePassword
} from '@/api/generatedApi/system'
import SendPhoneCode from '@/generatedComponents/send-phone-code.vue'
export default {
name: 'ResetPasswordDialog',
components: { SendPhoneCode },
props: {
visible: {
type: Boolean,
@@ -71,6 +85,18 @@ export default {
userId: {
type: String,
default: ''
},
hideDialog: {
type: Boolean,
default: false
},
isLogin: {
type: Boolean,
default: false
},
userName: {
type: String,
default: ''
}
},
data() {
@@ -83,6 +109,8 @@ export default {
}
}
return {
phoneVisabled: false,
minute: 120,
form: {
userPassword: '',
newPassword: '',
@@ -105,6 +133,42 @@ export default {
}
},
methods: {
handleSubmit(code) {
if (!this.isLogin) {
verifyUpdatePassword({
userPassword: this.form.userPassword,
newPassword: this.form.newPassword,
smsCode: code
}).then(async res => {
if (res) {
if (!this.hideDialog) {
this.$message.success('密码修改成功')
await this.$store.dispatch('user/logout')
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
} else {
this.$message.success('密码修改成功')
await this.$store.dispatch('user/logout')
this.phoneVisabled = false
this.handleClose()
}
}
})
} else {
externalUpdatePassword({
username: this.userName,
userPassword: this.form.userPassword,
newPassword: this.form.newPassword,
smsCode: code
}).then(res => {
if (res) {
this.$message.success('修改密码成功')
this.phoneVisabled = false
this.handleClose()
this.$emit('getResult')
}
})
}
},
handleClose() {
this.$refs.form.resetFields()
this.$emit('update:visible', false)
@@ -112,24 +176,38 @@ export default {
submitForm() {
this.$refs.form.validate(valid => {
if (valid) {
this.loading = true
const data = {
userPassword: this.form.userPassword,
newPassword: this.form.newPassword
}
if (!this.isLogin) {
this.loading = true
const data = {
userPassword: this.form.userPassword,
newPassword: this.form.newPassword
}
updatePassword(data)
.then(async () => {
this.$message.success('密码修改成功')
await this.$store.dispatch('user/logout')
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
})
.catch(() => {
this.$message.error('密码修改出错')
})
.finally(() => {
this.loading = false
})
updatePassword(data)
.then(async res => {
let number = Number(res.content.result)
switch (number) {
case 0:
this.$message.success('密码修改成功')
await this.$store.dispatch('user/logout')
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
break
case 51001:
this.phoneVisabled = true
break
default:
this.$message.error(res.content.resultMessage)
}
})
.catch(() => {
this.$message.error('系统异常,请联系管理员')
})
.finally(() => {
this.loading = false
})
} else {
this.phoneVisabled = true
}
}
})
}

View File

@@ -161,6 +161,14 @@ export default {
message: '请输入正确的邮箱地址'
}
],
mobile: [
{ required: true, message: '请输入手机号' },
// 手机号格式校验 正则
{
pattern: /^1[3456789]\d{9}$/,
message: '请输入正确的手机号'
}
],
sysUserRoleDTOs: [
{ required: true, message: '请选择用户角色', trigger: 'blur' }
]

View File

@@ -2,6 +2,7 @@
const path = require('path')
const defaultSettings = require('./src/assets/js/utils/settings.js')
const { DIFY_URL } = require('./src/config/base-url')
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin')
function resolve(dir) {
return path.join(__dirname, dir)
@@ -22,7 +23,7 @@ module.exports = {
在大多数情况下,请使用'/'
详细信息https://cli.vuejs.org/config/#publicpath
*/
publicPath: '/',
publicPath: '.',
outputDir: 'dist',
assetsDir: 'static',
lintOnSave: process.env.NODE_ENV === 'development',
@@ -81,6 +82,7 @@ module.exports = {
//在webpack的名称字段中提供应用程序的标题以便
//可以在index.html中对其进行访问以注入正确的标题。
name: name,
plugins: [new MonacoWebpackPlugin()],
module: {
rules: [
{
@@ -127,6 +129,30 @@ module.exports = {
return options
})
.end()
// 为 monaco-editor 添加特殊规则
config.module
.rule('monaco')
.test(/\.js$/)
.include.add(path.resolve(__dirname, 'node_modules/monaco-editor'))
.end()
.use('babel-loader')
.loader('babel-loader')
.options({
babelrc: false,
configFile: false,
presets: [
[
'@babel/preset-env',
{
targets: {
browsers: ['> 1%', 'last 2 versions']
}
}
]
]
})
// https://webpack.js.org/configuration/devtool/#development
config.when(process.env.NODE_ENV === 'development', config =>
config.devtool('cheap-source-map')
@@ -145,7 +171,7 @@ module.exports = {
config.optimization.splitChunks({
chunks: 'all',
minSize: 3000,
maxSize: 6000,
maxSize: 9000,
maxInitialRequests: 3,
cacheGroups: {
libs: {
@@ -169,6 +195,10 @@ module.exports = {
}
})
config.optimization.runtimeChunk('single')
// 添加时间戳到文件名中
})
config.output
.filename(`js/[name].[hash:8].js`)
.chunkFilename(`js/[name].[hash:8].js`)
}
}