parent
5701d81cf4
commit
9749dac3d3
@ -0,0 +1,21 @@ |
|||||||
|
import request from "@/utils/request"; |
||||||
|
import { AxiosPromise } from "axios"; |
||||||
|
|
||||||
|
export function updateIpv6Config(param1: string, param2: string) { |
||||||
|
return request({ |
||||||
|
url: `/api/ipv6-collection-config/v1/${param1}/${param2}`, |
||||||
|
method: "PUT", |
||||||
|
}); |
||||||
|
} |
||||||
|
export function uploadDevSnoApi(file: any): AxiosPromise<string> { |
||||||
|
const formData = new FormData(); |
||||||
|
formData.append("file", file); |
||||||
|
return request({ |
||||||
|
url: `/api/ipv6-collection-config/v1/upload`, |
||||||
|
method: "POST", |
||||||
|
data: formData, |
||||||
|
headers: { |
||||||
|
"Content-Type": "multipart/form-data", |
||||||
|
}, |
||||||
|
}); |
||||||
|
} |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 571 KiB |
@ -0,0 +1,289 @@ |
|||||||
|
/** |
||||||
|
* 数字 |
||||||
|
*/ |
||||||
|
const REG_NUMBER: string = ".*\\d+.*"; |
||||||
|
/** |
||||||
|
* 小写字母 |
||||||
|
*/ |
||||||
|
const REG_UPPERCASE: string = ".*[A-Z]+.*"; |
||||||
|
/** |
||||||
|
* 大写字母 |
||||||
|
*/ |
||||||
|
const REG_LOWERCASE: string = ".*[a-z]+.*"; |
||||||
|
/** |
||||||
|
* 特殊符号(~!@#$%^&*()_+|<>,.?/:;'[]{}\) |
||||||
|
*/ |
||||||
|
const REG_SYMBOL: string = ".*[~!@#$%^&*()_+|<>,.?/:;'\\[\\]{}\"]+.*"; |
||||||
|
/** |
||||||
|
* 键盘字符表(小写) |
||||||
|
* 非shift键盘字符表 |
||||||
|
*/ |
||||||
|
const CHAR_TABLE1: string[][] = [ |
||||||
|
["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "\0"], |
||||||
|
["q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "[", "]", "\\"], |
||||||
|
["a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'", "\0", "\0"], |
||||||
|
["z", "x", "c", "v", "b", "n", "m", ",", ".", "/", "\0", "\0", "\0"], |
||||||
|
]; |
||||||
|
/** |
||||||
|
* shift键盘的字符表 |
||||||
|
*/ |
||||||
|
const CHAR_TABLE2: string[][] = [ |
||||||
|
["!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "+", "\0"], |
||||||
|
["q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "{", "}", "|"], |
||||||
|
["a", "s", "d", "f", "g", "h", "j", "k", "l", ":", '"', "\0", "\0"], |
||||||
|
["z", "x", "c", "v", "b", "n", "m", "<", ">", "?", "\0", "\0", "\0"], |
||||||
|
]; |
||||||
|
|
||||||
|
/** |
||||||
|
* 校验密码是否符合条件 |
||||||
|
* @param password 密码 |
||||||
|
* @param username 用户名 |
||||||
|
*/ |
||||||
|
export const checkPasswordRule = (password: string, username: string) => { |
||||||
|
if (password === "" || password.length < 8 || password.length > 32) { |
||||||
|
// console.log("长度小于8,或大于32");
|
||||||
|
return "密码长度应大于8小于32"; |
||||||
|
} |
||||||
|
if (password.indexOf(username) !== -1) { |
||||||
|
// console.log("包含用户名");
|
||||||
|
return "请勿包含用户名"; |
||||||
|
} |
||||||
|
if (isContinuousChar(password)) { |
||||||
|
// console.log("包含3个及以上相同或字典连续字符");
|
||||||
|
return "请勿包含3个及以上相同或连续的字符"; |
||||||
|
} |
||||||
|
if (isKeyBoardContinuousChar(password)) { |
||||||
|
// console.log("包含3个及以上键盘连续字符");
|
||||||
|
return "请勿包含3个及以上键盘连续字符"; |
||||||
|
} |
||||||
|
let i: number = 0; |
||||||
|
if (password.match(REG_NUMBER)) i++; |
||||||
|
if (password.match(REG_LOWERCASE)) i++; |
||||||
|
if (password.match(REG_UPPERCASE)) i++; |
||||||
|
if (password.match(REG_SYMBOL)) i++; |
||||||
|
if (i < 2) { |
||||||
|
// console.log(("数字、小写字母、大写字母、特殊字符,至少包含两种"));
|
||||||
|
return "数字、小写字母、大写字母、特殊字符,至少包含两种"; |
||||||
|
} |
||||||
|
// console.log(i);
|
||||||
|
return "校验通过"; |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* 是否包含3个及以上相同或字典连续字符 |
||||||
|
*/ |
||||||
|
const isContinuousChar = (password: string) => { |
||||||
|
const chars: string[] = password.split(""); |
||||||
|
const charCode: number[] = []; |
||||||
|
for (let i = 0; i < chars.length - 2; i++) { |
||||||
|
charCode[i] = chars[i].charCodeAt(0); |
||||||
|
} |
||||||
|
for (let i = 0; i < charCode.length - 2; i++) { |
||||||
|
const n1 = charCode[i]; |
||||||
|
const n2 = charCode[i + 1]; |
||||||
|
const n3 = charCode[i + 2]; |
||||||
|
// 判断重复字符
|
||||||
|
if (n1 == n2 && n1 == n3) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
// 判断连续字符: 正序 + 倒序
|
||||||
|
if ((n1 + 1 == n2 && n1 + 2 == n3) || (n1 - 1 == n2 && n1 - 2 == n3)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
}; |
||||||
|
/** |
||||||
|
* 是否包含3个及以上键盘连续字符 |
||||||
|
* @param password 待匹配的字符串 |
||||||
|
*/ |
||||||
|
const isKeyBoardContinuousChar = (password: string) => { |
||||||
|
if (password === "") { |
||||||
|
return false; |
||||||
|
} |
||||||
|
//考虑大小写,都转换成小写字母
|
||||||
|
const lpStrChars: string[] = password.toLowerCase().split(""); |
||||||
|
// 获取字符串长度
|
||||||
|
const nStrLen: number = lpStrChars.length; |
||||||
|
// 定义位置数组:row - 行,col - column 列
|
||||||
|
const pRowCharPos: number[] = new Array(nStrLen).fill(""); |
||||||
|
const pColCharPos: number[] = new Array(nStrLen).fill(""); |
||||||
|
for (let i = 0; i < nStrLen; i++) { |
||||||
|
const chLower: string = lpStrChars[i]; |
||||||
|
pColCharPos[i] = -1; |
||||||
|
// 检索在表1中的位置,构建位置数组
|
||||||
|
for (let nRowTable1Idx = 0; nRowTable1Idx < 4; nRowTable1Idx++) { |
||||||
|
for (let nColTable1Idx = 0; nColTable1Idx < 13; nColTable1Idx++) { |
||||||
|
if (chLower == CHAR_TABLE1[nRowTable1Idx][nColTable1Idx]) { |
||||||
|
pRowCharPos[i] = nRowTable1Idx; |
||||||
|
pColCharPos[i] = nColTable1Idx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// 在表1中没找到,到表二中去找,找到则continue
|
||||||
|
if (pColCharPos[i] >= 0) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
// 检索在表2中的位置,构建位置数组
|
||||||
|
for (let nRowTable2Idx = 0; nRowTable2Idx < 4; nRowTable2Idx++) { |
||||||
|
for (let nColTable2Idx = 0; nColTable2Idx < 13; nColTable2Idx++) { |
||||||
|
if (chLower == CHAR_TABLE2[nRowTable2Idx][nColTable2Idx]) { |
||||||
|
pRowCharPos[i] = nRowTable2Idx; |
||||||
|
pColCharPos[i] = nColTable2Idx; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// 匹配坐标连线
|
||||||
|
for (let j = 1; j <= nStrLen - 2; j++) { |
||||||
|
//同一行
|
||||||
|
if ( |
||||||
|
pRowCharPos[j - 1] == pRowCharPos[j] && |
||||||
|
pRowCharPos[j] == pRowCharPos[j + 1] |
||||||
|
) { |
||||||
|
// 键盘行正向连续(asd)或者键盘行反向连续(dsa)
|
||||||
|
if ( |
||||||
|
(pColCharPos[j - 1] + 1 == pColCharPos[j] && |
||||||
|
pColCharPos[j] + 1 == pColCharPos[j + 1]) || |
||||||
|
(pColCharPos[j + 1] + 1 == pColCharPos[j] && |
||||||
|
pColCharPos[j] + 1 == pColCharPos[j - 1]) |
||||||
|
) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
//同一列
|
||||||
|
if ( |
||||||
|
pColCharPos[j - 1] == pColCharPos[j] && |
||||||
|
pColCharPos[j] == pColCharPos[j + 1] |
||||||
|
) { |
||||||
|
//键盘列连续(qaz)或者键盘列反向连续(zaq)
|
||||||
|
if ( |
||||||
|
(pRowCharPos[j - 1] + 1 == pRowCharPos[j] && |
||||||
|
pRowCharPos[j] + 1 == pRowCharPos[j + 1]) || |
||||||
|
(pRowCharPos[j - 1] - 1 == pRowCharPos[j] && |
||||||
|
pRowCharPos[j] - 1 == pRowCharPos[j + 1]) |
||||||
|
) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* 密码强度校验 |
||||||
|
*/ |
||||||
|
/** |
||||||
|
* 长度 |
||||||
|
* @param str |
||||||
|
*/ |
||||||
|
const length = (str: string) => { |
||||||
|
if (str.length < 5) { |
||||||
|
return 5; |
||||||
|
} else if (str.length < 8) { |
||||||
|
return 10; |
||||||
|
} else { |
||||||
|
return 25; |
||||||
|
} |
||||||
|
}; |
||||||
|
/** |
||||||
|
* 字母 |
||||||
|
* @param str |
||||||
|
*/ |
||||||
|
const letters = (str: string) => { |
||||||
|
let count1 = 0, |
||||||
|
count2 = 0; |
||||||
|
for (let i = 0; i < str.length; i++) { |
||||||
|
if (str.charAt(i) >= "a" && str.charAt(i) <= "z") { |
||||||
|
count1++; |
||||||
|
} |
||||||
|
if (str.charAt(i) >= "A" && str.charAt(i) <= "Z") { |
||||||
|
count2++; |
||||||
|
} |
||||||
|
} |
||||||
|
if (count1 == 0 && count2 == 0) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
if (count1 != 0 && count2 != 0) { |
||||||
|
return 20; |
||||||
|
} |
||||||
|
return 10; |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* 数字 |
||||||
|
* @param str |
||||||
|
*/ |
||||||
|
const numbers = (str: string) => { |
||||||
|
let count = 0; |
||||||
|
for (let i = 0; i < str.length; i++) { |
||||||
|
if (str.charAt(i) >= "0" && str.charAt(i) <= "9") { |
||||||
|
count++; |
||||||
|
} |
||||||
|
} |
||||||
|
if (count == 0) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
if (count == 1) { |
||||||
|
return 10; |
||||||
|
} |
||||||
|
return 20; |
||||||
|
}; |
||||||
|
/** |
||||||
|
* 符号 |
||||||
|
* @param str |
||||||
|
*/ |
||||||
|
const symbols = (str: string) => { |
||||||
|
let count = 0; |
||||||
|
for (let i = 0; i < str.length; i++) { |
||||||
|
if ( |
||||||
|
(str.charCodeAt(i) >= 0x21 && str.charCodeAt(i) <= 0x2f) || |
||||||
|
(str.charCodeAt(i) >= 0x3a && str.charCodeAt(i) <= 0x40) || |
||||||
|
(str.charCodeAt(i) >= 0x5b && str.charCodeAt(i) <= 0x60) || |
||||||
|
(str.charCodeAt(i) >= 0x7b && str.charCodeAt(i) <= 0x7e) |
||||||
|
) { |
||||||
|
count++; |
||||||
|
} |
||||||
|
} |
||||||
|
if (count == 0) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
if (count == 1) { |
||||||
|
return 10; |
||||||
|
} |
||||||
|
return 25; |
||||||
|
}; |
||||||
|
/** |
||||||
|
* 得分机制 |
||||||
|
* @param str |
||||||
|
*/ |
||||||
|
const rewards = (str: string) => { |
||||||
|
const letter = letters(str); //字母
|
||||||
|
const number = numbers(str); //数字
|
||||||
|
const symbol = symbols(str); //符号
|
||||||
|
if (letter > 0 && number > 0 && symbol == 0) { |
||||||
|
//字母和数字
|
||||||
|
return 2; |
||||||
|
} |
||||||
|
if (letter == 10 && number > 0 && symbol > 0) { |
||||||
|
//字母、数字和符号
|
||||||
|
return 3; |
||||||
|
} |
||||||
|
if (letter == 20 && number > 0 && symbol > 0) { |
||||||
|
//大小写字母、数字和符号
|
||||||
|
return 5; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
}; |
||||||
|
/** |
||||||
|
* 最终评分 |
||||||
|
* @param str |
||||||
|
*/ |
||||||
|
export const level = (str: string) => { |
||||||
|
const lengths = length(str); //长度
|
||||||
|
const letter = letters(str); //字母
|
||||||
|
const number = numbers(str); //数字
|
||||||
|
const symbol = symbols(str); //符号
|
||||||
|
const reward = rewards(str); //奖励
|
||||||
|
return lengths + letter + number + symbol + reward; |
||||||
|
}; |
@ -0,0 +1,382 @@ |
|||||||
|
<template> |
||||||
|
<div class="app-container"> |
||||||
|
<el-card shadow="never"> |
||||||
|
<template #header> |
||||||
|
<div style="display: flex; align-items: center"> |
||||||
|
<el-icon size="15"> <Grid /> </el-icon> <span |
||||||
|
style="font-weight: 700; font-size: 14px; line-height: 16px" |
||||||
|
>IPV6采集配置信息</span |
||||||
|
> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<el-descriptions :column="1" border v-loading="loading"> |
||||||
|
<el-descriptions-item |
||||||
|
label="分公司" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
<el-row :gutter="20"> |
||||||
|
<el-col :span="16"> |
||||||
|
<el-select v-model="area" clearable placeholder="请选择分公司"> |
||||||
|
<el-option |
||||||
|
v-for="item in areaOption" |
||||||
|
:label="item.label" |
||||||
|
:value="item.value" |
||||||
|
:key="item.value" |
||||||
|
/> |
||||||
|
</el-select> |
||||||
|
</el-col> |
||||||
|
<el-col :span="8"> |
||||||
|
<el-button type="primary" @click="updateIpv6ConfigParam('areaId')" |
||||||
|
>修改 |
||||||
|
</el-button> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item |
||||||
|
label="区局" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
<el-row :gutter="20"> |
||||||
|
<el-col :span="16"> |
||||||
|
<el-select v-model="subarea" placeholder="请选择区局" clearable> |
||||||
|
<el-option |
||||||
|
v-for="item in subareaOption" |
||||||
|
:label="item.label" |
||||||
|
:value="item.value" |
||||||
|
:key="item.value" |
||||||
|
/> |
||||||
|
</el-select> |
||||||
|
</el-col> |
||||||
|
<el-col :span="8"> |
||||||
|
<el-button |
||||||
|
type="primary" |
||||||
|
@click="updateIpv6ConfigParam('subAreaId')" |
||||||
|
>修改 |
||||||
|
</el-button> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item |
||||||
|
label="路由/桥接" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
<el-row :gutter="20"> |
||||||
|
<el-col :span="16"> |
||||||
|
<el-select |
||||||
|
v-model="rgMode" |
||||||
|
placeholder="请选择连接方式" |
||||||
|
clearable |
||||||
|
> |
||||||
|
<el-option label="桥接" value="1,IP_Routed" /> |
||||||
|
<el-option label="路由" value="2,PPPoE_Bridged" /> |
||||||
|
</el-select> |
||||||
|
</el-col> |
||||||
|
<el-col :span="8"> |
||||||
|
<el-button |
||||||
|
type="primary" |
||||||
|
@click="updateIpv6ConfigParam('routeId')" |
||||||
|
>修改 |
||||||
|
</el-button> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item |
||||||
|
label="设备供应商" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
<el-row :gutter="20"> |
||||||
|
<el-col :span="16"> |
||||||
|
<el-select |
||||||
|
v-model="category" |
||||||
|
placeholder="请选择设备供应商" |
||||||
|
filterable |
||||||
|
clearable |
||||||
|
> |
||||||
|
<el-option |
||||||
|
v-for="item in vendorNameOption" |
||||||
|
:label="item.label" |
||||||
|
:value="item.value" |
||||||
|
:key="item.value" |
||||||
|
/> |
||||||
|
</el-select> |
||||||
|
</el-col> |
||||||
|
<el-col :span="8"> |
||||||
|
<el-button |
||||||
|
type="primary" |
||||||
|
disabled |
||||||
|
@click="updateIpv6ConfigParam('devVendorName')" |
||||||
|
>修改 |
||||||
|
</el-button> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item |
||||||
|
label="设备型号" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
<el-row :gutter="20"> |
||||||
|
<el-col :span="16"> |
||||||
|
<el-select |
||||||
|
v-model="typeName" |
||||||
|
placeholder="请选择设备型号" |
||||||
|
filterable |
||||||
|
clearable |
||||||
|
> |
||||||
|
<el-option |
||||||
|
v-for="item in typeNameOption" |
||||||
|
:label="item.label" |
||||||
|
:value="item.value" |
||||||
|
:key="item.value" |
||||||
|
/> |
||||||
|
</el-select> |
||||||
|
</el-col> |
||||||
|
<el-col :span="8"> |
||||||
|
<el-button |
||||||
|
type="primary" |
||||||
|
@click="updateIpv6ConfigParam('deviceTypeId')" |
||||||
|
>修改 |
||||||
|
</el-button> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item |
||||||
|
label="采集组件" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
<el-row :gutter="20"> |
||||||
|
<el-col :span="16"> |
||||||
|
<el-select |
||||||
|
v-model="acquisitionComponents" |
||||||
|
placeholder="请选择采集组件" |
||||||
|
clearable |
||||||
|
> |
||||||
|
<el-option label="queryIpv6Info" value="queryIpv6Info" /> |
||||||
|
</el-select> |
||||||
|
</el-col> |
||||||
|
<el-col :span="8"> |
||||||
|
<el-button |
||||||
|
type="primary" |
||||||
|
disabled |
||||||
|
@click="updateIpv6ConfigParam('collectStrId')" |
||||||
|
>修改 |
||||||
|
</el-button> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item |
||||||
|
label="导入设备序列号" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
<el-row :gutter="20"> |
||||||
|
<el-col :span="16"> |
||||||
|
<el-upload |
||||||
|
drag |
||||||
|
action="#" |
||||||
|
:limit="1" |
||||||
|
:auto-upload="false" |
||||||
|
accept="text/plain" |
||||||
|
v-model:file-list="fileList" |
||||||
|
> |
||||||
|
<el-icon class="el-icon--upload"> |
||||||
|
<upload-filled /> |
||||||
|
</el-icon> |
||||||
|
<div class="el-upload__text">拖拽上传 或 <em>点击上传</em></div> |
||||||
|
<template #tip> |
||||||
|
<div |
||||||
|
style=" |
||||||
|
margin-top: 7px; |
||||||
|
color: var(--el-text-color-regular); |
||||||
|
font-size: 12px; |
||||||
|
" |
||||||
|
> |
||||||
|
(仅支持txt文件按列排序) |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
</el-upload> |
||||||
|
</el-col> |
||||||
|
<el-col :span="8" style="display: flex; margin: auto 0"> |
||||||
|
<div> |
||||||
|
<el-button type="primary" @click="handUpload" |
||||||
|
>提交文件</el-button |
||||||
|
> |
||||||
|
</div> |
||||||
|
</el-col> |
||||||
|
</el-row> |
||||||
|
</el-descriptions-item> |
||||||
|
</el-descriptions> |
||||||
|
</el-card> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { Grid, UploadFilled } from "@element-plus/icons-vue"; |
||||||
|
import { reportArea } from "@/api/report"; |
||||||
|
import { getTypeNameOption, getVendorNameOption } from "@/api/device-type"; |
||||||
|
import { UploadUserFile } from "element-plus"; |
||||||
|
import { confirm } from "@/utils/confirm"; |
||||||
|
import { updateIpv6Config, uploadDevSnoApi } from "@/api/ipv6Config"; |
||||||
|
|
||||||
|
defineOptions({ |
||||||
|
name: "Ipv6CollectingConfig", |
||||||
|
inheritAttrs: false, |
||||||
|
}); |
||||||
|
const fileList = ref<UploadUserFile[]>([]); |
||||||
|
const loading = ref<boolean>(false); |
||||||
|
const area = ref<number>(); |
||||||
|
const subarea = ref<number>(); |
||||||
|
const rgMode = ref<string>(); |
||||||
|
const category = ref<string>(); |
||||||
|
const typeName = ref<string>(); |
||||||
|
const acquisitionComponents = ref<string>(); |
||||||
|
const areaOption = ref<OptionType[]>([]); |
||||||
|
const subareaOption = ref<OptionType[]>([]); |
||||||
|
const vendorNameOption = ref<OptionType[]>([]); |
||||||
|
const typeNameOption = ref<OptionType[]>([]); |
||||||
|
watch( |
||||||
|
() => area.value, |
||||||
|
() => { |
||||||
|
if (area.value === undefined) { |
||||||
|
return; |
||||||
|
} |
||||||
|
loadSubarea(area.value); |
||||||
|
} |
||||||
|
); |
||||||
|
const loadSubarea = (groupId: number) => { |
||||||
|
reportArea(groupId).then(({ data }) => { |
||||||
|
subareaOption.value = data; |
||||||
|
}); |
||||||
|
}; |
||||||
|
const loadArea = (groupId: number) => { |
||||||
|
reportArea(groupId).then(({ data }) => { |
||||||
|
areaOption.value.push(...data); |
||||||
|
}); |
||||||
|
}; |
||||||
|
const loadVendorNameOption = () => { |
||||||
|
getVendorNameOption().then(({ data }) => { |
||||||
|
vendorNameOption.value.push(...data); |
||||||
|
}); |
||||||
|
}; |
||||||
|
const loadTypeNameOption = () => { |
||||||
|
getTypeNameOption("").then(({ data }) => { |
||||||
|
typeNameOption.value.push(...data); |
||||||
|
}); |
||||||
|
}; |
||||||
|
const updateIpv6ConfigParam = (param: string) => { |
||||||
|
let param2 = ""; |
||||||
|
switch (param) { |
||||||
|
case "areaId": |
||||||
|
param2 = area.value; |
||||||
|
break; |
||||||
|
case "subAreaId": |
||||||
|
param2 = subarea.value; |
||||||
|
break; |
||||||
|
case "routeId": |
||||||
|
param2 = rgMode.value; |
||||||
|
break; |
||||||
|
case "devVendorName": |
||||||
|
param2 = category.value; |
||||||
|
break; |
||||||
|
case "deviceTypeId": |
||||||
|
param2 = typeName.value; |
||||||
|
break; |
||||||
|
case "collectStrId": |
||||||
|
param2 = acquisitionComponents.value; |
||||||
|
break; |
||||||
|
} |
||||||
|
if (param2 === "" || param2 == undefined) { |
||||||
|
param2 = "-1"; |
||||||
|
} |
||||||
|
confirm("确定修改吗", () => { |
||||||
|
loading.value = true; |
||||||
|
updateIpv6Config(param, param2) |
||||||
|
.then(() => { |
||||||
|
ElMessage({ |
||||||
|
message: "修改成功", |
||||||
|
type: "success", |
||||||
|
duration: 1000, |
||||||
|
}); |
||||||
|
}) |
||||||
|
.finally(() => { |
||||||
|
loading.value = false; |
||||||
|
}); |
||||||
|
}); |
||||||
|
}; |
||||||
|
const handUpload = () => { |
||||||
|
if (fileList.value.length === 0) { |
||||||
|
ElMessage({ |
||||||
|
message: "请选择需要上传的文件", |
||||||
|
type: "error", |
||||||
|
duration: 1000, |
||||||
|
}); |
||||||
|
return; |
||||||
|
} |
||||||
|
const file = fileList.value[0].raw; |
||||||
|
let fileType = file?.type; |
||||||
|
if (fileType != "text/plain") { |
||||||
|
ElMessage({ |
||||||
|
message: "文件类型错误", |
||||||
|
type: "error", |
||||||
|
duration: 1000, |
||||||
|
}); |
||||||
|
return; |
||||||
|
} |
||||||
|
confirm("确定提交文件吗", () => { |
||||||
|
loading.value = true; |
||||||
|
uploadDevSnoApi(file) |
||||||
|
.then(() => { |
||||||
|
ElMessage({ |
||||||
|
message: "操作成功", |
||||||
|
duration: 1000, |
||||||
|
type: "success", |
||||||
|
}); |
||||||
|
}) |
||||||
|
.finally(() => { |
||||||
|
loading.value = false; |
||||||
|
}); |
||||||
|
}); |
||||||
|
}; |
||||||
|
onMounted(() => { |
||||||
|
loadArea(0); |
||||||
|
loadVendorNameOption(); |
||||||
|
loadTypeNameOption(); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
:deep(.el-card__body) { |
||||||
|
padding: 10px 0 0 0; |
||||||
|
} |
||||||
|
|
||||||
|
:deep(.my-label) { |
||||||
|
width: 10px !important; |
||||||
|
background: var(--el-color-white) !important; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,110 @@ |
|||||||
|
<template> |
||||||
|
<div class="app-container"> |
||||||
|
<el-card shadow="never"> |
||||||
|
<template #header> |
||||||
|
<div style="display: flex; align-items: center"> |
||||||
|
<el-icon size="15"> <Grid /> </el-icon> <span |
||||||
|
style="font-weight: 700; font-size: 14px; line-height: 16px" |
||||||
|
>远程操作任务信息</span |
||||||
|
> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<el-descriptions v-loading="loading" :column="1" border> |
||||||
|
<el-descriptions-item |
||||||
|
label="创建人" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
{{ result.userName }} |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item |
||||||
|
label="创建时间" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
{{ result.operTaskCreateTime }} |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item |
||||||
|
label="开始时间" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
{{ result.operStartTime }} |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item |
||||||
|
label="结束时间" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
{{ result.operEndTime }} |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item |
||||||
|
label="结果" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
{{ result.resultState }} |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item |
||||||
|
label="原因" |
||||||
|
label-align="left" |
||||||
|
align="left" |
||||||
|
label-class-name="my-label" |
||||||
|
class-name="my-content" |
||||||
|
width="150px" |
||||||
|
> |
||||||
|
{{ result.errorDesc }} |
||||||
|
</el-descriptions-item> |
||||||
|
</el-descriptions> |
||||||
|
</el-card> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { Grid } from "@element-plus/icons-vue"; |
||||||
|
import { OperateTask2ResultVO } from "@/api/operate-task2/types"; |
||||||
|
import { taskResult } from "@/api/operate-task2"; |
||||||
|
const route = useRoute(); |
||||||
|
let taskId: number = parseInt(<string>route.params.taskId); |
||||||
|
const result = ref<OperateTask2ResultVO>({}); |
||||||
|
const loading = ref<boolean>(false); |
||||||
|
|
||||||
|
const getData = () => { |
||||||
|
loading.value = false; |
||||||
|
taskResult(taskId) |
||||||
|
.then(({ data }) => { |
||||||
|
result.value = data; |
||||||
|
}) |
||||||
|
.finally(() => { |
||||||
|
loading.value = false; |
||||||
|
}); |
||||||
|
}; |
||||||
|
onMounted(() => { |
||||||
|
getData(); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
:deep(.my-label) { |
||||||
|
width: 80px !important; |
||||||
|
background: var(--el-color-white) !important; |
||||||
|
} |
||||||
|
:deep(.el-card__body) { |
||||||
|
padding: 10px 0 0 0; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,254 @@ |
|||||||
|
<template> |
||||||
|
<div class="app-container"> |
||||||
|
<div class="flex justify-between"> |
||||||
|
<div class="card mr-1 ml-3"> |
||||||
|
<div> |
||||||
|
<el-image |
||||||
|
class="parent-img" |
||||||
|
style="border-radius: 10px 10px 0 0" |
||||||
|
:src="personUrl" |
||||||
|
/> |
||||||
|
<el-avatar |
||||||
|
:size="100" |
||||||
|
shape="circle" |
||||||
|
fit="cover" |
||||||
|
class="child-avatar" |
||||||
|
:src="avatarUrl" |
||||||
|
/> |
||||||
|
<div class="user-info"> |
||||||
|
<div class="username">{{ userStore.user.username }}</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="wh-full"> |
||||||
|
<el-card shadow="never"> |
||||||
|
<template #header> |
||||||
|
<div style="display: flex; align-items: center"> |
||||||
|
<el-icon size="15"> <Grid /> </el-icon> <span |
||||||
|
style="font-weight: 700; font-size: 14px; line-height: 16px" |
||||||
|
>更改密码</span |
||||||
|
> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
<el-form |
||||||
|
:model="formData" |
||||||
|
ref="ruleFormRef" |
||||||
|
:rules="rules" |
||||||
|
size="large" |
||||||
|
v-loading="loading" |
||||||
|
label-position="top" |
||||||
|
> |
||||||
|
<el-form-item label="当前密码" prop="oldPwd"> |
||||||
|
<el-input |
||||||
|
placeholder="请输入当前密码" |
||||||
|
v-model="formData.oldPwd" |
||||||
|
type="password" |
||||||
|
show-password |
||||||
|
/> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="新密码" prop="newPwd"> |
||||||
|
<el-input |
||||||
|
placeholder="请输入新密码密码" |
||||||
|
v-model="formData.newPwd" |
||||||
|
type="password" |
||||||
|
show-password |
||||||
|
/> |
||||||
|
<div class="flex justify-end w-full mt-2"> |
||||||
|
<div class="bar w-20" :style="{ backgroundColor: weakColor }"> |
||||||
|
弱 |
||||||
|
</div> |
||||||
|
<div class="bar w-20" :style="{ backgroundColor: middleColor }"> |
||||||
|
中 |
||||||
|
</div> |
||||||
|
<div class="bar w-20" :style="{ backgroundColor: strongColor }"> |
||||||
|
强 |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="确认新密码密码" prop="lastPwd"> |
||||||
|
<el-input |
||||||
|
placeholder="请输入新密码密码" |
||||||
|
v-model="formData.lastPwd" |
||||||
|
type="password" |
||||||
|
show-password |
||||||
|
/> |
||||||
|
</el-form-item> |
||||||
|
</el-form> |
||||||
|
<template #footer> |
||||||
|
<div class="flex justify-end"> |
||||||
|
<el-button type="primary" @click="submitForm(ruleFormRef)" |
||||||
|
>保 存</el-button |
||||||
|
> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
</el-card> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { Grid } from "@element-plus/icons-vue"; |
||||||
|
import { useUserStore } from "@/store"; |
||||||
|
import { FormInstance, FormRules } from "element-plus"; |
||||||
|
import { checkPasswordRule, level } from "@/utils/checkPwd"; |
||||||
|
import { PasswordForm } from "@/api/user/types"; |
||||||
|
import { confirm } from "@/utils/confirm"; |
||||||
|
import { updateUserPwd } from "@/api/user"; |
||||||
|
const userStore = useUserStore(); |
||||||
|
const ruleFormRef = ref<FormInstance>(); |
||||||
|
const loading = ref<boolean>(false); |
||||||
|
const route = useRoute(); |
||||||
|
const router = useRouter(); |
||||||
|
const formData = ref<PasswordForm>({ |
||||||
|
oldPwd: "", |
||||||
|
newPwd: "", |
||||||
|
lastPwd: "", |
||||||
|
}); |
||||||
|
const personUrl = ref( |
||||||
|
new URL(`../../assets/images/person_bg.jpg`, import.meta.url).href |
||||||
|
); |
||||||
|
const avatarUrl = ref( |
||||||
|
new URL(`../../assets/images/avatar.png`, import.meta.url).href |
||||||
|
); |
||||||
|
// 强度条颜色 |
||||||
|
const weakColor = ref<string>(""); |
||||||
|
const middleColor = ref<string>(""); |
||||||
|
const strongColor = ref<string>(""); |
||||||
|
watch( |
||||||
|
() => formData.value.newPwd, |
||||||
|
(newVal) => { |
||||||
|
if (formData.value.newPwd?.length === 0) { |
||||||
|
weakColor.value = ""; |
||||||
|
return; |
||||||
|
} |
||||||
|
let scores = level(<string>newVal); |
||||||
|
if (scores > 80) { |
||||||
|
strongColor.value = "#00c6ee"; |
||||||
|
} else { |
||||||
|
strongColor.value = ""; |
||||||
|
} |
||||||
|
if (scores > 70) { |
||||||
|
middleColor.value = "#00c6ee"; |
||||||
|
} else { |
||||||
|
middleColor.value = ""; |
||||||
|
} |
||||||
|
if (scores > 0) { |
||||||
|
weakColor.value = "#00c6ee"; |
||||||
|
} else { |
||||||
|
weakColor.value = ""; |
||||||
|
} |
||||||
|
} |
||||||
|
); |
||||||
|
const rules = reactive<FormRules<PasswordForm>>({ |
||||||
|
oldPwd: [{ required: true, message: "请输入当前密码", trigger: "blur" }], |
||||||
|
newPwd: [ |
||||||
|
{ |
||||||
|
validator: (rule: any, value: any, callback: any) => { |
||||||
|
if (value === undefined) { |
||||||
|
callback(new Error("请输入密码")); |
||||||
|
} else if (value.length < 12) { |
||||||
|
callback(new Error("密码必须大于12位")); |
||||||
|
} else { |
||||||
|
const result: string = checkPasswordRule( |
||||||
|
value, |
||||||
|
<string>userStore.user.username |
||||||
|
); |
||||||
|
if (result === "校验通过") { |
||||||
|
callback(); |
||||||
|
} else { |
||||||
|
callback(new Error(result)); |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
required: true, |
||||||
|
trigger: "blur", |
||||||
|
}, |
||||||
|
], |
||||||
|
lastPwd: [ |
||||||
|
{ |
||||||
|
required: true, |
||||||
|
validator: (rule: any, value: any, callback: any) => { |
||||||
|
if (formData.value.newPwd === undefined) { |
||||||
|
callback(new Error("请先输入新密码")); |
||||||
|
} else if (value === undefined) { |
||||||
|
callback(new Error("请输入确认密码")); |
||||||
|
} else if (formData.value.newPwd != formData.value.lastPwd) { |
||||||
|
callback(new Error("两次密码不一致")); |
||||||
|
} else { |
||||||
|
callback(); |
||||||
|
} |
||||||
|
}, |
||||||
|
trigger: "blur", |
||||||
|
}, |
||||||
|
], |
||||||
|
}); |
||||||
|
const submitForm = async (formEl: FormInstance | undefined) => { |
||||||
|
if (!formEl) return; |
||||||
|
await formEl.validate((valid, fields) => { |
||||||
|
if (valid) { |
||||||
|
confirm("确认修改密码吗", () => { |
||||||
|
loading.value = true; |
||||||
|
updateUserPwd(formData.value) |
||||||
|
.then(() => { |
||||||
|
router.push(`/login?redirect=${route.fullPath}`); |
||||||
|
}) |
||||||
|
.finally(() => { |
||||||
|
loading.value = false; |
||||||
|
}); |
||||||
|
}); |
||||||
|
} else { |
||||||
|
console.log("error submit!", fields); |
||||||
|
} |
||||||
|
}); |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
.card { |
||||||
|
/* 设置卡片的宽度 */ |
||||||
|
width: 600px; |
||||||
|
/* 设置卡片的高度(可选,根据需要设置) */ |
||||||
|
/* height: 200px; */ |
||||||
|
/* 设置卡片的背景颜色 */ |
||||||
|
background-color: #fff; |
||||||
|
/* 设置卡片的边框(可选) */ |
||||||
|
border: 1px solid #ddd; |
||||||
|
/* 设置卡片的圆角 */ |
||||||
|
border-radius: 10px; /* 你可以根据需要调整这个值 */ |
||||||
|
/* 设置卡片的盒子模型为border-box,这样padding和border就不会增加元素的宽度和高度 */ |
||||||
|
box-sizing: border-box; |
||||||
|
} |
||||||
|
.parent-img { |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
.child-avatar { |
||||||
|
position: relative; |
||||||
|
top: -50px; |
||||||
|
left: 38%; |
||||||
|
} |
||||||
|
.user-info { |
||||||
|
position: relative; |
||||||
|
top: -50px; |
||||||
|
.username { |
||||||
|
text-align: center; |
||||||
|
font-size: 22px; |
||||||
|
font-weight: 400; |
||||||
|
color: #344767; |
||||||
|
} |
||||||
|
.other-info { |
||||||
|
margin-left: 50px; |
||||||
|
margin-right: 50px; |
||||||
|
color: #677481; |
||||||
|
} |
||||||
|
} |
||||||
|
.bar { |
||||||
|
height: 8px; |
||||||
|
background-color: #dcdfe6; |
||||||
|
margin-right: 3px; |
||||||
|
border-radius: 4px; |
||||||
|
transition: 0.5s all ease; |
||||||
|
text-align: center; |
||||||
|
color: #606266; |
||||||
|
} |
||||||
|
</style> |
Loading…
Reference in new issue