Compare commits

..

2 Commits

  1. 21
      src/api/ipv6Config/index.ts
  2. 12
      src/api/operate-task2/index.ts
  3. 15
      src/api/operate-task2/types.ts
  4. 9
      src/api/user/index.ts
  5. 5
      src/api/user/types.ts
  6. BIN
      src/assets/images/avatar.png
  7. BIN
      src/assets/images/person_bg.jpg
  8. 5
      src/layout/components/NavBar/components/NavbarRight.vue
  9. 25
      src/router/index.ts
  10. 289
      src/utils/checkPwd.ts
  11. 382
      src/views/family/operate/ipv6CollectingConfig/index.vue
  12. 12
      src/views/family/operate/remote-operation/components/DeviceTaskTable.vue
  13. 18
      src/views/family/operate/remote-operation/index.vue
  14. 110
      src/views/family/operate/task/components/TaskResult.vue
  15. 13
      src/views/family/operate/task/index.vue
  16. 254
      src/views/personal/index.vue
  17. 13
      src/views/resources/tr069/components/Tr069Tree.vue
  18. 13
      src/views/resources/tr069/index.vue
  19. 2
      src/views/system/role/index.vue

@ -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",
},
});
}

@ -1,8 +1,8 @@
import request from "@/utils/request";
import { AxiosPromise } from "axios";
import {
OperateTask2PageResult,
OperateTask2TableVO,
OperateTask2PageResult, OperateTask2ResultVO,
OperateTask2TableVO
} from "@/api/operate-task2/types";
export function operateTask2Page(
@ -24,3 +24,11 @@ export function taskTablePage(
data,
});
}
export function taskResult(
taskId?: number
): AxiosPromise<OperateTask2ResultVO> {
return request({
url: `/api/operate-task2/v1/task-result/${taskId}`,
method: "GET",
});
}

@ -14,3 +14,18 @@ export interface OperateTask2TableVO {
resultState?: string;
}
export type OperateTask2PageResult = PageResult<OperateTask2TableVO[]>;
export interface OperateTask2ResultVO {
operTaskId?: number;
userName?: number;
errorDesc?: string;
operTaskCreateTime?: string;
operStartTime?: string;
operEndTime?: string;
resultState?: string;
}

@ -1,6 +1,6 @@
import request from "@/utils/request";
import { AxiosPromise } from "axios";
import { UserForm, UserInfo, UserPageVO, UserQuery } from "./types";
import { PasswordForm, UserForm, UserInfo, UserPageVO, UserQuery } from "./types";
/**
*
@ -138,3 +138,10 @@ export function importUser(deptId: number, file: File) {
},
});
}
export function updateUserPwd(data: PasswordForm) {
return request({
url: "/api/v1/users/update-user-pwd",
method: "POST",
data,
});
}

@ -122,3 +122,8 @@ export interface UserForm {
*/
domainGroupId?: number;
}
export interface PasswordForm {
oldPwd?: string;
newPwd?: string;
lastPwd?: string;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 KiB

@ -28,7 +28,7 @@
</div>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>个人中心</el-dropdown-item>
<el-dropdown-item @click="skipPersonal">个人中心</el-dropdown-item>
<el-dropdown-item divided @click="logout">
注销登出
</el-dropdown-item>
@ -86,6 +86,9 @@ function logout() {
});
});
}
const skipPersonal = () => {
router.push(`/resources/personal-center`);
};
</script>
<style lang="scss" scoped>
.setting-item {

@ -414,15 +414,34 @@ export const constantRoutes: RouteRecordRaw[] = [
path: "/resources/device-type/add",
name: "AddDeviceType",
component: () =>
import(
"@/views/resources/device-type/components/AddDeviceType.vue"
),
import("@/views/resources/device-type/components/AddDeviceType.vue"),
meta: {
hidden: true,
keepAlive: true,
title: "新增设备类型",
},
},
{
path: "/resources/task-result/:taskId",
name: "TaskResult",
component: () =>
import("@/views/family/operate/task/components/TaskResult.vue"),
meta: {
hidden: true,
keepAlive: true,
title: "任务详情",
},
},
{
path: "/resources/personal-center",
name: "Personal",
component: () => import("@/views/personal/index.vue"),
meta: {
hidden: true,
keepAlive: true,
title: "个人中心",
},
},
],
},
];

@ -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>&nbsp;<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>

@ -20,9 +20,12 @@
<el-table :data="tableData" v-loading="loading" max-height="500">
<el-table-column label="任务编号" prop="operTaskId" align="center">
<template #default="scope">
<el-button type="primary" link>{{
scope.row.operTaskId
}}</el-button>
<el-button
type="primary"
@click="skipTaskResult(scope.row.operTaskId)"
link
>{{ scope.row.operTaskId }}</el-button
>
</template>
</el-table-column>
<el-table-column label="AD编号" prop="devAdNo" align="center" />
@ -73,6 +76,9 @@ const getData = () => {
loading.value = false;
});
};
const skipTaskResult = (taskId: number) => {
router.push({ path: `/resources/task-result/${taskId}` });
};
onMounted(() => {
getData();
});

@ -62,10 +62,7 @@
v-if="columns[0].show"
>
<template #default="scope">
<el-button
type="primary"
link
@click="skipRemoteInfo(scope.row)"
<el-button type="primary" link @click="skipRemoteInfo(scope.row)"
>{{ scope.row.devVendorOui }}-{{ scope.row.devSno }}</el-button
>
</template>
@ -175,6 +172,9 @@ const total = ref<number>(0);
const options = ref<OptionType[]>([
{ label: "设备序列号", value: "devSno" },
{ label: "设备AD编号", value: "devAdNo" },
{ label: "逻辑ID", value: "logicId" },
{ label: "IP查询", value: "devIp" },
{ label: "设备PPPOE账号", value: "pppoeAccount" },
]);
const loading = ref<boolean>(false);
const buttonColSpan = computed(() => {
@ -204,6 +204,16 @@ const handleQuery = () => {
if (queryForm.value.selectValue === undefined) {
return;
}
if (
queryForm.value.selectName === "devSno" &&
queryForm.value.selectValue.length < 8
) {
ElMessage.error({
message: "请至少输入8位序列号",
duration: 1000,
});
return;
}
loading.value = true;
remoteTablePage(queryForm.value)
.then(({ data }) => {

@ -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>&nbsp;<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>

@ -3,14 +3,19 @@
<el-card>
<template #header>
<div class="head-parent-right">
<el-button :icon="Refresh" type="primary" @click="getData">刷新</el-button>
<el-button :icon="Refresh" type="primary" @click="getData"
>刷新</el-button
>
</div>
</template>
<div class="any-table">
<el-table :data="tableData" v-loading="loading" max-height="500">
<el-table-column label="任务编号" prop="operTaskId" align="center">
<template #default="scope">
<el-button type="primary" link
<el-button
type="primary"
link
@click="skipTaskResult(scope.row.operTaskId)"
>{{ scope.row.operTaskId }}
</el-button>
</template>
@ -50,6 +55,7 @@ defineOptions({
inheritAttrs: false,
});
const tableData = ref<OperateTask2TableVO[]>([]);
const router = useRouter();
const total = ref<number>(0);
const queryForm = ref<PageQuery>({ pageNum: 1, pageSize: 10 });
const loading = ref<boolean>(false);
@ -64,6 +70,9 @@ const getData = () => {
loading.value = false;
});
};
const skipTaskResult = (taskId: number) => {
router.push({ path: `/resources/task-result/${taskId}` });
};
onMounted(() => {
getData();
});

@ -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>&nbsp;<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>

@ -20,6 +20,13 @@
<el-button type="primary" @click="submitForm(tr069FormRef)"
><el-icon><EditPen /></el-icon></el-button
>
<el-button
type="primary"
v-hasPerm="['tr069:index:import']"
@click="openTr069FileForm"
plain
><i-ep-plus />导入TR069文件</el-button
>
</template>
<el-descriptions-item
label="TR-069数据模型版本"
@ -91,6 +98,7 @@
</el-scrollbar>
</div>
</el-card>
<add-tr069-file ref="addTr069FileRef" />
</div>
</template>
@ -105,6 +113,7 @@ import {
getTr069XmlTree,
} from "@/api/tr069";
import { FormInstance, FormRules } from "element-plus";
import AddTr069File from "@/views/resources/tr069/components/AddTr069File.vue";
const route = useRoute();
let tr069VerId: number = parseInt(<string>route.params?.tr069VerId);
@ -168,6 +177,10 @@ const handleAdd = () => {
loadingForm.value = false;
});
};
const addTr069FileRef = ref();
const openTr069FileForm = () => {
addTr069FileRef.value.open("3", "新增TR-069数据模型文件");
};
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid, fields) => {

@ -11,13 +11,7 @@
@click="goto(-999, -999)"
><i-ep-plus />新增</el-button
>
<el-button
type="primary"
v-hasPerm="['tr069:index:import']"
@click="openTr069FileForm"
plain
><i-ep-plus />导入TR069文件</el-button
>
<el-button @click="loadTr069Page" plain
><i-ep-refresh />刷新</el-button
>
@ -106,7 +100,6 @@
@pagination="loadTr069Page"
/>
</div>
<add-tr069-file ref="addTr069FileRef" />
</div>
</template>
@ -150,10 +143,6 @@ const goto = (tr069VerId?: number, fileId?: number) => {
path: `/resources/tr069-tree/${tr069VerId}/${fileId}`,
});
};
const addTr069FileRef = ref();
const openTr069FileForm = () => {
addTr069FileRef.value.open("3", "新增TR-069数据模型文件");
};
const skipDevTypeSoftVerList = (tr069VerId?: number) => {
router.push({
path: `/resources/tr069-dev-type-soft-ver/${tr069VerId}`,

@ -27,7 +27,7 @@ const total = ref(0);
const queryParams = reactive<RoleQuery>({
pageNum: 1,
pageSize: 5,
pageSize: 10,
});
const roleList = ref<RolePageVO[]>();

Loading…
Cancel
Save