feat: 添加实训教学
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
## 静态资源
|
## 静态资源
|
||||||
|
|
||||||
将目录下文件放置到对应目录
|
将目录下文件放置到对应目录 替换约18个文件
|
||||||
|
|
||||||
- i18n 对应覆盖 src\i18n
|
- i18n 对应覆盖 src\i18n
|
||||||
- views 对应覆盖 src\views
|
- views 对应覆盖 src\views
|
||||||
|
|||||||
@@ -341,7 +341,7 @@ export default {
|
|||||||
profile: {
|
profile: {
|
||||||
phonenumber: "Phone",
|
phonenumber: "Phone",
|
||||||
email: "Email",
|
email: "Email",
|
||||||
deptName: "Department",
|
deptName: "Class",
|
||||||
postGroup: "Possession of posts",
|
postGroup: "Possession of posts",
|
||||||
roleGroup: "Ownership",
|
roleGroup: "Ownership",
|
||||||
loginIp: "Log in",
|
loginIp: "Log in",
|
||||||
@@ -506,6 +506,23 @@ export default {
|
|||||||
updateItemTip: "Confirm updating the data item with Index [{num}]?",
|
updateItemTip: "Confirm updating the data item with Index [{num}]?",
|
||||||
delItemTip: "Confirm deleting the data item with Index [{num}]?",
|
delItemTip: "Confirm deleting the data item with Index [{num}]?",
|
||||||
arrayMore: "Expand",
|
arrayMore: "Expand",
|
||||||
|
ptDiff: 'Comparison Example',
|
||||||
|
ptDiffExample: 'Example Configuration',
|
||||||
|
ptDiffSelf: 'Current Individuals',
|
||||||
|
ptDiffLoad: 'Load More',
|
||||||
|
ptDiffMerge: 'Comparative Differences',
|
||||||
|
ptDiffRest: 'Restore this version',
|
||||||
|
ptHistory: 'History',
|
||||||
|
ptReset: 'Reset To Example',
|
||||||
|
ptLoad: 'Load Current Configuration',
|
||||||
|
ptExport: "Export Excel",
|
||||||
|
ptExportTip: "Exporting NE Configuration Data to an Excel file",
|
||||||
|
ptApplyShow: 'View Student',
|
||||||
|
ptApply: 'request',
|
||||||
|
ptApplyNE: 'Application To NE',
|
||||||
|
ptApplyStu: 'Application To {ne}',
|
||||||
|
ptApplyStuRack: 'Return Request',
|
||||||
|
ptApplyStuNE: 'Application Request',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
dashboard: {
|
dashboard: {
|
||||||
@@ -1708,7 +1725,7 @@ export default {
|
|||||||
account: 'Account',
|
account: 'Account',
|
||||||
userName: 'Nick Name',
|
userName: 'Nick Name',
|
||||||
permission: 'Role',
|
permission: 'Role',
|
||||||
className: 'Department',
|
className: 'Class',
|
||||||
loginIp: 'Login Address',
|
loginIp: 'Login Address',
|
||||||
loginTime: 'Login Time',
|
loginTime: 'Login Time',
|
||||||
status: 'Status',
|
status: 'Status',
|
||||||
@@ -1733,7 +1750,7 @@ export default {
|
|||||||
userTop:'User profile',
|
userTop:'User profile',
|
||||||
sex:'User Gender',
|
sex:'User Gender',
|
||||||
email:'E-mail',
|
email:'E-mail',
|
||||||
fromClass:'Department',
|
fromClass:'Class',
|
||||||
userWork:'User position',
|
userWork:'User position',
|
||||||
userWorkPlease: 'Please select user post',
|
userWorkPlease: 'Please select user post',
|
||||||
userTip:'User Description',
|
userTip:'User Description',
|
||||||
@@ -1834,8 +1851,8 @@ export default {
|
|||||||
role:{
|
role:{
|
||||||
allScopeOptions:'All data permissions',
|
allScopeOptions:'All data permissions',
|
||||||
byMyselfScopeOptions:'Custom data permissions',
|
byMyselfScopeOptions:'Custom data permissions',
|
||||||
onlyClassScopeOptions:'Data permissions of this department',
|
onlyClassScopeOptions:'Data permissions of this class',
|
||||||
classAllScopeOptions:'Data permissions for this department and the following',
|
classAllScopeOptions:'Data permissions for this class and the following',
|
||||||
myselfScopeOptions:'Only personal data permissions',
|
myselfScopeOptions:'Only personal data permissions',
|
||||||
roleId:'Role Number',
|
roleId:'Role Number',
|
||||||
roleName:'Role Name',
|
roleName:'Role Name',
|
||||||
@@ -1876,20 +1893,20 @@ export default {
|
|||||||
batchCancel:'Batch cancellation of authorization',
|
batchCancel:'Batch cancellation of authorization',
|
||||||
},
|
},
|
||||||
dept:{
|
dept:{
|
||||||
classInfo:' Department Information',
|
classInfo:' Class Information',
|
||||||
className:'Department Name',
|
className:'Class Name',
|
||||||
classId:'Department Number',
|
classId:'Class Number',
|
||||||
classSort:'Department Sorting',
|
classSort:'Class Sorting',
|
||||||
status:'Department Status',
|
status:'Class Status',
|
||||||
createTime:'Creation Time',
|
createTime:'Creation Time',
|
||||||
highClass:'Higher Office',
|
highClass:'Higher Office',
|
||||||
emailTip:'Please input the correct email address',
|
emailTip:'Please input the correct email address',
|
||||||
phoneTip:'Please enter the correct phone number',
|
phoneTip:'Please enter the correct phone number',
|
||||||
node:'Root Node',
|
node:'Root Node',
|
||||||
delSure:'Are you sure to delete the data item with department number [{deptId}]?',
|
delSure:'Are you sure to delete the data item with class number [{deptId}]?',
|
||||||
open:'Exhibition',
|
open:'Exhibition',
|
||||||
close:'Fold',
|
close:'Fold',
|
||||||
addClass:'Add new sub-department',
|
addClass:'Add new sub-class',
|
||||||
admin:'Principal',
|
admin:'Principal',
|
||||||
phone:'Contact Number',
|
phone:'Contact Number',
|
||||||
email:'Mail',
|
email:'Mail',
|
||||||
|
|||||||
@@ -341,8 +341,8 @@ export default {
|
|||||||
profile: {
|
profile: {
|
||||||
phonenumber: "手机号码",
|
phonenumber: "手机号码",
|
||||||
email: "用户邮箱",
|
email: "用户邮箱",
|
||||||
deptName: "所属部门",
|
deptName: "所属班级",
|
||||||
postGroup: "拥有岗位",
|
postGroup: "拥有职位",
|
||||||
roleGroup: "拥有角色",
|
roleGroup: "拥有角色",
|
||||||
loginIp: "登录地址",
|
loginIp: "登录地址",
|
||||||
loginDate: "登录时间",
|
loginDate: "登录时间",
|
||||||
@@ -506,6 +506,23 @@ export default {
|
|||||||
updateItemTip: "确认更新Index为 【{num}】 的数据项?",
|
updateItemTip: "确认更新Index为 【{num}】 的数据项?",
|
||||||
delItemTip: "确认删除Index为 【{num}】 的数据项?",
|
delItemTip: "确认删除Index为 【{num}】 的数据项?",
|
||||||
arrayMore: "展开",
|
arrayMore: "展开",
|
||||||
|
ptDiff: '对比示例',
|
||||||
|
ptDiffExample: '示例配置',
|
||||||
|
ptDiffSelf: '当前个人',
|
||||||
|
ptDiffLoad: '加载更多',
|
||||||
|
ptDiffMerge: '差异对比',
|
||||||
|
ptDiffRest: '还原此版本',
|
||||||
|
ptHistory: '历史记录',
|
||||||
|
ptReset: '重置为示例',
|
||||||
|
ptLoad: '载入当前网元配置',
|
||||||
|
ptExport: "导出Excel",
|
||||||
|
ptExportTip: "导出网元配置数据到Excel文件中",
|
||||||
|
ptApplyShow: '查看学生',
|
||||||
|
ptApply: '申请',
|
||||||
|
ptApplyNE: '应用配置到网元',
|
||||||
|
ptApplyStu: '申请配置应用到 {ne}',
|
||||||
|
ptApplyStuRack: '退回该学生配置',
|
||||||
|
ptApplyStuNE: '应用该学生配置',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
dashboard: {
|
dashboard: {
|
||||||
@@ -1296,7 +1313,7 @@ export default {
|
|||||||
type:'网元类型',
|
type:'网元类型',
|
||||||
neId:'网元唯一标识',
|
neId:'网元唯一标识',
|
||||||
MML:'MML',
|
MML:'MML',
|
||||||
logTime:'log Time'
|
logTime:'记录时间',
|
||||||
},
|
},
|
||||||
forwarding:{
|
forwarding:{
|
||||||
type:'网元类型',
|
type:'网元类型',
|
||||||
@@ -1708,7 +1725,7 @@ export default {
|
|||||||
account: '登录账号',
|
account: '登录账号',
|
||||||
userName: '用户昵称',
|
userName: '用户昵称',
|
||||||
permission: '用户权限',
|
permission: '用户权限',
|
||||||
className: '部门名称',
|
className: '班级名称',
|
||||||
loginIp: '登录地址',
|
loginIp: '登录地址',
|
||||||
loginTime: '登录时间',
|
loginTime: '登录时间',
|
||||||
status: '用户状态',
|
status: '用户状态',
|
||||||
@@ -1733,9 +1750,9 @@ export default {
|
|||||||
userTop:'用户头像',
|
userTop:'用户头像',
|
||||||
sex:'用户性别',
|
sex:'用户性别',
|
||||||
email:'电子邮箱',
|
email:'电子邮箱',
|
||||||
fromClass:'所属部门',
|
fromClass:'所属班级',
|
||||||
userWork:'用户岗位',
|
userWork:'用户职位',
|
||||||
userWorkPlease: '请选择用户岗位',
|
userWorkPlease: '请选择用户职位',
|
||||||
userTip:'用户说明',
|
userTip:'用户说明',
|
||||||
loginPwd:'登录密码',
|
loginPwd:'登录密码',
|
||||||
updateSure:'是否更新已经存在的数据',
|
updateSure:'是否更新已经存在的数据',
|
||||||
@@ -1834,8 +1851,8 @@ export default {
|
|||||||
role:{
|
role:{
|
||||||
allScopeOptions:'全部数据权限',
|
allScopeOptions:'全部数据权限',
|
||||||
byMyselfScopeOptions:'自定数据权限',
|
byMyselfScopeOptions:'自定数据权限',
|
||||||
onlyClassScopeOptions:'本部门数据权限',
|
onlyClassScopeOptions:'本班级数据权限',
|
||||||
classAllScopeOptions:'本部门及以下数据权限',
|
classAllScopeOptions:'本班级及以下数据权限',
|
||||||
myselfScopeOptions:'仅本人数据权限',
|
myselfScopeOptions:'仅本人数据权限',
|
||||||
roleId:'角色编号',
|
roleId:'角色编号',
|
||||||
roleName:'角色名称',
|
roleName:'角色名称',
|
||||||
@@ -1876,36 +1893,36 @@ export default {
|
|||||||
batchCancel:'批量取消授权',
|
batchCancel:'批量取消授权',
|
||||||
},
|
},
|
||||||
dept:{
|
dept:{
|
||||||
classInfo:'部门信息',
|
classInfo:'班级信息',
|
||||||
className:'部门名称',
|
className:'班级名称',
|
||||||
classId:'部门编号',
|
classId:'班级编号',
|
||||||
classSort:'部门排序',
|
classSort:'班级排序',
|
||||||
status:'部门状态',
|
status:'班级状态',
|
||||||
createTime:'创建时间',
|
createTime:'创建时间',
|
||||||
highClass:'上级部门',
|
highClass:'上级班级',
|
||||||
emailTip:'请输入正确的邮箱地址',
|
emailTip:'请输入正确的邮箱地址',
|
||||||
phoneTip:'请输入正确的手机号码',
|
phoneTip:'请输入正确的手机号码',
|
||||||
node:'根节点',
|
node:'根节点',
|
||||||
delSure:'确认删除部门编号为 【{deptId}】 的数据项?',
|
delSure:'确认删除班级编号为 【{deptId}】 的数据项?',
|
||||||
open:'展',
|
open:'展',
|
||||||
close:'折',
|
close:'折',
|
||||||
addClass:'新增子部门',
|
addClass:'新增子班级',
|
||||||
admin:'负责人',
|
admin:'负责人',
|
||||||
phone:'联系电话',
|
phone:'联系电话',
|
||||||
email:'邮箱',
|
email:'邮箱',
|
||||||
},
|
},
|
||||||
post:{
|
post:{
|
||||||
positionInfo:'岗位信息',
|
positionInfo:'职位信息',
|
||||||
positionId:'岗位编号',
|
positionId:'职位编号',
|
||||||
positionCode:'岗位编码',
|
positionCode:'职位编码',
|
||||||
positionName:'岗位名称',
|
positionName:'职位名称',
|
||||||
positionSort:'岗位排序',
|
positionSort:'职位排序',
|
||||||
positionStatus:'岗位状态',
|
positionStatus:'职位状态',
|
||||||
positionMark:'岗位说明',
|
positionMark:'职位说明',
|
||||||
createTime:'创建时间',
|
createTime:'创建时间',
|
||||||
codeTip:'请正确输入岗位编码',
|
codeTip:'请正确输入职位编码',
|
||||||
nameTip:'请正确输入岗位名称',
|
nameTip:'请正确输入职位名称',
|
||||||
delSure:'确认删除岗位编号为 【{postId}】 的数据项?',
|
delSure:'确认删除职位编号为 【{postId}】 的数据项?',
|
||||||
},
|
},
|
||||||
log:{
|
log:{
|
||||||
operate:{
|
operate:{
|
||||||
|
|||||||
713
src/views/configManage/configParamApply/index.vue
Normal file
713
src/views/configManage/configParamApply/index.vue
Normal file
@@ -0,0 +1,713 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, onMounted, toRaw, computed } from 'vue';
|
||||||
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
|
import { ProModal } from 'antdv-pro-modal';
|
||||||
|
import { Form, message, Modal } from 'ant-design-vue/es';
|
||||||
|
import { SizeType } from 'ant-design-vue/es/config-provider';
|
||||||
|
import { MenuInfo } from 'ant-design-vue/es/menu/src/interface';
|
||||||
|
import { ColumnsType } from 'ant-design-vue/es/table';
|
||||||
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
|
import useDictStore from '@/store/modules/dict';
|
||||||
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
import {
|
||||||
|
getPtNeConfigApplyList,
|
||||||
|
stuPtNeConfigApply,
|
||||||
|
updatePtNeConfigApply,
|
||||||
|
} from '@/api/pt/neConfigApply';
|
||||||
|
import { hasRoles } from '@/plugins/auth-user';
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { getDict } = useDictStore();
|
||||||
|
const neInfoStore = useNeInfoStore();
|
||||||
|
|
||||||
|
/**字典数据 */
|
||||||
|
let dict: {
|
||||||
|
/**配置申请应用状态 */
|
||||||
|
ptConfigApplyStatus: DictType[];
|
||||||
|
} = reactive({
|
||||||
|
ptConfigApplyStatus: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**查询参数 */
|
||||||
|
let queryParams = reactive({
|
||||||
|
/**网元类型 */
|
||||||
|
neType: '',
|
||||||
|
/**申请人 */
|
||||||
|
createBy: '',
|
||||||
|
/**状态 */
|
||||||
|
status: undefined,
|
||||||
|
/**当前页数 */
|
||||||
|
pageNum: 1,
|
||||||
|
/**每页条数 */
|
||||||
|
pageSize: 20,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**查询参数重置 */
|
||||||
|
function fnQueryReset() {
|
||||||
|
queryParams = Object.assign(queryParams, {
|
||||||
|
neType: '',
|
||||||
|
createBy: '',
|
||||||
|
status: undefined,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
});
|
||||||
|
tablePagination.current = 1;
|
||||||
|
tablePagination.pageSize = 20;
|
||||||
|
fnGetList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**表格状态类型 */
|
||||||
|
type TabeStateType = {
|
||||||
|
/**加载等待 */
|
||||||
|
loading: boolean;
|
||||||
|
/**紧凑型 */
|
||||||
|
size: SizeType;
|
||||||
|
/**搜索栏 */
|
||||||
|
seached: boolean;
|
||||||
|
/**记录数据 */
|
||||||
|
data: object[];
|
||||||
|
/**勾选记录 */
|
||||||
|
selectedRowKeys: (string | number)[];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**表格状态 */
|
||||||
|
let tableState: TabeStateType = reactive({
|
||||||
|
loading: false,
|
||||||
|
size: 'middle',
|
||||||
|
seached: true,
|
||||||
|
data: [],
|
||||||
|
selectedRowKeys: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**表格字段列 */
|
||||||
|
let tableColumns: ColumnsType = [
|
||||||
|
{
|
||||||
|
title: t('common.rowId'),
|
||||||
|
dataIndex: 'id',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('views.ne.common.neType'),
|
||||||
|
dataIndex: 'neType',
|
||||||
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '申请人',
|
||||||
|
dataIndex: 'createBy',
|
||||||
|
align: 'left',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '申请时间',
|
||||||
|
dataIndex: 'createTime',
|
||||||
|
align: 'left',
|
||||||
|
width: 150,
|
||||||
|
customRender(opt) {
|
||||||
|
if (+opt.value <= 0) return '';
|
||||||
|
return parseDateToStr(+opt.value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'status',
|
||||||
|
key: 'status',
|
||||||
|
align: 'left',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '处理人',
|
||||||
|
dataIndex: 'updateBy',
|
||||||
|
align: 'left',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '处理时间',
|
||||||
|
dataIndex: 'updateTime',
|
||||||
|
align: 'left',
|
||||||
|
width: 150,
|
||||||
|
customRender(opt) {
|
||||||
|
if (+opt.value <= 0) return '';
|
||||||
|
return parseDateToStr(+opt.value);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('common.operate'),
|
||||||
|
key: 'id',
|
||||||
|
align: 'left',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**表格分页器参数 */
|
||||||
|
let tablePagination = reactive({
|
||||||
|
/**当前页数 */
|
||||||
|
current: 1,
|
||||||
|
/**每页条数 */
|
||||||
|
pageSize: 20,
|
||||||
|
/**默认的每页条数 */
|
||||||
|
defaultPageSize: 20,
|
||||||
|
/**指定每页可以显示多少条 */
|
||||||
|
pageSizeOptions: ['10', '20', '50', '100'],
|
||||||
|
/**只有一页时是否隐藏分页器 */
|
||||||
|
hideOnSinglePage: false,
|
||||||
|
/**是否可以快速跳转至某页 */
|
||||||
|
showQuickJumper: true,
|
||||||
|
/**是否可以改变 pageSize */
|
||||||
|
showSizeChanger: true,
|
||||||
|
/**数据总数 */
|
||||||
|
total: 0,
|
||||||
|
showTotal: (total: number) =>
|
||||||
|
t('common.tablePaginationTotal', { total: total }),
|
||||||
|
onChange: (page: number, pageSize: number) => {
|
||||||
|
tablePagination.current = page;
|
||||||
|
tablePagination.pageSize = pageSize;
|
||||||
|
queryParams.pageNum = page;
|
||||||
|
queryParams.pageSize = pageSize;
|
||||||
|
fnGetList();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**表格紧凑型变更操作 */
|
||||||
|
function fnTableSize({ key }: MenuInfo) {
|
||||||
|
tableState.size = key as SizeType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**表格多选 */
|
||||||
|
function fnTableSelectedRowKeys(keys: (string | number)[], infos: any) {
|
||||||
|
const arr = [];
|
||||||
|
for (const item of infos) {
|
||||||
|
if (item.status === '0') {
|
||||||
|
arr.push(item.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tableState.selectedRowKeys = arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**查询列表, pageNum初始页数 */
|
||||||
|
function fnGetList(pageNum?: number) {
|
||||||
|
if (tableState.loading) return;
|
||||||
|
tableState.loading = true;
|
||||||
|
if (pageNum) {
|
||||||
|
queryParams.pageNum = pageNum;
|
||||||
|
}
|
||||||
|
getPtNeConfigApplyList(toRaw(queryParams)).then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
// 取消勾选
|
||||||
|
if (tableState.selectedRowKeys.length > 0) {
|
||||||
|
tableState.selectedRowKeys = [];
|
||||||
|
}
|
||||||
|
tablePagination.total = res.total;
|
||||||
|
tableState.data = res.rows;
|
||||||
|
if (
|
||||||
|
tablePagination.total <=
|
||||||
|
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||||
|
queryParams.pageNum !== 1
|
||||||
|
) {
|
||||||
|
tableState.loading = false;
|
||||||
|
fnGetList(queryParams.pageNum - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tableState.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**对话框对象信息状态类型 */
|
||||||
|
type ModalStateType = {
|
||||||
|
/**详情框是否显示 */
|
||||||
|
openByView: boolean;
|
||||||
|
/**新增框或修改框是否显示 */
|
||||||
|
openByEdit: boolean;
|
||||||
|
/**标题 */
|
||||||
|
title: string;
|
||||||
|
/**表单数据 */
|
||||||
|
from: Record<string, any>;
|
||||||
|
/**确定按钮 loading */
|
||||||
|
confirmLoading: boolean;
|
||||||
|
/**cron生成框是否显示 */
|
||||||
|
openByCron: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**对话框对象信息状态 */
|
||||||
|
let modalState: ModalStateType = reactive({
|
||||||
|
openByView: false,
|
||||||
|
openByEdit: false,
|
||||||
|
title: '任务',
|
||||||
|
from: {
|
||||||
|
id: undefined,
|
||||||
|
createBy: '',
|
||||||
|
createTime: 0,
|
||||||
|
updateBy: '',
|
||||||
|
updateTime: 0,
|
||||||
|
neType: 'MME',
|
||||||
|
status: '0',
|
||||||
|
backInfo: '',
|
||||||
|
},
|
||||||
|
confirmLoading: false,
|
||||||
|
openByCron: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**对话框内表单属性和校验规则 */
|
||||||
|
const modalStateFrom = Form.useForm(
|
||||||
|
modalState.from,
|
||||||
|
reactive({
|
||||||
|
status: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t('common.selectPlease'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话框弹出显示为 查看
|
||||||
|
* @param jobId 任务id
|
||||||
|
*/
|
||||||
|
function fnModalVisibleByVive(row: Record<string, any>) {
|
||||||
|
modalState.from = Object.assign(modalState.from, row);
|
||||||
|
modalState.title = '查看';
|
||||||
|
modalState.openByView = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话框弹出显示为 编辑
|
||||||
|
* @param jobId 任务id
|
||||||
|
*/
|
||||||
|
function fnModalVisibleByEdit(row: Record<string, any>) {
|
||||||
|
Object.assign(modalState.from, row);
|
||||||
|
modalState.from.status = '3';
|
||||||
|
modalState.title = '编辑状态';
|
||||||
|
modalState.openByEdit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话框弹出确认执行函数
|
||||||
|
* 进行表达规则校验
|
||||||
|
*/
|
||||||
|
function fnModalOk() {
|
||||||
|
modalStateFrom
|
||||||
|
.validate()
|
||||||
|
.then(() => {
|
||||||
|
modalState.confirmLoading = true;
|
||||||
|
const from = toRaw(modalState.from);
|
||||||
|
updatePtNeConfigApply({
|
||||||
|
applyId: from.id,
|
||||||
|
neType: from.neType,
|
||||||
|
status: from.status,
|
||||||
|
backInfo: from.backInfo,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('common.operateOk'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
|
||||||
|
modalState.openByEdit = false;
|
||||||
|
modalStateFrom.resetFields();
|
||||||
|
fnGetList();
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
modalState.confirmLoading = false;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
message.error(t('common.errorFields', { num: e.errorFields.length }), 3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对话框弹出关闭执行函数
|
||||||
|
* 进行表达规则校验
|
||||||
|
*/
|
||||||
|
function fnModalCancel() {
|
||||||
|
modalState.openByEdit = false;
|
||||||
|
modalState.openByView = false;
|
||||||
|
modalState.from = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**批量退回 */
|
||||||
|
function fnRecordBack(row?: Record<string, any>) {
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: row
|
||||||
|
? '确认要撤回配置应用申请吗?'
|
||||||
|
: '确认要批量退回学生的配置应用申请吗?',
|
||||||
|
onOk() {
|
||||||
|
let result: any;
|
||||||
|
if (row) {
|
||||||
|
result = stuPtNeConfigApply({ neType: row.neType, status: '1' });
|
||||||
|
} else {
|
||||||
|
result = updatePtNeConfigApply({
|
||||||
|
status: "3",
|
||||||
|
backId: tableState.selectedRowKeys.join(","),
|
||||||
|
backInfo: "请重新检查配置",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
result.then((res: any) => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('common.operateOk'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**应用状态 */
|
||||||
|
const applyStatus = computed(() => {
|
||||||
|
if (hasRoles(['student'])) {
|
||||||
|
return dict.ptConfigApplyStatus.filter(s => ['0', '1'].includes(s.value));
|
||||||
|
}
|
||||||
|
let data = dict.ptConfigApplyStatus;
|
||||||
|
if (modalState.openByEdit && modalState.from.id) {
|
||||||
|
data = dict.ptConfigApplyStatus.filter(s => ['2', '3'].includes(s.value));
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 初始字典数据
|
||||||
|
Promise.allSettled([getDict('pt_config_apply_status')]).then(resArr => {
|
||||||
|
if (resArr[0].status === 'fulfilled') {
|
||||||
|
dict.ptConfigApplyStatus = resArr[0].value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 获取网元列表
|
||||||
|
neInfoStore.fnNelist().finally(() => {
|
||||||
|
// 获取列表数据
|
||||||
|
fnGetList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<PageContainer>
|
||||||
|
<a-card
|
||||||
|
v-show="tableState.seached"
|
||||||
|
:bordered="false"
|
||||||
|
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
|
||||||
|
>
|
||||||
|
<!-- 表格搜索栏 -->
|
||||||
|
<a-form :model="queryParams" name="queryParams" layout="horizontal">
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.configManage.license.neType')"
|
||||||
|
name="neType "
|
||||||
|
>
|
||||||
|
<a-auto-complete
|
||||||
|
v-model:value="queryParams.neType"
|
||||||
|
:options="neInfoStore.getNeSelectOtions"
|
||||||
|
allow-clear
|
||||||
|
:placeholder="t('views.configManage.license.neTypePlease')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item label="状态" name="status">
|
||||||
|
<a-select
|
||||||
|
v-model:value="queryParams.status"
|
||||||
|
allow-clear
|
||||||
|
:placeholder="t('common.selectPlease')"
|
||||||
|
:options="applyStatus"
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item>
|
||||||
|
<a-space :size="8">
|
||||||
|
<a-button type="primary" @click.prevent="fnGetList(1)">
|
||||||
|
<template #icon><SearchOutlined /></template>
|
||||||
|
{{ t('common.search') }}
|
||||||
|
</a-button>
|
||||||
|
<a-button type="default" @click.prevent="fnQueryReset">
|
||||||
|
<template #icon><ClearOutlined /></template>
|
||||||
|
{{ t('common.reset') }}
|
||||||
|
</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
||||||
|
<!-- 插槽-卡片左侧侧 -->
|
||||||
|
<template #title>
|
||||||
|
<div class="button-container">
|
||||||
|
<a-button
|
||||||
|
type="default"
|
||||||
|
danger
|
||||||
|
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||||
|
@click.prevent="fnRecordBack()"
|
||||||
|
v-roles:has="['admin', 'teacher']"
|
||||||
|
>
|
||||||
|
<template #icon><DeleteOutlined /></template>
|
||||||
|
批量退回
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 插槽-卡片右侧 -->
|
||||||
|
<template #extra>
|
||||||
|
<div class="button-container">
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ t('common.searchBarText') }}</template>
|
||||||
|
<a-switch
|
||||||
|
v-model:checked="tableState.seached"
|
||||||
|
:checked-children="t('common.switch.show')"
|
||||||
|
:un-checked-children="t('common.switch.hide')"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ t('common.reloadText') }}</template>
|
||||||
|
<a-button type="text" @click.prevent="fnGetList()">
|
||||||
|
<template #icon><ReloadOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip placement="topRight">
|
||||||
|
<template #title>{{ t('common.sizeText') }}</template>
|
||||||
|
<a-dropdown placement="bottomRight" trigger="click">
|
||||||
|
<a-button type="text">
|
||||||
|
<template #icon><ColumnHeightOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
<template #overlay>
|
||||||
|
<a-menu
|
||||||
|
:selected-keys="[tableState.size as string]"
|
||||||
|
@click="fnTableSize"
|
||||||
|
>
|
||||||
|
<a-menu-item key="default">
|
||||||
|
{{ t('common.size.default') }}
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item key="middle">
|
||||||
|
{{ t('common.size.middle') }}
|
||||||
|
</a-menu-item>
|
||||||
|
<a-menu-item key="small">
|
||||||
|
{{ t('common.size.small') }}
|
||||||
|
</a-menu-item>
|
||||||
|
</a-menu>
|
||||||
|
</template>
|
||||||
|
</a-dropdown>
|
||||||
|
</a-tooltip>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 表格列表 -->
|
||||||
|
<a-table
|
||||||
|
class="table"
|
||||||
|
row-key="id"
|
||||||
|
:columns="tableColumns"
|
||||||
|
:loading="tableState.loading"
|
||||||
|
:data-source="tableState.data"
|
||||||
|
:size="tableState.size"
|
||||||
|
:scroll="{ x: tableColumns.length * 120 }"
|
||||||
|
:pagination="tablePagination"
|
||||||
|
:row-selection="{
|
||||||
|
type: 'checkbox',
|
||||||
|
selectedRowKeys: tableState.selectedRowKeys,
|
||||||
|
onChange: fnTableSelectedRowKeys,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.key === 'status'">
|
||||||
|
<DictTag
|
||||||
|
:options="dict.ptConfigApplyStatus"
|
||||||
|
:value="record.status"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-if="column.key === 'id'">
|
||||||
|
<a-space :size="8" align="center">
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>{{ t('common.viewText') }}</template>
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
@click.prevent="fnModalVisibleByVive(record)"
|
||||||
|
>
|
||||||
|
<template #icon><ProfileOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip v-if="record.status === '0' && hasRoles(['student'])">
|
||||||
|
<template #title>撤回</template>
|
||||||
|
<a-button type="link" @click.prevent="fnRecordBack(record)">
|
||||||
|
<template #icon><RollbackOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-tooltip
|
||||||
|
v-if="record.status === '0' && hasRoles(['admin', 'teacher'])"
|
||||||
|
>
|
||||||
|
<template #title>{{ t('common.editText') }}</template>
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
@click.prevent="fnModalVisibleByEdit(record)"
|
||||||
|
>
|
||||||
|
<template #icon><FormOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-space>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<!-- 详情框 -->
|
||||||
|
<ProModal
|
||||||
|
:drag="true"
|
||||||
|
:width="800"
|
||||||
|
:open="modalState.openByView"
|
||||||
|
:title="modalState.title"
|
||||||
|
@cancel="fnModalCancel"
|
||||||
|
>
|
||||||
|
<a-form layout="horizontal" :label-col="{ span: 6 }" :label-wrap="true">
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('views.ne.common.neType')" name="neType">
|
||||||
|
{{ modalState.from.neType }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item label="状态" name="status">
|
||||||
|
<DictTag
|
||||||
|
:options="dict.ptConfigApplyStatus"
|
||||||
|
:value="modalState.from.status"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item label="申请人" name="createBy">
|
||||||
|
{{ modalState.from.createBy }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item label="申请时间" name="createTime">
|
||||||
|
{{ parseDateToStr(+modalState.from.createTime) }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
<a-row :gutter="16" v-if="modalState.from.status !== '0'">
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item label="处理人" name="updateBy">
|
||||||
|
{{ modalState.from.updateBy }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item label="处理时间" name="updateTime">
|
||||||
|
{{ parseDateToStr(+modalState.from.updateTime) }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-form-item
|
||||||
|
v-if="modalState.from.status === '3'"
|
||||||
|
label="退回说明"
|
||||||
|
name="backInfo"
|
||||||
|
:label-col="{ span: 3 }"
|
||||||
|
:label-wrap="true"
|
||||||
|
>
|
||||||
|
{{ modalState.from.backInfo }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
<template #footer>
|
||||||
|
<a-button key="cancel" @click="fnModalCancel">
|
||||||
|
{{ t('common.close') }}
|
||||||
|
</a-button>
|
||||||
|
</template>
|
||||||
|
</ProModal>
|
||||||
|
|
||||||
|
<!-- 新增框或修改框 -->
|
||||||
|
<ProModal
|
||||||
|
:drag="true"
|
||||||
|
:width="800"
|
||||||
|
:open="modalState.openByEdit"
|
||||||
|
:title="modalState.title"
|
||||||
|
:confirm-loading="modalState.confirmLoading"
|
||||||
|
:destroyOnClose="true"
|
||||||
|
@ok="fnModalOk"
|
||||||
|
@cancel="fnModalCancel"
|
||||||
|
>
|
||||||
|
<a-form
|
||||||
|
name="modalStateFrom"
|
||||||
|
layout="horizontal"
|
||||||
|
:label-col="{ span: 6 }"
|
||||||
|
:label-wrap="true"
|
||||||
|
>
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('views.ne.common.neType')" name="neType">
|
||||||
|
{{ modalState.from.neType }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item label="申请人" name="createBy">
|
||||||
|
{{ modalState.from.createBy }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item label="申请时间" name="createTime">
|
||||||
|
{{ parseDateToStr(+modalState.from.createTime) }}
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<a-form-item
|
||||||
|
label="状态"
|
||||||
|
name="status"
|
||||||
|
:label-col="{ span: 3 }"
|
||||||
|
:label-wrap="true"
|
||||||
|
v-bind="modalStateFrom.validateInfos.status"
|
||||||
|
>
|
||||||
|
<a-select
|
||||||
|
v-model:value="modalState.from.status"
|
||||||
|
:placeholder="t('common.selectPlease')"
|
||||||
|
:options="applyStatus"
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item
|
||||||
|
v-if="modalState.from.status === '3'"
|
||||||
|
label="退回说明"
|
||||||
|
name="backInfo"
|
||||||
|
:label-col="{ span: 3 }"
|
||||||
|
:label-wrap="true"
|
||||||
|
>
|
||||||
|
<a-textarea
|
||||||
|
v-model:value="modalState.from.backInfo"
|
||||||
|
:auto-size="{ minRows: 2, maxRows: 6 }"
|
||||||
|
:maxlength="400"
|
||||||
|
:placeholder="t('common.inputPlease')"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</ProModal>
|
||||||
|
</PageContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.table :deep(.ant-pagination) {
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,327 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, onMounted, toRaw, watch } from 'vue';
|
||||||
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import CodemirrorEditeDiff from '@/components/CodemirrorEditeDiff/index.vue';
|
||||||
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
|
import {
|
||||||
|
getPtNeConfigDataLogList,
|
||||||
|
restorePtNeConfigDataLog,
|
||||||
|
} from '@/api/pt/neConfigDataLog';
|
||||||
|
import useDictStore from '@/store/modules/dict';
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const emit = defineEmits(['ok', 'cancel', 'update:open']);
|
||||||
|
const props = defineProps({
|
||||||
|
open: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
/**网元类型 */
|
||||||
|
neType: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
/**参数名 */
|
||||||
|
paramName: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
/**学生用户账号 */
|
||||||
|
student: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { getDict } = useDictStore();
|
||||||
|
|
||||||
|
/**字典数据 */
|
||||||
|
let dict: {
|
||||||
|
/**业务类型 */
|
||||||
|
sysBusinessType: DictType[];
|
||||||
|
} = reactive({
|
||||||
|
sysBusinessType: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**对话框对象信息状态类型 */
|
||||||
|
type StateType = {
|
||||||
|
/**新增框或修改框是否显示 */
|
||||||
|
openByList: boolean;
|
||||||
|
/**差异比较框是否显示 */
|
||||||
|
openByDiff: boolean;
|
||||||
|
/**标题 */
|
||||||
|
title: string;
|
||||||
|
/**加载状态 */
|
||||||
|
loading: boolean;
|
||||||
|
/**数据 */
|
||||||
|
data: Record<string, any>[];
|
||||||
|
/**差异数据 */
|
||||||
|
dataDiff: Record<string, any>;
|
||||||
|
/**确定按钮 loading */
|
||||||
|
confirmLoading: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**对话框对象信息状态 */
|
||||||
|
let state: StateType = reactive({
|
||||||
|
openByList: false,
|
||||||
|
openByDiff: false,
|
||||||
|
title: '操作参数名称-学生账号',
|
||||||
|
loading: false,
|
||||||
|
data: [],
|
||||||
|
dataDiff: {},
|
||||||
|
confirmLoading: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
function onClose() {
|
||||||
|
state.loading = false;
|
||||||
|
state.openByList = false;
|
||||||
|
state.openByDiff = false;
|
||||||
|
state.data = [];
|
||||||
|
state.dataDiff = {};
|
||||||
|
emit('cancel');
|
||||||
|
emit('update:open', false);
|
||||||
|
queryParams = {
|
||||||
|
neType: '',
|
||||||
|
paramName: '',
|
||||||
|
student: '',
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**查询参数 */
|
||||||
|
let queryParams = reactive({
|
||||||
|
/**网元类型 */
|
||||||
|
neType: '',
|
||||||
|
/**可用属性值 */
|
||||||
|
paramName: '',
|
||||||
|
/**学生账号 */
|
||||||
|
student: '',
|
||||||
|
/**当前页数 */
|
||||||
|
pageNum: 1,
|
||||||
|
/**每页条数 */
|
||||||
|
pageSize: 10,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**查询列表, pageNum初始页数 */
|
||||||
|
function fnGetList(pageNum?: number) {
|
||||||
|
if (state.loading) return;
|
||||||
|
state.loading = true;
|
||||||
|
if (pageNum) {
|
||||||
|
queryParams.pageNum = pageNum;
|
||||||
|
if (pageNum === 1) state.data = [];
|
||||||
|
}
|
||||||
|
getPtNeConfigDataLogList(toRaw(queryParams)).then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
||||||
|
// tablePagination.total = res.total;
|
||||||
|
state.data = state.data.concat(res.rows);
|
||||||
|
// 去首个做标题
|
||||||
|
if (queryParams.pageNum === 1 && state.data.length > 0) {
|
||||||
|
const item = state.data[0];
|
||||||
|
state.title = `${item.paramDisplay} - ${item.createBy}`;
|
||||||
|
}
|
||||||
|
if (state.data.length <= res.total && res.rows.length > 0) {
|
||||||
|
queryParams.pageNum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**差异比较框打开 */
|
||||||
|
function fnMergeCellOpen(row: Record<string, any>) {
|
||||||
|
state.dataDiff = row;
|
||||||
|
state.dataDiff.paramJsonOld = JSON.stringify(
|
||||||
|
JSON.parse(state.dataDiff.paramJsonOld),
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
);
|
||||||
|
state.dataDiff.paramJsonNew = JSON.stringify(
|
||||||
|
JSON.parse(state.dataDiff.paramJsonNew),
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
);
|
||||||
|
state.openByDiff = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**差异比较框关闭 */
|
||||||
|
function fnMergeCellClose() {
|
||||||
|
state.openByDiff = false;
|
||||||
|
state.dataDiff = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**差异比较还原 */
|
||||||
|
function fnMergeCellRestore(value: 'old' | 'new') {
|
||||||
|
if (state.confirmLoading) return;
|
||||||
|
const id = state.dataDiff.id;
|
||||||
|
restorePtNeConfigDataLog({ id, value })
|
||||||
|
.then((res: any) => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('common.operateOk'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
fnMergeCellClose();
|
||||||
|
fnGetList(1);
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
state.confirmLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**监听是否显示,初始数据 */
|
||||||
|
watch(
|
||||||
|
() => props.open,
|
||||||
|
val => {
|
||||||
|
if (val) {
|
||||||
|
if (props.neType && props.paramName) {
|
||||||
|
state.title = '';
|
||||||
|
state.openByList = true;
|
||||||
|
// 根据条件查询数据
|
||||||
|
queryParams.neType = props.neType;
|
||||||
|
queryParams.paramName = props.paramName;
|
||||||
|
if (props.student) {
|
||||||
|
queryParams.student = props.student;
|
||||||
|
}
|
||||||
|
fnGetList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
// 初始字典数据
|
||||||
|
Promise.allSettled([getDict('sys_oper_type')]).then(resArr => {
|
||||||
|
if (resArr[0].status === 'fulfilled') {
|
||||||
|
dict.sysBusinessType = resArr[0].value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-drawer
|
||||||
|
:width="500"
|
||||||
|
:title="state.title"
|
||||||
|
placement="right"
|
||||||
|
:open="state.openByList"
|
||||||
|
@close="onClose"
|
||||||
|
>
|
||||||
|
<a-list
|
||||||
|
class="demo-loadmore-list"
|
||||||
|
item-layout="horizontal"
|
||||||
|
:data-source="state.data"
|
||||||
|
>
|
||||||
|
<template #loadMore>
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
textAlign: 'center',
|
||||||
|
marginTop: '12px',
|
||||||
|
height: '32px',
|
||||||
|
lineHeight: '32px',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<a-button @click="fnGetList()" :loading="state.loading">
|
||||||
|
{{ t('views.configManage.configParamForm.ptDiffLoad') }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #renderItem="{ item }">
|
||||||
|
<a-list-item>
|
||||||
|
<template #actions>
|
||||||
|
<a-tooltip>
|
||||||
|
<template #title>
|
||||||
|
{{ t('views.configManage.configParamForm.ptDiffMerge') }}
|
||||||
|
</template>
|
||||||
|
<a-button type="primary" @click.prevent="fnMergeCellOpen(item)">
|
||||||
|
<template #icon><MergeCellsOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
<a-list-item-meta>
|
||||||
|
<template #title>
|
||||||
|
<DictTag
|
||||||
|
:options="dict.sysBusinessType"
|
||||||
|
:value="item.operaType"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #description>
|
||||||
|
{{ parseDateToStr(item.createTime) }}
|
||||||
|
</template>
|
||||||
|
</a-list-item-meta>
|
||||||
|
</a-list-item>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
</a-drawer>
|
||||||
|
|
||||||
|
<a-modal
|
||||||
|
:width="800"
|
||||||
|
:destroyOnClose="true"
|
||||||
|
:mask-closable="false"
|
||||||
|
v-model:open="state.openByDiff"
|
||||||
|
:footer="null"
|
||||||
|
:body-style="{ padding: 0, maxHeight: '650px', 'overflow-y': 'auto' }"
|
||||||
|
@ok="fnMergeCellClose()"
|
||||||
|
@cancel="fnMergeCellClose()"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
<DictTag
|
||||||
|
:options="dict.sysBusinessType"
|
||||||
|
:value="state.dataDiff.operaType"
|
||||||
|
/>
|
||||||
|
{{ parseDateToStr(state.dataDiff.createTime) }}
|
||||||
|
</template>
|
||||||
|
<div class="diffBack">
|
||||||
|
<div>
|
||||||
|
<a-button
|
||||||
|
type="text"
|
||||||
|
:loading="state.confirmLoading"
|
||||||
|
@click.prevent="fnMergeCellRestore('old')"
|
||||||
|
>
|
||||||
|
<template #icon><MergeCellsOutlined /></template>
|
||||||
|
{{ t('views.configManage.configParamForm.ptDiffRest') }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a-button
|
||||||
|
type="text"
|
||||||
|
:loading="state.confirmLoading"
|
||||||
|
@click.prevent="fnMergeCellRestore('new')"
|
||||||
|
>
|
||||||
|
<template #icon><MergeCellsOutlined /></template>
|
||||||
|
{{ t('views.configManage.configParamForm.ptDiffRest') }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<CodemirrorEditeDiff
|
||||||
|
:old-area="state.dataDiff.paramJsonOld"
|
||||||
|
:new-area="state.dataDiff.paramJsonNew"
|
||||||
|
></CodemirrorEditeDiff>
|
||||||
|
</a-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.diffBack {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
& > div:first-child {
|
||||||
|
flex: 1;
|
||||||
|
background: #fa9;
|
||||||
|
}
|
||||||
|
& > div:last-child {
|
||||||
|
flex: 1;
|
||||||
|
background: #8f8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,342 @@
|
|||||||
|
import {
|
||||||
|
addPtNeConfigData,
|
||||||
|
delPtNeConfigData,
|
||||||
|
editPtNeConfigData,
|
||||||
|
} from '@/api/pt/neConfig';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import { Modal } from 'ant-design-vue/lib';
|
||||||
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
|
import message from 'ant-design-vue/lib/message';
|
||||||
|
import { reactive, watch } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数配置array类型
|
||||||
|
* @param param 父级传入 { t, treeState, fnActiveConfigNode, ruleVerification, modalState, fnModalCancel}
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function useConfigArray({
|
||||||
|
t,
|
||||||
|
treeState,
|
||||||
|
fnActiveConfigNode,
|
||||||
|
ruleVerification,
|
||||||
|
modalState,
|
||||||
|
fnModalCancel,
|
||||||
|
}: any) {
|
||||||
|
/**多列列表状态类型 */
|
||||||
|
type ArrayStateType = {
|
||||||
|
/**紧凑型 */
|
||||||
|
size: SizeType;
|
||||||
|
/**多列嵌套记录字段 */
|
||||||
|
columns: Record<string, any>[];
|
||||||
|
/**表格字段列排序 */
|
||||||
|
columnsDnd: Record<string, any>[];
|
||||||
|
/**多列记录数据 */
|
||||||
|
columnsData: Record<string, any>[];
|
||||||
|
/**多列嵌套展开key */
|
||||||
|
arrayChildExpandKeys: any[];
|
||||||
|
|
||||||
|
/**多列记录数据 */
|
||||||
|
data: Record<string, any>[];
|
||||||
|
/**多列记录规则 */
|
||||||
|
dataRule: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**多列列表状态 */
|
||||||
|
let arrayState: ArrayStateType = reactive({
|
||||||
|
size: 'small',
|
||||||
|
columns: [],
|
||||||
|
columnsDnd: [],
|
||||||
|
columnsData: [],
|
||||||
|
arrayChildExpandKeys: [],
|
||||||
|
data: [],
|
||||||
|
dataRule: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**多列表编辑 */
|
||||||
|
function arrayEdit(rowIndex: Record<string, any>) {
|
||||||
|
const item = arrayState.data.find((s: any) => s.key === rowIndex.value);
|
||||||
|
if (!item) return;
|
||||||
|
const from = arrayInitEdit(item, arrayState.dataRule);
|
||||||
|
// 处理信息
|
||||||
|
const row: Record<string, any> = {};
|
||||||
|
for (const v of from.record) {
|
||||||
|
if (Array.isArray(v.array)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row[v.name] = Object.assign({}, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
modalState.from = row;
|
||||||
|
modalState.type = 'arrayEdit';
|
||||||
|
modalState.title = `${treeState.selectNode.paramDisplay} ${from.title}`;
|
||||||
|
modalState.key = from.key;
|
||||||
|
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
|
||||||
|
modalState.open = true;
|
||||||
|
|
||||||
|
// 关闭嵌套
|
||||||
|
arrayState.arrayChildExpandKeys = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表编辑关闭 */
|
||||||
|
function arrayEditClose() {
|
||||||
|
arrayState.arrayChildExpandKeys = [];
|
||||||
|
fnModalCancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表编辑确认 */
|
||||||
|
function arrayEditOk(from: Record<string, any>) {
|
||||||
|
// 遍历提取属性和值
|
||||||
|
let data: Record<string, any> = {};
|
||||||
|
for (const key in from) {
|
||||||
|
// 子嵌套的不插入
|
||||||
|
if (from[key]['array']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 检查规则
|
||||||
|
const [ok, msg] = ruleVerification(from[key]);
|
||||||
|
if (!ok) {
|
||||||
|
message.warning({
|
||||||
|
content: `${msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data[key] = from[key]['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
editPtNeConfigData({
|
||||||
|
neType: treeState.neType,
|
||||||
|
paramName: treeState.selectNode.paramName,
|
||||||
|
paramData: data,
|
||||||
|
loc: `${from['index']['value']}`,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.configManage.configParamForm.updateItem', {
|
||||||
|
num: modalState.title,
|
||||||
|
}),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('views.configManage.configParamForm.updateItemErr'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
arrayEditClose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表删除单行 */
|
||||||
|
function arrayDelete(rowIndex: Record<string, any>) {
|
||||||
|
const loc = `${rowIndex.value}`;
|
||||||
|
const title = `${treeState.selectNode.paramDisplay} Index-${loc}`;
|
||||||
|
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.configManage.configParamForm.delItemTip', {
|
||||||
|
num: title,
|
||||||
|
}),
|
||||||
|
onOk() {
|
||||||
|
delPtNeConfigData({
|
||||||
|
neType: treeState.neType,
|
||||||
|
paramName: treeState.selectNode.paramName,
|
||||||
|
loc: loc,
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.configManage.configParamForm.delItemOk', {
|
||||||
|
num: title,
|
||||||
|
}),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
arrayEditClose();
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表新增单行 */
|
||||||
|
function arrayAdd() {
|
||||||
|
const from = arrayInitAdd(arrayState.data, arrayState.dataRule);
|
||||||
|
|
||||||
|
// 处理信息
|
||||||
|
const row: Record<string, any> = {};
|
||||||
|
for (const v of from.record) {
|
||||||
|
if (Array.isArray(v.array)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row[v.name] = Object.assign({}, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
modalState.from = row;
|
||||||
|
modalState.type = 'arrayAdd';
|
||||||
|
modalState.title = `${treeState.selectNode.paramDisplay} ${from.title}`;
|
||||||
|
modalState.key = from.key;
|
||||||
|
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
|
||||||
|
modalState.open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表新增单行确认 */
|
||||||
|
function arrayAddOk(from: Record<string, any>) {
|
||||||
|
// 遍历提取属性和值
|
||||||
|
let data: Record<string, any> = {};
|
||||||
|
for (const key in from) {
|
||||||
|
// 子嵌套的不插入
|
||||||
|
if (from[key]['array']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 检查规则
|
||||||
|
const [ok, msg] = ruleVerification(from[key]);
|
||||||
|
if (!ok) {
|
||||||
|
message.warning({
|
||||||
|
content: `${msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data[key] = from[key]['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
addPtNeConfigData({
|
||||||
|
neType: treeState.neType,
|
||||||
|
paramName: treeState.selectNode.paramName,
|
||||||
|
paramData: data,
|
||||||
|
loc: `${from['index']['value']}`,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.configManage.configParamForm.addItemOk', {
|
||||||
|
num: modalState.title,
|
||||||
|
}),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('views.configManage.configParamForm.addItemErr'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
arrayEditClose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表编辑行数据初始化 */
|
||||||
|
function arrayInitEdit(data: Record<string, any>, dataRule: any) {
|
||||||
|
const dataFrom = data.record;
|
||||||
|
const ruleFrom = Object.assign({}, JSON.parse(JSON.stringify(dataRule)));
|
||||||
|
for (const row of ruleFrom.record) {
|
||||||
|
// 子嵌套的不初始
|
||||||
|
if (row.array) {
|
||||||
|
row.value = [];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 查找项的值
|
||||||
|
const item = dataFrom.find((s: any) => s.name === row.name);
|
||||||
|
if (!item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 可选的
|
||||||
|
row.optional = 'true';
|
||||||
|
// 根据规则类型转值
|
||||||
|
if (['enum', 'int'].includes(row.type)) {
|
||||||
|
row.value = Number(item.value);
|
||||||
|
} else if ('bool' === row.type) {
|
||||||
|
row.value = Boolean(item.value);
|
||||||
|
} else {
|
||||||
|
row.value = item.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ruleFrom.key = data.key;
|
||||||
|
ruleFrom.title = data.title;
|
||||||
|
return ruleFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表新增行数据初始化 */
|
||||||
|
function arrayInitAdd(data: any[], dataRule: any) {
|
||||||
|
// 有数据时取得最后的index
|
||||||
|
let dataLastIndex = 0;
|
||||||
|
if (data.length !== 0) {
|
||||||
|
const lastFrom = Object.assign(
|
||||||
|
{},
|
||||||
|
JSON.parse(JSON.stringify(data.at(-1)))
|
||||||
|
);
|
||||||
|
if (lastFrom.record.length > 0) {
|
||||||
|
dataLastIndex = parseInt(lastFrom.key);
|
||||||
|
dataLastIndex += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ruleFrom = Object.assign({}, JSON.parse(JSON.stringify(dataRule)));
|
||||||
|
for (const row of ruleFrom.record) {
|
||||||
|
// 子嵌套的不初始
|
||||||
|
if (row.array) {
|
||||||
|
row.value = [];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 可选的
|
||||||
|
row.optional = 'true';
|
||||||
|
// index值
|
||||||
|
if (row.name === 'index') {
|
||||||
|
let newIndex =
|
||||||
|
dataLastIndex !== 0 ? dataLastIndex : parseInt(row.value);
|
||||||
|
if (isNaN(newIndex)) {
|
||||||
|
newIndex = 0;
|
||||||
|
}
|
||||||
|
row.value = newIndex;
|
||||||
|
ruleFrom.key = newIndex;
|
||||||
|
ruleFrom.title = `Index-${newIndex}`;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 根据规则类型转值
|
||||||
|
if (['enum', 'int'].includes(row.type)) {
|
||||||
|
row.value = Number(row.value);
|
||||||
|
}
|
||||||
|
if ('bool' === row.type) {
|
||||||
|
row.value = Boolean(row.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ruleFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听表格字段列排序变化关闭展开
|
||||||
|
watch(
|
||||||
|
() => arrayState.columnsDnd,
|
||||||
|
() => {
|
||||||
|
arrayEditClose();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
arrayState,
|
||||||
|
arrayEdit,
|
||||||
|
arrayEditClose,
|
||||||
|
arrayEditOk,
|
||||||
|
arrayDelete,
|
||||||
|
arrayAdd,
|
||||||
|
arrayAddOk,
|
||||||
|
arrayInitEdit,
|
||||||
|
arrayInitAdd,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,349 @@
|
|||||||
|
import {
|
||||||
|
addPtNeConfigData,
|
||||||
|
delPtNeConfigData,
|
||||||
|
editPtNeConfigData,
|
||||||
|
} from '@/api/pt/neConfig';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import { Modal } from 'ant-design-vue/lib';
|
||||||
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
|
import message from 'ant-design-vue/lib/message';
|
||||||
|
import { nextTick, reactive } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数配置array类型的嵌套array
|
||||||
|
* @param param 父级传入 { t, treeState, fnActiveConfigNode, ruleVerification, modalState, arrayState, arrayInitEdit, arrayInitAdd, arrayEditClose}
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function useConfigArrayChild({
|
||||||
|
t,
|
||||||
|
treeState,
|
||||||
|
fnActiveConfigNode,
|
||||||
|
ruleVerification,
|
||||||
|
modalState,
|
||||||
|
arrayState,
|
||||||
|
arrayInitEdit,
|
||||||
|
arrayInitAdd,
|
||||||
|
arrayEditClose,
|
||||||
|
}: any) {
|
||||||
|
/**多列嵌套列表状态类型 */
|
||||||
|
type ArrayChildStateType = {
|
||||||
|
/**标题 */
|
||||||
|
title: string;
|
||||||
|
/**层级index */
|
||||||
|
loc: string;
|
||||||
|
/**紧凑型 */
|
||||||
|
size: SizeType;
|
||||||
|
/**多列嵌套记录字段 */
|
||||||
|
columns: Record<string, any>[];
|
||||||
|
/**表格字段列排序 */
|
||||||
|
columnsDnd: Record<string, any>[];
|
||||||
|
/**多列记录数据 */
|
||||||
|
columnsData: Record<string, any>[];
|
||||||
|
|
||||||
|
/**多列嵌套记录数据 */
|
||||||
|
data: Record<string, any>[];
|
||||||
|
/**多列嵌套记录规则 */
|
||||||
|
dataRule: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**多列嵌套表格状态 */
|
||||||
|
let arrayChildState: ArrayChildStateType = reactive({
|
||||||
|
title: '',
|
||||||
|
loc: '',
|
||||||
|
size: 'small',
|
||||||
|
columns: [],
|
||||||
|
columnsDnd: [],
|
||||||
|
columnsData: [],
|
||||||
|
data: [],
|
||||||
|
dataRule: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**多列表展开嵌套行 */
|
||||||
|
function arrayChildExpand(
|
||||||
|
indexRow: Record<string, any>,
|
||||||
|
row: Record<string, any>
|
||||||
|
) {
|
||||||
|
const loc = indexRow.value;
|
||||||
|
if (arrayChildState.loc === `${loc}/${row.name}`) {
|
||||||
|
arrayChildState.loc = '';
|
||||||
|
arrayState.arrayChildExpandKeys = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
arrayChildState.loc = '';
|
||||||
|
arrayState.arrayChildExpandKeys = [];
|
||||||
|
const from = Object.assign({}, JSON.parse(JSON.stringify(row)));
|
||||||
|
// 无数据时
|
||||||
|
if (!Array.isArray(from.value)) {
|
||||||
|
from.value = [];
|
||||||
|
}
|
||||||
|
const dataArr = Object.freeze(from.value);
|
||||||
|
const ruleArr = Object.freeze(from.array);
|
||||||
|
|
||||||
|
// 列表项数据
|
||||||
|
const dataArray: Record<string, any>[] = [];
|
||||||
|
for (const item of dataArr) {
|
||||||
|
const index = item['index'];
|
||||||
|
let record: Record<string, any>[] = [];
|
||||||
|
for (const key of Object.keys(item)) {
|
||||||
|
// 规则为准
|
||||||
|
for (const rule of ruleArr) {
|
||||||
|
if (rule['name'] === key) {
|
||||||
|
const ruleItem = Object.assign({ optional: 'true' }, rule, {
|
||||||
|
value: item[key],
|
||||||
|
});
|
||||||
|
record.push(ruleItem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// dataArray.push(record);
|
||||||
|
dataArray.push({ title: `Index-${index}`, key: index, record });
|
||||||
|
}
|
||||||
|
arrayChildState.data = dataArray;
|
||||||
|
|
||||||
|
// 无数据时,用于新增
|
||||||
|
arrayChildState.dataRule = {
|
||||||
|
title: `Index-0`,
|
||||||
|
key: 0,
|
||||||
|
record: ruleArr,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 列表数据
|
||||||
|
const columnsData: Record<string, any>[] = [];
|
||||||
|
for (const v of arrayChildState.data) {
|
||||||
|
const row: Record<string, any> = {};
|
||||||
|
for (const item of v.record) {
|
||||||
|
row[item.name] = item;
|
||||||
|
}
|
||||||
|
columnsData.push(row);
|
||||||
|
}
|
||||||
|
arrayChildState.columnsData = columnsData;
|
||||||
|
|
||||||
|
// 列表字段
|
||||||
|
const columns: Record<string, any>[] = [];
|
||||||
|
for (const rule of arrayChildState.dataRule.record) {
|
||||||
|
columns.push({
|
||||||
|
title: rule.display,
|
||||||
|
dataIndex: rule.name,
|
||||||
|
align: 'left',
|
||||||
|
resizable: true,
|
||||||
|
width: 50,
|
||||||
|
minWidth: 50,
|
||||||
|
maxWidth: 250,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
columns.push({
|
||||||
|
title: t('common.operate'),
|
||||||
|
dataIndex: 'index',
|
||||||
|
key: 'index',
|
||||||
|
align: 'center',
|
||||||
|
fixed: 'right',
|
||||||
|
width: 100,
|
||||||
|
});
|
||||||
|
arrayChildState.columns = columns;
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
// 设置展开key
|
||||||
|
arrayState.arrayChildExpandKeys = [indexRow];
|
||||||
|
// 层级标识
|
||||||
|
arrayChildState.loc = `${loc}/${from['name']}`;
|
||||||
|
// 设置展开列表标题
|
||||||
|
arrayChildState.title = `${from['display']}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表嵌套行编辑 */
|
||||||
|
function arrayChildEdit(rowIndex: Record<string, any>) {
|
||||||
|
const item = arrayChildState.data.find(
|
||||||
|
(s: any) => s.key === rowIndex.value
|
||||||
|
);
|
||||||
|
if (!item) return;
|
||||||
|
const from = arrayInitEdit(item, arrayChildState.dataRule);
|
||||||
|
// 处理信息
|
||||||
|
const row: Record<string, any> = {};
|
||||||
|
for (const v of from.record) {
|
||||||
|
if (Array.isArray(v.array)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row[v.name] = Object.assign({}, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
modalState.from = row;
|
||||||
|
modalState.type = 'arrayChildEdit';
|
||||||
|
modalState.title = `${arrayChildState.title} ${from.title}`;
|
||||||
|
modalState.key = from.key;
|
||||||
|
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
|
||||||
|
modalState.open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表嵌套行编辑确认 */
|
||||||
|
function arrayChildEditOk(from: Record<string, any>) {
|
||||||
|
const loc = `${arrayChildState.loc}/${from['index']['value']}`;
|
||||||
|
|
||||||
|
let data: Record<string, any> = {};
|
||||||
|
for (const key in from) {
|
||||||
|
// 子嵌套的不插入
|
||||||
|
if (from[key]['array']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 检查规则
|
||||||
|
const [ok, msg] = ruleVerification(from[key]);
|
||||||
|
if (!ok) {
|
||||||
|
message.warning({
|
||||||
|
content: `${msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data[key] = from[key]['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
editPtNeConfigData({
|
||||||
|
neType: treeState.neType,
|
||||||
|
paramName: treeState.selectNode.paramName,
|
||||||
|
paramData: data,
|
||||||
|
loc,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.configManage.configParamForm.updateItem', {
|
||||||
|
num: modalState.title,
|
||||||
|
}),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('views.configManage.configParamForm.updateItemErr'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
arrayEditClose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表嵌套行删除单行 */
|
||||||
|
function arrayChildDelete(rowIndex: Record<string, any>) {
|
||||||
|
const index = rowIndex.value;
|
||||||
|
const loc = `${arrayChildState.loc}/${index}`;
|
||||||
|
const title = `${arrayChildState.title} Index-${index}`;
|
||||||
|
|
||||||
|
Modal.confirm({
|
||||||
|
title: t('common.tipTitle'),
|
||||||
|
content: t('views.configManage.configParamForm.delItemTip', {
|
||||||
|
num: title,
|
||||||
|
}),
|
||||||
|
onOk() {
|
||||||
|
delPtNeConfigData({
|
||||||
|
neType: treeState.neType,
|
||||||
|
paramName: treeState.selectNode.paramName,
|
||||||
|
loc,
|
||||||
|
}).then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.configManage.configParamForm.delItemOk', {
|
||||||
|
num: title,
|
||||||
|
}),
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
arrayEditClose();
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
duration: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表嵌套行新增单行 */
|
||||||
|
function arrayChildAdd() {
|
||||||
|
const from = arrayInitAdd(arrayChildState.data, arrayChildState.dataRule);
|
||||||
|
// 处理信息
|
||||||
|
const row: Record<string, any> = {};
|
||||||
|
for (const v of from.record) {
|
||||||
|
if (Array.isArray(v.array)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
row[v.name] = Object.assign({}, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
modalState.from = row;
|
||||||
|
modalState.type = 'arrayChildAdd';
|
||||||
|
modalState.title = `${arrayChildState.title} ${from.title}`;
|
||||||
|
modalState.key = from.key;
|
||||||
|
modalState.data = from.record.filter((v: any) => !Array.isArray(v.array));
|
||||||
|
modalState.open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**多列表新增单行确认 */
|
||||||
|
function arrayChildAddOk(from: Record<string, any>) {
|
||||||
|
const loc = `${arrayChildState.loc}/${from['index']['value']}`;
|
||||||
|
|
||||||
|
let data: Record<string, any> = {};
|
||||||
|
for (const key in from) {
|
||||||
|
// 子嵌套的不插入
|
||||||
|
if (from[key]['array']) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 检查规则
|
||||||
|
const [ok, msg] = ruleVerification(from[key]);
|
||||||
|
if (!ok) {
|
||||||
|
message.warning({
|
||||||
|
content: `${msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
data[key] = from[key]['value'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
addPtNeConfigData({
|
||||||
|
neType: treeState.neType,
|
||||||
|
paramName: treeState.selectNode.paramName,
|
||||||
|
paramData: data,
|
||||||
|
loc,
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.configManage.configParamForm.addItemOk', {
|
||||||
|
num: modalState.title,
|
||||||
|
}),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('views.configManage.configParamForm.addItemErr'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
arrayEditClose();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
arrayChildState,
|
||||||
|
arrayChildExpand,
|
||||||
|
arrayChildEdit,
|
||||||
|
arrayChildEditOk,
|
||||||
|
arrayChildDelete,
|
||||||
|
arrayChildAdd,
|
||||||
|
arrayChildAddOk,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
import { editPtNeConfigData } from '@/api/pt/neConfig';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import { SizeType } from 'ant-design-vue/es/config-provider';
|
||||||
|
import message from 'ant-design-vue/es/message';
|
||||||
|
import { reactive, toRaw } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list类型参数处理
|
||||||
|
* @param param 父级传入 {t, treeState, ruleVerification}
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function useConfigList({ t, treeState, ruleVerification }: any) {
|
||||||
|
/**单列表状态类型 */
|
||||||
|
type ListStateType = {
|
||||||
|
/**紧凑型 */
|
||||||
|
size: SizeType;
|
||||||
|
/**单列记录字段 */
|
||||||
|
columns: Record<string, any>[];
|
||||||
|
/**单列记录数据 */
|
||||||
|
data: Record<string, any>[];
|
||||||
|
/**编辑行记录 */
|
||||||
|
editRecord: Record<string, any>;
|
||||||
|
/**确认提交等待 */
|
||||||
|
confirmLoading: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**单列表状态 */
|
||||||
|
let listState: ListStateType = reactive({
|
||||||
|
size: 'small',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: 'Key',
|
||||||
|
dataIndex: 'display',
|
||||||
|
align: 'left',
|
||||||
|
width: '30%',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Value',
|
||||||
|
dataIndex: 'value',
|
||||||
|
align: 'left',
|
||||||
|
width: '70%',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
data: [],
|
||||||
|
confirmLoading: false,
|
||||||
|
editRecord: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**单列表编辑 */
|
||||||
|
function listEdit(row: Record<string, any>) {
|
||||||
|
listState.editRecord = Object.assign({}, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**单列表编辑关闭 */
|
||||||
|
function listEditClose() {
|
||||||
|
listState.confirmLoading = false;
|
||||||
|
listState.editRecord = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**单列表编辑确认 */
|
||||||
|
function listEditOk() {
|
||||||
|
if (listState.confirmLoading) return;
|
||||||
|
const from = toRaw(listState.editRecord);
|
||||||
|
// 检查规则
|
||||||
|
const [ok, msg] = ruleVerification(from);
|
||||||
|
if (!ok) {
|
||||||
|
message.warning({
|
||||||
|
content: `${msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送
|
||||||
|
listState.confirmLoading = true;
|
||||||
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
|
editPtNeConfigData({
|
||||||
|
neType: treeState.neType,
|
||||||
|
paramName: treeState.selectNode.paramName,
|
||||||
|
paramData: {
|
||||||
|
[from['name']]: from['value'],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('views.configManage.configParamForm.updateValue', {
|
||||||
|
num: from['display'],
|
||||||
|
}),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
// 改变表格数据
|
||||||
|
const item = listState.data.find(
|
||||||
|
(item: Record<string, any>) => from['name'] === item['name']
|
||||||
|
);
|
||||||
|
if (item) {
|
||||||
|
Object.assign(item, listState.editRecord);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.warning({
|
||||||
|
content: t('views.configManage.configParamForm.updateValueErr'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
hide();
|
||||||
|
listState.confirmLoading = false;
|
||||||
|
listState.editRecord = {};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**表格分页器参数 */
|
||||||
|
let tablePagination = reactive({
|
||||||
|
/**当前页数 */
|
||||||
|
current: 1,
|
||||||
|
/**每页条数 */
|
||||||
|
pageSize: 10,
|
||||||
|
/**默认的每页条数 */
|
||||||
|
defaultPageSize: 10,
|
||||||
|
/**指定每页可以显示多少条 */
|
||||||
|
pageSizeOptions: ['10', '20', '50', '100'],
|
||||||
|
/**只有一页时是否隐藏分页器 */
|
||||||
|
hideOnSinglePage: true,
|
||||||
|
/**是否可以快速跳转至某页 */
|
||||||
|
showQuickJumper: true,
|
||||||
|
/**是否可以改变 pageSize */
|
||||||
|
showSizeChanger: true,
|
||||||
|
/**数据总数 */
|
||||||
|
total: 0,
|
||||||
|
showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
|
||||||
|
onChange: (page: number, pageSize: number) => {
|
||||||
|
tablePagination.current = page;
|
||||||
|
tablePagination.pageSize = pageSize;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return { tablePagination, listState, listEdit, listEditClose, listEditOk };
|
||||||
|
}
|
||||||
192
src/views/configManage/configParamTreeTable/hooks/useOptions.ts
Normal file
192
src/views/configManage/configParamTreeTable/hooks/useOptions.ts
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
import { getNeConfigData } from '@/api/ne/neConfig';
|
||||||
|
import { regExpIPv4, regExpIPv6, validURL } from '@/utils/regular-utils';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数公共函数
|
||||||
|
* @param param 父级传入 {t}
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function useOptions({ t }: any) {
|
||||||
|
/**规则校验 */
|
||||||
|
function ruleVerification(row: Record<string, any>): (string | boolean)[] {
|
||||||
|
let result = [true, ''];
|
||||||
|
const type = row.type;
|
||||||
|
const value = row.value;
|
||||||
|
const filter = row.filter;
|
||||||
|
const display = row.display;
|
||||||
|
|
||||||
|
// 子嵌套的不检查
|
||||||
|
if (row.array) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 可选的同时没有值不检查
|
||||||
|
if (row.optional === 'true' && !value) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
switch (type) {
|
||||||
|
case 'int':
|
||||||
|
// filter: "0~128"
|
||||||
|
|
||||||
|
if (filter && filter.indexOf('~') !== -1) {
|
||||||
|
const filterArr = filter.split('~');
|
||||||
|
const minInt = parseInt(filterArr[0]);
|
||||||
|
const maxInt = parseInt(filterArr[1]);
|
||||||
|
const valueInt = parseInt(value);
|
||||||
|
if (valueInt < minInt || valueInt > maxInt) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.configManage.configParamForm.requireInt', {
|
||||||
|
display,
|
||||||
|
filter,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'ipv4':
|
||||||
|
if (!regExpIPv4.test(value)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.configManage.configParamForm.requireIpv4', { display }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'ipv6':
|
||||||
|
if (!regExpIPv6.test(value)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.configManage.configParamForm.requireIpv6', { display }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'enum':
|
||||||
|
if (filter && filter.indexOf('{') === 1) {
|
||||||
|
let filterJson: Record<string, any> = {};
|
||||||
|
try {
|
||||||
|
filterJson = JSON.parse(filter); //string---json
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Object.keys(filterJson).includes(`${value}`)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.configManage.configParamForm.requireEnum', { display }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'bool':
|
||||||
|
// filter: '{"0":"false", "1":"true"}'
|
||||||
|
|
||||||
|
if (filter && filter.indexOf('{') === 1) {
|
||||||
|
let filterJson: Record<string, any> = {};
|
||||||
|
try {
|
||||||
|
filterJson = JSON.parse(filter); //string---json
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Object.values(filterJson).includes(`${value}`)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.configManage.configParamForm.requireBool', { display }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'string':
|
||||||
|
// filter: "0~128"
|
||||||
|
|
||||||
|
// 字符串长度判断
|
||||||
|
if (filter && filter.indexOf('~') !== -1) {
|
||||||
|
try {
|
||||||
|
const filterArr = filter.split('~');
|
||||||
|
let rule = new RegExp(
|
||||||
|
'^\\S{' + filterArr[0] + ',' + filterArr[1] + '}$'
|
||||||
|
);
|
||||||
|
if (!rule.test(value)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.configManage.configParamForm.requireString', {
|
||||||
|
display,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 字符串http判断
|
||||||
|
if (value.startsWith('http')) {
|
||||||
|
try {
|
||||||
|
if (!validURL(value)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.configManage.configParamForm.requireString', {
|
||||||
|
display,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'regex':
|
||||||
|
// filter: "^[0-9]{3}$"
|
||||||
|
|
||||||
|
if (filter) {
|
||||||
|
try {
|
||||||
|
let regex = new RegExp(filter);
|
||||||
|
if (!regex.test(value)) {
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.configManage.configParamForm.requireString', {
|
||||||
|
display,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return [
|
||||||
|
false,
|
||||||
|
t('views.configManage.configParamForm.requireUn', { display }),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**upfId可选择 */
|
||||||
|
const SMFByUPFIdOptions = ref<{ value: string; label: string }[]>([]);
|
||||||
|
/**加载smf配置的upfId */
|
||||||
|
function getConfigSMFByUPFIds(neId: string) {
|
||||||
|
getNeConfigData({
|
||||||
|
neType: 'SMF',
|
||||||
|
neId: neId,
|
||||||
|
paramName: 'upfConfig',
|
||||||
|
}).then(res => {
|
||||||
|
SMFByUPFIdOptions.value = [];
|
||||||
|
for (const s of res.data) {
|
||||||
|
SMFByUPFIdOptions.value.push({
|
||||||
|
value: s.id,
|
||||||
|
label: s.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
ruleVerification,
|
||||||
|
getConfigSMFByUPFIds,
|
||||||
|
SMFByUPFIdOptions,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
import { ptSaveAsDefault, ptResetAsDefault } from '@/api/pt/neConfig';
|
||||||
|
import {
|
||||||
|
getPtClassStudents,
|
||||||
|
stuPtNeConfigApply,
|
||||||
|
updatePtNeConfigApply,
|
||||||
|
} from '@/api/pt/neConfigApply';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import { hasRoles } from '@/plugins/auth-user';
|
||||||
|
import { message } from 'ant-design-vue/lib';
|
||||||
|
import { computed, onMounted, reactive } from 'vue';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实训教学函数
|
||||||
|
* @param param 父级传入 {t,fnActiveConfigNode}
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function usePtOptions({ t, fnActiveConfigNode }: any) {
|
||||||
|
const ptConfigState = reactive({
|
||||||
|
saveLoading: false,
|
||||||
|
restLoading: false,
|
||||||
|
applyLoading: false,
|
||||||
|
});
|
||||||
|
/**(管理员)保存网元下所有配置为示例配置 */
|
||||||
|
function ptConfigSave(neType: string) {
|
||||||
|
ptConfigState.saveLoading = true;
|
||||||
|
ptSaveAsDefault(neType, '001')
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('common.operateOk'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
ptConfigState.saveLoading = false;
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**重置网元下所有配置 */
|
||||||
|
function ptConfigReset(neType: string) {
|
||||||
|
ptConfigState.restLoading = true;
|
||||||
|
ptResetAsDefault(neType)
|
||||||
|
.then(res => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('common.operateOk'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
ptConfigState.restLoading = false;
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**配置下方应用(学生)申请撤回和(管理/教师)应用退回 */
|
||||||
|
function ptConfigApply(
|
||||||
|
neType: string,
|
||||||
|
status: '0' | '1' | '2' | '3',
|
||||||
|
student?: string
|
||||||
|
) {
|
||||||
|
let result: any;
|
||||||
|
if (status === '2' || status === '3') {
|
||||||
|
let from: {
|
||||||
|
neType: string;
|
||||||
|
status: string;
|
||||||
|
student?: string;
|
||||||
|
backInfo?: string;
|
||||||
|
} = {
|
||||||
|
neType,
|
||||||
|
status: '2',
|
||||||
|
};
|
||||||
|
if (student) {
|
||||||
|
if (status === '2') {
|
||||||
|
from = { neType, status, student };
|
||||||
|
}
|
||||||
|
if (status === '3') {
|
||||||
|
from = { neType, status, student, backInfo: '请重新检查配置' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = updatePtNeConfigApply(from);
|
||||||
|
}
|
||||||
|
if (status === '0' || status === '1') {
|
||||||
|
result = stuPtNeConfigApply({ neType, status });
|
||||||
|
}
|
||||||
|
if (!result) return;
|
||||||
|
ptConfigState.applyLoading = true;
|
||||||
|
result
|
||||||
|
.then((res: any) => {
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS) {
|
||||||
|
message.success({
|
||||||
|
content: t('common.operateOk'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
// 教师修改学生时改变状态
|
||||||
|
if (student) {
|
||||||
|
const item = classState.studentOptionsDef.find(
|
||||||
|
s => s.value === classState.student
|
||||||
|
);
|
||||||
|
if (item) {
|
||||||
|
item.applyStatus = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error({
|
||||||
|
content: `${res.msg}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
ptConfigState.applyLoading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const classState = reactive<{
|
||||||
|
/**学生账号 */
|
||||||
|
student: string | undefined;
|
||||||
|
/**学生可选择列表 */
|
||||||
|
studentOptions: {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
applyId: string;
|
||||||
|
applyStatus: string;
|
||||||
|
}[];
|
||||||
|
studentOptionsDef: {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
applyId: string;
|
||||||
|
applyStatus: string;
|
||||||
|
}[];
|
||||||
|
}>({
|
||||||
|
student: undefined,
|
||||||
|
studentOptions: [],
|
||||||
|
studentOptionsDef: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// 仅教师加载
|
||||||
|
if (hasRoles(['teacher'])) {
|
||||||
|
onMounted(() => {
|
||||||
|
classStudents(); // 初始学生列表
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**学生选择搜索 */
|
||||||
|
function studentChange(v: any) {
|
||||||
|
if (!v) {
|
||||||
|
Object.assign(classState.studentOptions, classState.studentOptionsDef);
|
||||||
|
}
|
||||||
|
fnActiveConfigNode('#');
|
||||||
|
}
|
||||||
|
|
||||||
|
let timeout: any;
|
||||||
|
|
||||||
|
/**学生选择搜索 */
|
||||||
|
function studentSearch(val: string) {
|
||||||
|
if (timeout) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = null;
|
||||||
|
}
|
||||||
|
if (!val) {
|
||||||
|
Object.assign(classState.studentOptions, classState.studentOptionsDef);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
timeout = setTimeout(() => classStudents(val), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**班级学生列表 */
|
||||||
|
function classStudents(val?: string) {
|
||||||
|
getPtClassStudents({ userName: val }).then(res => {
|
||||||
|
classState.studentOptions = [];
|
||||||
|
if (!Array.isArray(res.data) || res.data.length <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const v of res.data) {
|
||||||
|
classState.studentOptions.push({
|
||||||
|
value: v.userName,
|
||||||
|
label: v.userName,
|
||||||
|
applyId: v.applyId,
|
||||||
|
applyStatus: v.applyStatus,
|
||||||
|
});
|
||||||
|
// 设为最新状态
|
||||||
|
const item = classState.studentOptionsDef.find(
|
||||||
|
s => s.value === v.userName
|
||||||
|
);
|
||||||
|
if (item) {
|
||||||
|
item.applyStatus = v.applyStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!val) {
|
||||||
|
Object.assign(classState.studentOptionsDef, classState.studentOptions);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 学生状态
|
||||||
|
const studentStatus = computed(() => {
|
||||||
|
const item = classState.studentOptionsDef.find(
|
||||||
|
s => s.value === classState.student
|
||||||
|
);
|
||||||
|
if (item) return item.applyStatus;
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
ptConfigState,
|
||||||
|
ptConfigSave,
|
||||||
|
ptConfigReset,
|
||||||
|
ptConfigApply,
|
||||||
|
classState,
|
||||||
|
studentStatus,
|
||||||
|
studentSearch,
|
||||||
|
studentChange,
|
||||||
|
};
|
||||||
|
}
|
||||||
1249
src/views/configManage/configParamTreeTable/index.vue
Normal file
1249
src/views/configManage/configParamTreeTable/index.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,7 @@ import { listAMFDataUE, delAMFDataUE, exportAMFDataUE } from '@/api/neData/amf';
|
|||||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
import saveAs from 'file-saver';
|
import saveAs from 'file-saver';
|
||||||
import PQueue from 'p-queue';
|
import PQueue from 'p-queue';
|
||||||
|
import { hasRoles } from '@/plugins/auth-user';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { getDict } = useDictStore();
|
const { getDict } = useDictStore();
|
||||||
const ws = new WS();
|
const ws = new WS();
|
||||||
@@ -522,6 +523,7 @@ onBeforeUnmount(() => {
|
|||||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||||
:loading="modalState.confirmLoading"
|
:loading="modalState.confirmLoading"
|
||||||
@click.prevent="fnRecordDelete('0')"
|
@click.prevent="fnRecordDelete('0')"
|
||||||
|
v-if="!hasRoles(['student'])"
|
||||||
>
|
>
|
||||||
<template #icon><DeleteOutlined /></template>
|
<template #icon><DeleteOutlined /></template>
|
||||||
{{ t('common.deleteText') }}
|
{{ t('common.deleteText') }}
|
||||||
@@ -583,7 +585,7 @@ onBeforeUnmount(() => {
|
|||||||
<a-table
|
<a-table
|
||||||
class="table"
|
class="table"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:columns="tableColumns"
|
:columns="hasRoles(['student']) ? tableColumns.filter((s:any)=>s.key !== 'id'): tableColumns"
|
||||||
:loading="tableState.loading"
|
:loading="tableState.loading"
|
||||||
:data-source="tableState.data"
|
:data-source="tableState.data"
|
||||||
:size="tableState.size"
|
:size="tableState.size"
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import { parseDateToStr, parseDuration } from '@/utils/date-utils';
|
|||||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
import saveAs from 'file-saver';
|
import saveAs from 'file-saver';
|
||||||
import PQueue from 'p-queue';
|
import PQueue from 'p-queue';
|
||||||
|
import { hasRoles } from '@/plugins/auth-user';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { getDict } = useDictStore();
|
const { getDict } = useDictStore();
|
||||||
const ws = new WS();
|
const ws = new WS();
|
||||||
@@ -628,6 +629,7 @@ onBeforeUnmount(() => {
|
|||||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||||
:loading="modalState.confirmLoading"
|
:loading="modalState.confirmLoading"
|
||||||
@click.prevent="fnRecordDelete('0')"
|
@click.prevent="fnRecordDelete('0')"
|
||||||
|
v-if="!hasRoles(['student'])"
|
||||||
>
|
>
|
||||||
<template #icon><DeleteOutlined /></template>
|
<template #icon><DeleteOutlined /></template>
|
||||||
{{ t('common.deleteText') }}
|
{{ t('common.deleteText') }}
|
||||||
@@ -690,7 +692,7 @@ onBeforeUnmount(() => {
|
|||||||
<a-table
|
<a-table
|
||||||
class="table"
|
class="table"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:columns="tableColumns"
|
:columns="hasRoles(['student']) ? tableColumns.filter((s:any)=>s.key !== 'id'): tableColumns"
|
||||||
:loading="tableState.loading"
|
:loading="tableState.loading"
|
||||||
:data-source="tableState.data"
|
:data-source="tableState.data"
|
||||||
:size="tableState.size"
|
:size="tableState.size"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { parseDateToStr } from '@/utils/date-utils';
|
|||||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
import saveAs from 'file-saver';
|
import saveAs from 'file-saver';
|
||||||
import PQueue from 'p-queue';
|
import PQueue from 'p-queue';
|
||||||
|
import { hasRoles } from '@/plugins/auth-user';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { getDict } = useDictStore();
|
const { getDict } = useDictStore();
|
||||||
const ws = new WS();
|
const ws = new WS();
|
||||||
@@ -572,6 +573,7 @@ onBeforeUnmount(() => {
|
|||||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||||
:loading="modalState.confirmLoading"
|
:loading="modalState.confirmLoading"
|
||||||
@click.prevent="fnRecordDelete('0')"
|
@click.prevent="fnRecordDelete('0')"
|
||||||
|
v-if="!hasRoles(['student'])"
|
||||||
>
|
>
|
||||||
<template #icon><DeleteOutlined /></template>
|
<template #icon><DeleteOutlined /></template>
|
||||||
{{ t('common.deleteText') }}
|
{{ t('common.deleteText') }}
|
||||||
@@ -634,7 +636,7 @@ onBeforeUnmount(() => {
|
|||||||
<a-table
|
<a-table
|
||||||
class="table"
|
class="table"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:columns="tableColumns"
|
:columns="hasRoles(['student']) ? tableColumns.filter((s:any)=>s.key !== 'id'): tableColumns"
|
||||||
:loading="tableState.loading"
|
:loading="tableState.loading"
|
||||||
:data-source="tableState.data"
|
:data-source="tableState.data"
|
||||||
:size="tableState.size"
|
:size="tableState.size"
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
import PQueue from 'p-queue';
|
import PQueue from 'p-queue';
|
||||||
import saveAs from 'file-saver';
|
import saveAs from 'file-saver';
|
||||||
|
import { hasRoles } from '@/plugins/auth-user';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const ws = new WS();
|
const ws = new WS();
|
||||||
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
||||||
@@ -591,6 +592,7 @@ onBeforeUnmount(() => {
|
|||||||
:disabled="tableState.selectedRowKeys.length <= 0"
|
:disabled="tableState.selectedRowKeys.length <= 0"
|
||||||
:loading="modalState.confirmLoading"
|
:loading="modalState.confirmLoading"
|
||||||
@click.prevent="fnRecordDelete('0')"
|
@click.prevent="fnRecordDelete('0')"
|
||||||
|
v-if="!hasRoles(['student'])"
|
||||||
>
|
>
|
||||||
<template #icon><DeleteOutlined /></template>
|
<template #icon><DeleteOutlined /></template>
|
||||||
{{ t('common.deleteText') }}
|
{{ t('common.deleteText') }}
|
||||||
@@ -653,7 +655,7 @@ onBeforeUnmount(() => {
|
|||||||
<a-table
|
<a-table
|
||||||
class="table"
|
class="table"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
:columns="tableColumns"
|
:columns="hasRoles(['student']) ? tableColumns.filter((s:any)=>s.key !== 'id'): tableColumns"
|
||||||
:loading="tableState.loading"
|
:loading="tableState.loading"
|
||||||
:data-source="tableState.data"
|
:data-source="tableState.data"
|
||||||
:size="tableState.size"
|
:size="tableState.size"
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import {
|
|||||||
import useNeOptions from '@/views/ne/neInfo/hooks/useNeOptions';
|
import useNeOptions from '@/views/ne/neInfo/hooks/useNeOptions';
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
|
import { hasRoles } from '@/plugins/auth-user';
|
||||||
import { parseBasePath } from '@/plugins/file-static-url';
|
import { parseBasePath } from '@/plugins/file-static-url';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { fnNeRestart, fnNeStop, fnNeLogFile } = useNeOptions();
|
const { fnNeRestart, fnNeStop, fnNeLogFile } = useNeOptions();
|
||||||
@@ -134,6 +135,16 @@ const graphNodeTooltip = new Tooltip({
|
|||||||
if (!neState) {
|
if (!neState) {
|
||||||
return `<div><span>${label || id}</span></div>`;
|
return `<div><span>${label || id}</span></div>`;
|
||||||
}
|
}
|
||||||
|
let notStudentInfo = '';
|
||||||
|
if (hasRoles(['teacher', 'admin'])) {
|
||||||
|
notStudentInfo = `
|
||||||
|
<div><strong>${t('views.monitor.topology.serialNum')}:</strong><span>
|
||||||
|
${neState.sn ?? '--'}
|
||||||
|
</span></div>
|
||||||
|
<div><strong>${t('views.monitor.topology.expiryDate')}:</strong><span>
|
||||||
|
${neState.expire ?? '--'}
|
||||||
|
</span></div> `;
|
||||||
|
}
|
||||||
return `
|
return `
|
||||||
<div
|
<div
|
||||||
style="
|
style="
|
||||||
@@ -161,12 +172,7 @@ const graphNodeTooltip = new Tooltip({
|
|||||||
<div><strong>${t('views.monitor.topology.version')}:</strong><span>
|
<div><strong>${t('views.monitor.topology.version')}:</strong><span>
|
||||||
${neState.version ?? '--'}
|
${neState.version ?? '--'}
|
||||||
</span></div>
|
</span></div>
|
||||||
<div><strong>${t('views.monitor.topology.serialNum')}:</strong><span>
|
${notStudentInfo}
|
||||||
${neState.sn ?? '--'}
|
|
||||||
</span></div>
|
|
||||||
<div><strong>${t('views.monitor.topology.expiryDate')}:</strong><span>
|
|
||||||
${neState.expire ?? '--'}
|
|
||||||
</span></div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
|||||||
import useNeInfoStore from '@/store/modules/neinfo';
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
import { listNeInfo, delNeInfo, stateNeInfo } from '@/api/ne/neInfo';
|
import { listNeInfo, delNeInfo, stateNeInfo } from '@/api/ne/neInfo';
|
||||||
import { NE_TYPE_LIST } from '@/constants/ne-constants';
|
import { NE_TYPE_LIST } from '@/constants/ne-constants';
|
||||||
|
import { hasRoles } from '@/plugins/auth-user';
|
||||||
import useDictStore from '@/store/modules/dict';
|
import useDictStore from '@/store/modules/dict';
|
||||||
import useNeOptions from './hooks/useNeOptions';
|
import useNeOptions from './hooks/useNeOptions';
|
||||||
const { getDict } = useDictStore();
|
const { getDict } = useDictStore();
|
||||||
@@ -492,7 +493,7 @@ onMounted(() => {
|
|||||||
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
<a-card :bordered="false" :body-style="{ padding: '0px' }">
|
||||||
<!-- 插槽-卡片左侧侧 -->
|
<!-- 插槽-卡片左侧侧 -->
|
||||||
<template #title>
|
<template #title>
|
||||||
<a-space :size="8" align="center">
|
<a-space :size="8" align="center" v-roles:has="['admin']">
|
||||||
<a-button type="primary" @click.prevent="fnModalVisibleByEdit()">
|
<a-button type="primary" @click.prevent="fnModalVisibleByEdit()">
|
||||||
<template #icon><PlusOutlined /></template>
|
<template #icon><PlusOutlined /></template>
|
||||||
{{ t('common.addText') }}
|
{{ t('common.addText') }}
|
||||||
@@ -578,26 +579,31 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
<template v-if="column.key === 'id'">
|
<template v-if="column.key === 'id'">
|
||||||
<a-space :size="8" align="center">
|
<a-space :size="8" align="center">
|
||||||
<a-tooltip>
|
<span v-roles:has="['admin']">
|
||||||
<template #title>{{ t('common.editText') }}</template>
|
<a-tooltip>
|
||||||
<a-button
|
<template #title>{{ t('common.editText') }}</template>
|
||||||
type="link"
|
<a-button
|
||||||
@click.prevent="fnModalVisibleByEdit(record)"
|
type="link"
|
||||||
>
|
@click.prevent="fnModalVisibleByEdit(record)"
|
||||||
<template #icon><FormOutlined /></template>
|
>
|
||||||
</a-button>
|
<template #icon><FormOutlined /></template>
|
||||||
</a-tooltip>
|
</a-button>
|
||||||
<a-tooltip>
|
</a-tooltip>
|
||||||
<template #title>
|
</span>
|
||||||
{{ t('views.ne.common.restart') }}
|
<span v-roles:has="['admin', 'teacher']">
|
||||||
</template>
|
<a-tooltip>
|
||||||
<a-button
|
<template #title>
|
||||||
type="link"
|
{{ t('views.ne.common.restart') }}
|
||||||
@click.prevent="fnRecordMore('restart', record)"
|
</template>
|
||||||
>
|
<a-button
|
||||||
<template #icon><UndoOutlined /></template>
|
type="link"
|
||||||
</a-button>
|
@click.prevent="fnRecordMore('restart', record)"
|
||||||
</a-tooltip>
|
>
|
||||||
|
<template #icon><UndoOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
|
</span>
|
||||||
|
|
||||||
<a-tooltip placement="left">
|
<a-tooltip placement="left">
|
||||||
<template #title>{{ t('common.moreText') }}</template>
|
<template #title>{{ t('common.moreText') }}</template>
|
||||||
<a-dropdown placement="bottomRight" trigger="click">
|
<a-dropdown placement="bottomRight" trigger="click">
|
||||||
@@ -610,31 +616,30 @@ onMounted(() => {
|
|||||||
<FileTextOutlined />
|
<FileTextOutlined />
|
||||||
{{ t('views.ne.common.log') }}
|
{{ t('views.ne.common.log') }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="start">
|
<a-menu-item key="start" v-if="hasRoles(['admin'])">
|
||||||
<ThunderboltOutlined />
|
<ThunderboltOutlined />
|
||||||
{{ t('views.ne.common.start') }}
|
{{ t('views.ne.common.start') }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="stop">
|
<a-menu-item key="stop" v-if="hasRoles(['admin'])">
|
||||||
<CloseSquareOutlined />
|
<CloseSquareOutlined />
|
||||||
{{ t('views.ne.common.stop') }}
|
{{ t('views.ne.common.stop') }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item
|
<a-menu-item
|
||||||
key="reload"
|
key="reload"
|
||||||
v-if="
|
v-if="
|
||||||
!['OMC', 'PCF', 'IMS', 'MME'].includes(record.neType)
|
!['OMC', 'PCF', 'IMS', 'MME'].includes(
|
||||||
|
record.neType
|
||||||
|
) && hasRoles(['admin'])
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<SyncOutlined />
|
<SyncOutlined />
|
||||||
{{ t('views.ne.common.reload') }}
|
{{ t('views.ne.common.reload') }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item key="delete">
|
<a-menu-item key="delete" v-if="hasRoles(['admin'])">
|
||||||
<DeleteOutlined />
|
<DeleteOutlined />
|
||||||
{{ t('common.deleteText') }}
|
{{ t('common.deleteText') }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item
|
<a-menu-item key="oam" v-if="hasRoles(['admin'])">
|
||||||
key="oam"
|
|
||||||
v-if="!['OMC'].includes(record.neType)"
|
|
||||||
>
|
|
||||||
<FileTextOutlined />
|
<FileTextOutlined />
|
||||||
{{ t('views.ne.common.oam') }}
|
{{ t('views.ne.common.oam') }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
@@ -655,7 +660,7 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<template #expandedRowRender="{ record }">
|
<template #expandedRowRender="{ record }">
|
||||||
<a-row>
|
<a-row :gutter="16">
|
||||||
<a-col :offset="2" :lg="8" :md="8" :xs="8">
|
<a-col :offset="2" :lg="8" :md="8" :xs="8">
|
||||||
<a-divider orientation="left">
|
<a-divider orientation="left">
|
||||||
{{ t('views.ne.neInfo.info') }}
|
{{ t('views.ne.neInfo.info') }}
|
||||||
|
|||||||
66
src/views/plugins/auth-user.ts
Normal file
66
src/views/plugins/auth-user.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { ADMIN_PERMISSION, ADMIN_ROLE_KEY } from '@/constants/admin-constants';
|
||||||
|
import useUserStore from '@/store/modules/user';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否系统管理员
|
||||||
|
* @returns true | false
|
||||||
|
*/
|
||||||
|
export function isSystemAdmin(): boolean {
|
||||||
|
const userPermissions = useUserStore().permissions;
|
||||||
|
if (userPermissions.includes(ADMIN_PERMISSION)) return true;
|
||||||
|
const userRoles = useUserStore().roles;
|
||||||
|
if (userRoles.includes(ADMIN_ROLE_KEY)) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只需含有其中权限
|
||||||
|
* @param role 权限字符数组
|
||||||
|
* @returns true | false
|
||||||
|
*/
|
||||||
|
export function hasPermissions(permissions: string[]): boolean {
|
||||||
|
if (!permissions || permissions.length === 0) return false;
|
||||||
|
const userPermissions = useUserStore().permissions;
|
||||||
|
if (!userPermissions || userPermissions.length === 0) return false;
|
||||||
|
if (userPermissions.includes(ADMIN_PERMISSION)) return true;
|
||||||
|
return permissions.some(p => userPermissions.some(up => up === p));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同时匹配其中权限
|
||||||
|
* @param role 权限字符数组
|
||||||
|
* @returns true | false
|
||||||
|
*/
|
||||||
|
export function matchPermissions(permissions: string[]): boolean {
|
||||||
|
if (!permissions || permissions.length === 0) return false;
|
||||||
|
const userPermissions = useUserStore().permissions;
|
||||||
|
if (!userPermissions || userPermissions.length === 0) return false;
|
||||||
|
if (userPermissions.includes(ADMIN_PERMISSION)) return true;
|
||||||
|
return permissions.every(p => userPermissions.some(up => up === p));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只需含有其中角色
|
||||||
|
* @param role 角色字符数组
|
||||||
|
* @returns true | false
|
||||||
|
*/
|
||||||
|
export function hasRoles(roles: string[]): boolean {
|
||||||
|
if (!roles || roles.length === 0) return false;
|
||||||
|
const userRoles = useUserStore().roles;
|
||||||
|
if (!userRoles || userRoles.length === 0) return false;
|
||||||
|
if (userRoles.includes(ADMIN_ROLE_KEY)) return true;
|
||||||
|
return roles.some(r => userRoles.some(ur => ur === r));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同时匹配其中角色
|
||||||
|
* @param role 角色字符数组
|
||||||
|
* @returns true | false
|
||||||
|
*/
|
||||||
|
export function matchRoles(roles: string[]): boolean {
|
||||||
|
if (!roles || roles.length === 0) return false;
|
||||||
|
const userRoles = useUserStore().roles;
|
||||||
|
if (!userRoles || userRoles.length === 0) return false;
|
||||||
|
if (userRoles.includes(ADMIN_ROLE_KEY)) return true;
|
||||||
|
return roles.every(r => userRoles.some(ur => ur === r));
|
||||||
|
}
|
||||||
171
src/views/store/modules/user.ts
Normal file
171
src/views/store/modules/user.ts
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
import defaultAvatar from '@/assets/images/default_avatar.png';
|
||||||
|
import useLayoutStore from './layout';
|
||||||
|
import { login, logout, getInfo } from '@/api/login';
|
||||||
|
import { setToken, removeToken } from '@/plugins/auth-token';
|
||||||
|
import { defineStore } from 'pinia';
|
||||||
|
import { TOKEN_RESPONSE_FIELD } from '@/constants/token-constants';
|
||||||
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
|
import { parseUrlPath } from '@/plugins/file-static-url';
|
||||||
|
|
||||||
|
/**用户信息类型 */
|
||||||
|
type UserInfo = {
|
||||||
|
/**用户ID */
|
||||||
|
userId: string;
|
||||||
|
/**登录账号 */
|
||||||
|
userName: string;
|
||||||
|
/**用户角色 字符串数组 */
|
||||||
|
roles: string[];
|
||||||
|
/**用户权限 字符串数组 */
|
||||||
|
permissions: string[];
|
||||||
|
/**用户头像 */
|
||||||
|
avatar: string;
|
||||||
|
/**用户昵称 */
|
||||||
|
nickName: string;
|
||||||
|
/**用户手机号 */
|
||||||
|
phonenumber: string;
|
||||||
|
/**用户邮箱 */
|
||||||
|
email: string;
|
||||||
|
/**用户性别 */
|
||||||
|
sex: string | undefined;
|
||||||
|
/**其他信息 */
|
||||||
|
profile: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const useUserStore = defineStore('user', {
|
||||||
|
state: (): UserInfo => ({
|
||||||
|
userId: '',
|
||||||
|
userName: '',
|
||||||
|
roles: [],
|
||||||
|
permissions: [],
|
||||||
|
avatar: '',
|
||||||
|
nickName: '',
|
||||||
|
phonenumber: '',
|
||||||
|
email: '',
|
||||||
|
sex: undefined,
|
||||||
|
profile: {},
|
||||||
|
}),
|
||||||
|
getters: {
|
||||||
|
/**
|
||||||
|
* 获取正确头像地址
|
||||||
|
* @param state 内部属性不用传入
|
||||||
|
* @returns 头像地址url
|
||||||
|
*/
|
||||||
|
getAvatar(state) {
|
||||||
|
if (!state.avatar) {
|
||||||
|
return defaultAvatar;
|
||||||
|
}
|
||||||
|
return parseUrlPath(state.avatar);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 获取基础信息属性
|
||||||
|
* @param state 内部属性不用传入
|
||||||
|
* @returns 基础信息
|
||||||
|
*/
|
||||||
|
getBaseInfo(state) {
|
||||||
|
return {
|
||||||
|
nickName: state.nickName,
|
||||||
|
phonenumber: state.phonenumber,
|
||||||
|
email: state.email,
|
||||||
|
sex: state.sex,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
/**
|
||||||
|
* 更新基础信息属性
|
||||||
|
* @param data 变更信息
|
||||||
|
*/
|
||||||
|
setBaseInfo(data: Record<string, any>) {
|
||||||
|
this.nickName = data.nickName;
|
||||||
|
this.phonenumber = data.phonenumber;
|
||||||
|
this.email = data.email;
|
||||||
|
this.sex = data.sex;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 更新头像
|
||||||
|
* @param avatar 上传后的地址
|
||||||
|
*/
|
||||||
|
setAvatar(avatar: string) {
|
||||||
|
this.avatar = avatar;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 获取正确头像地址
|
||||||
|
* @param avatar
|
||||||
|
*/
|
||||||
|
fnAvatar(avatar: string) {
|
||||||
|
if (!avatar) {
|
||||||
|
return defaultAvatar;
|
||||||
|
}
|
||||||
|
return parseUrlPath(avatar);
|
||||||
|
},
|
||||||
|
// 登录
|
||||||
|
async fnLogin(loginBody: Record<string, string>) {
|
||||||
|
const res = await login(loginBody);
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||||
|
const token = res.data[TOKEN_RESPONSE_FIELD];
|
||||||
|
setToken(token);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
// 获取用户信息
|
||||||
|
async fnGetInfo() {
|
||||||
|
const res = await getInfo();
|
||||||
|
if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||||
|
const { user, roles, permissions } = res.data;
|
||||||
|
this.userId = user.userId;
|
||||||
|
// 登录账号
|
||||||
|
this.userName = user.userName;
|
||||||
|
// 用户头像
|
||||||
|
this.avatar = user.avatar;
|
||||||
|
// 基础信息
|
||||||
|
this.nickName = user.nickName;
|
||||||
|
this.phonenumber = user.phonenumber;
|
||||||
|
this.email = user.email;
|
||||||
|
this.sex = user.sex;
|
||||||
|
|
||||||
|
// 验证返回的roles是否是一个非空数组
|
||||||
|
if (Array.isArray(roles) && roles.length > 0) {
|
||||||
|
this.roles = roles;
|
||||||
|
this.permissions = permissions;
|
||||||
|
} else {
|
||||||
|
this.roles = ['ROLE_DEFAULT'];
|
||||||
|
this.permissions = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 水印文字信息=用户昵称 手机号
|
||||||
|
let waterMarkContent = this.userName;
|
||||||
|
if (this.phonenumber) {
|
||||||
|
waterMarkContent = `${this.userName} ${this.phonenumber}`;
|
||||||
|
}
|
||||||
|
// useLayoutStore().changeWaterMark(waterMarkContent);
|
||||||
|
useLayoutStore().changeWaterMark('');
|
||||||
|
// 学生布局用不一样的
|
||||||
|
if (this.roles.includes('student')) {
|
||||||
|
useLayoutStore().changeConf('layout', 'side');
|
||||||
|
useLayoutStore().changeConf('menuTheme', 'dark');
|
||||||
|
useLayoutStore().changeConf('tabRender', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 网络错误时退出登录状态
|
||||||
|
if (res.code === 0) {
|
||||||
|
removeToken();
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
// 退出系统
|
||||||
|
async fnLogOut() {
|
||||||
|
try {
|
||||||
|
await logout();
|
||||||
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
this.roles = [];
|
||||||
|
this.permissions = [];
|
||||||
|
removeToken();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default useUserStore;
|
||||||
Reference in New Issue
Block a user