Compare commits
4 Commits
Author | SHA1 | Date |
---|---|---|
|
1c34f2bd89 | |
|
3057dc64bf | |
|
1d3284d7f9 | |
|
a16645c060 |
|
@ -41,7 +41,8 @@
|
|||
"passwordMsg": "The password can not be less than 6 digits",
|
||||
"check": "Check",
|
||||
"submit": "Submit",
|
||||
"instance": "Instance"
|
||||
"instance": "Instance",
|
||||
"select": "Select"
|
||||
},
|
||||
"menu": {
|
||||
"taskManagement": "Task",
|
||||
|
@ -92,6 +93,7 @@
|
|||
"resourceList": "API Management",
|
||||
"oplList": "Operation Logs",
|
||||
"login": "Login",
|
||||
"register": "Register",
|
||||
"monitorSelect": "Monitor",
|
||||
"monitorSelectBk": "Resource Center",
|
||||
"monitorSelectNew": "PCM Overview",
|
||||
|
@ -103,7 +105,14 @@
|
|||
"appObserve": "App Monitoring",
|
||||
"logMana": "Log Mgmt",
|
||||
"monitorSelectPcm": "JCCE",
|
||||
"fileManagement": "File Management"
|
||||
"fileManagement": "File Management",
|
||||
"blockchain": "存证查验",
|
||||
"blockchainLog": "数据可信核验",
|
||||
"blockchainBrowser": "区块链浏览器",
|
||||
"datasetManagement": "数据集管理",
|
||||
"algorithmManagement": "算法管理",
|
||||
"imageManagement": "镜像管理",
|
||||
"modelManagement": "模型管理"
|
||||
},
|
||||
"check": {
|
||||
"input": "Please Input",
|
||||
|
@ -551,6 +560,7 @@
|
|||
"result": "Result",
|
||||
"pictureUpload": "Picture Upload",
|
||||
"createDeductiveTask": "Create Deductive Task",
|
||||
"createTrainingTask": "中国算力网——智算训练任务创建",
|
||||
"image": "Image",
|
||||
"initFile": "Init File",
|
||||
"codeUpload": "Code Upload",
|
||||
|
@ -574,6 +584,27 @@
|
|||
"partition": "Partition",
|
||||
"cmdScript": "Script",
|
||||
"fileUpload": "File Upload",
|
||||
"uploadSuccess": "Upload Success"
|
||||
"uploadSuccess": "Upload Success",
|
||||
"cpCluster": "Computing Power Cluster",
|
||||
"computingResource": "Computing Resource",
|
||||
"internet": "Internet",
|
||||
"visualization": "Visualization",
|
||||
"codeBranch": "Branch",
|
||||
"runParams": "Params",
|
||||
"imageName": "Image Name",
|
||||
"packageName": "Package Name",
|
||||
"targetCluster": "Target Cluster",
|
||||
"datasetCategory": "Dataset Category",
|
||||
"resourceRecom": "Resource Recommendation",
|
||||
"authSetting": "Authentification Setting",
|
||||
"applyList": "Apply List",
|
||||
"applyAccount": "Apply Account",
|
||||
"applyDataset": "Applied Dataset",
|
||||
"applyModel": "Applied Model Name",
|
||||
"category": "Category",
|
||||
"datasetApplied": "Applied Dataset",
|
||||
"modelApplied": "Applied Model",
|
||||
"forApply": "Can Apply List",
|
||||
"sonAlgorithmName": "Son Algorithm Name"
|
||||
}
|
||||
}
|
|
@ -41,7 +41,8 @@
|
|||
"passwordMsg": "密码不能少于6位",
|
||||
"check": "验证",
|
||||
"submit": "提交",
|
||||
"instance": "实例"
|
||||
"instance": "实例",
|
||||
"select": "选择"
|
||||
},
|
||||
"menu": {
|
||||
"taskManagement": "任务管理",
|
||||
|
@ -92,6 +93,7 @@
|
|||
"resourceList": "接口管理",
|
||||
"oplList": "操作日志",
|
||||
"login": "登录",
|
||||
"register": "注册",
|
||||
"monitorSelect": "综合运控",
|
||||
"monitorSelectBk": "资源中心",
|
||||
"monitorSelectNew": "PCM总览",
|
||||
|
@ -103,7 +105,16 @@
|
|||
"appObserve": "应用观测",
|
||||
"logMana": "日志管理",
|
||||
"monitorSelectPcm": "云际算力网基础平台",
|
||||
"fileManagement": "文件管理"
|
||||
"fileManagement": "文件管理",
|
||||
"blockchain": "存证查验",
|
||||
"blockchainLog": "数据可信核验",
|
||||
"blockchainBrowser": "区块链浏览器",
|
||||
"datasetManagement": "数据集管理",
|
||||
"algorithmManagement": "算法管理",
|
||||
"imageManagement": "镜像管理",
|
||||
"modelManagement": "模型管理",
|
||||
"personalCenter": "个人中心",
|
||||
"pointManagement": "积分管理"
|
||||
},
|
||||
"check": {
|
||||
"input": "请输入",
|
||||
|
@ -551,6 +562,7 @@
|
|||
"result": "结果",
|
||||
"pictureUpload": "图片上传",
|
||||
"createDeductiveTask": "创建智算推理任务",
|
||||
"createTrainingTask": "中国算力网——智算训练任务创建",
|
||||
"image": "镜像",
|
||||
"initFile": "启动文件",
|
||||
"codeUpload": "代码上传",
|
||||
|
@ -574,6 +586,27 @@
|
|||
"partition": "分区",
|
||||
"cmdScript": "脚本",
|
||||
"fileUpload": "文件上传",
|
||||
"uploadSuccess": "上传成功"
|
||||
"uploadSuccess": "上传成功",
|
||||
"cpCluster": "算力集群",
|
||||
"computingResource": "计算资源",
|
||||
"internet": "访问Internet",
|
||||
"visualization": "可视化",
|
||||
"codeBranch": "代码分支",
|
||||
"runParams": "运行参数",
|
||||
"imageName": "镜像名称",
|
||||
"packageName": "Package名称",
|
||||
"targetCluster": "目标集群",
|
||||
"datasetCategory": "数据集类别",
|
||||
"resourceRecom": "资源推荐",
|
||||
"authSetting": "访问权限设置",
|
||||
"applyList": "申请列表",
|
||||
"applyAccount": "申请用户",
|
||||
"applyDataset": "申请使用数据集名称",
|
||||
"applyModel": "申请使用模型名称",
|
||||
"category": "类别",
|
||||
"datasetApplied": "申请使用数据集名称",
|
||||
"modelApplied": "申请使用模型名称",
|
||||
"forApply": "可申请数据集",
|
||||
"sonAlgorithmName": "子算法名称"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
const preUrl = '/jcc-admin'
|
||||
export function login(username, password) {
|
||||
return request({
|
||||
url: preUrl + '/admin/login',
|
||||
method: 'post',
|
||||
data: {
|
||||
username,
|
||||
password
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getInfo() {
|
||||
return request({
|
||||
url: preUrl + '/admin/info',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function logout() {
|
||||
return request({
|
||||
url: preUrl + '/admin/logout',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
export function getUserList(params) {
|
||||
return request({
|
||||
url: preUrl + '/admin/list',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function createAdmin(data) {
|
||||
return request({
|
||||
url: preUrl + '/admin/register',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateAdmin(id, data) {
|
||||
return request({
|
||||
url: preUrl + '/admin/update/' + id,
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateUserStatus(id, params) {
|
||||
return request({
|
||||
url: preUrl + '/admin/updateStatus/' + id,
|
||||
method: 'put',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteAdmin(id) {
|
||||
return request({
|
||||
url: preUrl + '/admin/delete/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function getRoleByAdmin(id) {
|
||||
return request({
|
||||
url: preUrl + '/admin/role/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function allocRole(data) {
|
||||
return request({
|
||||
url: preUrl + '/admin/role/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 角色列表
|
||||
export function getRoleList(params) {
|
||||
return request({
|
||||
url: preUrl + '/role/list',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function createRole(data) {
|
||||
return request({
|
||||
url: preUrl + '/role/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateRole(id, data) {
|
||||
return request({
|
||||
url: preUrl + '/role/update/' + id,
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateRoleStatus(id, params) {
|
||||
return request({
|
||||
url: preUrl + '/role/updateStatus/' + id,
|
||||
method: 'put',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteRole(params) {
|
||||
return request({
|
||||
url: preUrl + '/role/delete',
|
||||
method: 'delete',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchAllRoleList() {
|
||||
return request({
|
||||
url: preUrl + '/role/listAll',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function listMenuByRole(roleId) {
|
||||
return request({
|
||||
url: preUrl + '/role/listMenu/' + roleId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function listResourceByRole(roleId) {
|
||||
return request({
|
||||
url: preUrl + '/role/listResource/' + roleId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function allocMenu(data) {
|
||||
return request({
|
||||
url: preUrl + '/role/allocMenu',
|
||||
method: 'post',
|
||||
params: data
|
||||
})
|
||||
}
|
||||
|
||||
export function allocResource(data) {
|
||||
return request({
|
||||
url: preUrl + '/role/allocResource',
|
||||
method: 'post',
|
||||
params: data
|
||||
})
|
||||
}
|
||||
|
||||
// 菜单列表
|
||||
export function getMenuList(parentId, params) {
|
||||
return request({
|
||||
url: preUrl + '/menu/list/' + parentId,
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteMenu(id) {
|
||||
return request({
|
||||
url: preUrl + '/menu/delete/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function createMenu(data) {
|
||||
return request({
|
||||
url: preUrl + '/menu/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateMenu(id, data) {
|
||||
return request({
|
||||
url: preUrl + '/menu/update/' + id,
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function getMenu(id) {
|
||||
return request({
|
||||
url: preUrl + '/menu/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function updateHidden(id, params) {
|
||||
return request({
|
||||
url: preUrl + '/menu/updateHidden/' + id,
|
||||
method: 'put',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchTreeList() {
|
||||
return request({
|
||||
url: preUrl + '/menu/treeList',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 资源列表
|
||||
export function getResourceList(params) {
|
||||
return request({
|
||||
url: preUrl + '/resource/list',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function createResource(data) {
|
||||
return request({
|
||||
url: preUrl + '/resource/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateResource(id, data) {
|
||||
return request({
|
||||
url: preUrl + '/resource/update/' + id,
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteResource(id) {
|
||||
return request({
|
||||
url: preUrl + '/resource/delete/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchAllResourceList() {
|
||||
return request({
|
||||
url: preUrl + '/resource/listAll',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function listAllCate() {
|
||||
return request({
|
||||
url: preUrl + '/resourceCategory/listAll',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function createResourceCategory(data) {
|
||||
return request({
|
||||
url: preUrl + '/resourceCategory/create',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateResourceCategory(id, data) {
|
||||
return request({
|
||||
url: preUrl + '/resourceCategory/update/' + id,
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteResourceCategory(id) {
|
||||
return request({
|
||||
url: preUrl + '/resourceCategory/delete/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 区块列表信息-最新区块
|
||||
export function getBlockList(params) {
|
||||
return request({
|
||||
url: '/blockChain/blockChain/block/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 左上角信息
|
||||
export function getBlockChain(params) {
|
||||
return request({
|
||||
url: '/blockChain/blockChain',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 合约调用记录分页查询-最新交易列表
|
||||
export function getRecordPage(params) {
|
||||
return request({
|
||||
url: '/blockChain/invoke/record/page',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 查询区块上的交易列表
|
||||
export function getTransactions(id) {
|
||||
return request({
|
||||
url: '/blockChain/blockChain/transactions/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 合约列表
|
||||
export function getContractList(params) {
|
||||
return request({
|
||||
url: '/blockChain/contract/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 查询日志列表
|
||||
export function getBusinessLog(params) {
|
||||
return request({
|
||||
url: '/blockChain/businessLog/page',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 节点列表
|
||||
export function getNodeList(params) {
|
||||
return request({
|
||||
url: '/blockChain/blockChain/node/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 合约调用记录详情--交易详情
|
||||
export function getRecordDetail(params) {
|
||||
return request({
|
||||
url: '/blockChain/invoke/record/detail',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 查询合约
|
||||
export function getRecordQuery(params) {
|
||||
return request({
|
||||
url: '/blockChain/invoke/record/query',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 7日交易量
|
||||
export function get7dayChart() {
|
||||
return request({
|
||||
url: '/blockChain/invoke/record/7dayChart',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 最近7日积分变动情况
|
||||
export function get7dayChart(params) {
|
||||
return request({
|
||||
url: '/blockChain/points/record/7dayChart',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 查询余额
|
||||
export function getBalance(params) {
|
||||
return request({
|
||||
url: '/blockChain/points/balance',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 积分流水
|
||||
export function getRecordList(params) {
|
||||
return request({
|
||||
url: '/blockChain/points/record/page',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
// 根据txHash查询积分记录
|
||||
export function getPointByHash(params) {
|
||||
return request({
|
||||
url: '/blockChain/points/record/getByTxHash',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
import request from '@/utils/jcs-request'
|
||||
|
||||
export const taskSubmit = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/submit',
|
||||
method: 'post',
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const getFileList = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/queryUploaded',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const createPackage = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/createPackage',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function registerAdmin(params) {
|
||||
return request({
|
||||
url: '/jsm/user/register',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// export const getUploadData = (data) => {
|
||||
// return request({
|
||||
// url: '/jsm/jobSet/notifyUploaded',
|
||||
// method: 'post',
|
||||
// data,
|
||||
// headers: {
|
||||
// 'Content-Type': 'application/json'
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
export const getUploadData = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/notifyUploaded',
|
||||
method: 'post',
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const uploadData = (data) => {
|
||||
return request({
|
||||
url: '/jcs/object/upload',
|
||||
method: 'post',
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const downloadFile = (params) => {
|
||||
return request({
|
||||
url: '/jcs/object/download',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export const updatecode = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/updateCode',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const uploadSuccessMessage = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/localFileUploaded',
|
||||
method: 'post',
|
||||
data,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const createFolder = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/createFolder',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const deleteFolder = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/deleteFolder',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const deleteFile = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/deleteFile',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const deletePackage = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/deletePackage',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const getBindingList = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/queryBinding',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const addBinding = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/binding',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const deleteBinding = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/removeBinding',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const queryImages = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/queryImages',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const getResourceListByfilter = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/queryResource',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const getResourceRange = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/resourceRange',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const createTrainingTask = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/submit',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const getApplyList = (data) => {
|
||||
return request({
|
||||
url: '/jsm/access/getAccessRequests',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export const confirmApply = (data) => {
|
||||
return request({
|
||||
url: '/jsm/access/approvalRequestAccess',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 访问权限设置
|
||||
export const accessAuthSetting = (data) => {
|
||||
return request({
|
||||
url: '/jsm/access/updateBindingDataAccess',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 撤销申请接口 取消访问 status值:撤销申请:revoked,取消访问:cancel
|
||||
export const cancelApply = (data) => {
|
||||
return request({
|
||||
url: '/jsm/access/updateAccessRequestStatus',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 申请访问接口
|
||||
export const applyData = (data) => {
|
||||
return request({
|
||||
url: '/jsm/access/applyRequestAccess',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取userID
|
||||
export const getUserID = (params) => {
|
||||
return request({
|
||||
url: '/jsm/user/query',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 创建子算法:/jobSet/addChildrenCode
|
||||
export const addCode = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/addCodeVersion',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 查询算法列表
|
||||
export const queryCodeList = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/queryCodeVersion',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除算法
|
||||
export const deleteCode = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/removeCodeVersion',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 查询上传状态
|
||||
export const getStatusList = (data) => {
|
||||
return request({
|
||||
url: '/jsm/jobSet/uploadStatus',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
|
@ -37,7 +37,9 @@ export const getTrainingTaskStat = () => {
|
|||
export const getInstanceList = (params) => {
|
||||
return request({ url: '/pcm/v1/inference/instanceCenter', method: 'get', params })
|
||||
}
|
||||
|
||||
export const getHpcInstanceList = (params) => {
|
||||
return request({ url: '/pcm/v1/hpc/ListInstanceCenter', method: 'get', params })
|
||||
}
|
||||
export const getAppPodsByAppName = (name, params) => {
|
||||
return request({ url: '/pcm/v1/apps/pods/' + name, method: 'get', params })
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 874 B |
After Width: | Height: | Size: 146 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 283 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 981 B |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 4.9 KiB |
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 174 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 2.1 KiB |
|
@ -26,6 +26,16 @@
|
|||
v-model="filterData[key]"
|
||||
type="date"
|
||||
/>
|
||||
<el-date-picker
|
||||
v-else-if="item.type === 'datetimerange'"
|
||||
v-model="filterData[key]"
|
||||
type="datetimerange"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
:range-separator="$t('message.to')"
|
||||
:start-placeholder="$t('message.startDate')"
|
||||
:end-placeholder="$t('message.endDate')"
|
||||
align="right"
|
||||
/>
|
||||
<template
|
||||
v-else-if="item.type === 'dateRange'"
|
||||
>
|
||||
|
@ -97,6 +107,7 @@
|
|||
:key="index"
|
||||
:prop="item.prop"
|
||||
:label="item.label"
|
||||
:min-width="item.minWidth"
|
||||
:width="item.width"
|
||||
:formatter="item.formatter"
|
||||
:sortable="item.sortable"
|
||||
|
@ -302,6 +313,12 @@ export default {
|
|||
...this.query,
|
||||
...this.filterData
|
||||
}
|
||||
// 查找条件中 含有时间范围 需要转换
|
||||
if (this.filterMap && 'time' in this.filterMap && this.filterMap.time.type === 'datetimerange' && params.time) {
|
||||
params.startTime = params.time[0]
|
||||
params.endTime = params.time[1]
|
||||
params.time = undefined
|
||||
}
|
||||
if (this.getListAction) {
|
||||
const ListData = await this.getListAction(params)
|
||||
this.total = Number(ListData?.data?.[this.totalKey]) || Number(ListData[this.totalKey]) || 0
|
||||
|
|
|
@ -59,6 +59,12 @@
|
|||
<el-dropdown-item v-if="menus.includes('fileManagement')" @click.native="toFileManagement">
|
||||
{{ $t('menu.fileManagement') }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="menus.includes('blockchain')" @click.native="toBlockchainBrowser">
|
||||
存证查验
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item v-if="menus.includes('pointManagement')" @click.native="toPersonalCenter">
|
||||
积分管理
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided @click.native="logout">
|
||||
<span style="display:block;">{{ $t('message.logout') }}</span>
|
||||
</el-dropdown-item>
|
||||
|
@ -156,6 +162,10 @@ export default {
|
|||
toMoniter() {
|
||||
window.open('https://www.jointcloud.net/dashboard/dashboards', '_blank')
|
||||
},
|
||||
toBlockchainBrowser() {
|
||||
this.$store.dispatch('user/setRouteType', 'blockchain')
|
||||
this.$router.push({ path: '/blockchain/blockchainBrowser' })
|
||||
},
|
||||
toContainerCost() {
|
||||
this.$store.dispatch('user/setRouteType', 'containerCost')
|
||||
this.$router.push({ path: '/containerCost' })
|
||||
|
@ -172,6 +182,10 @@ export default {
|
|||
this.$store.dispatch('user/setRouteType', 'fileManagement')
|
||||
this.$router.push({ path: '/fileManagement/fileList' })
|
||||
},
|
||||
toPersonalCenter() {
|
||||
this.$store.dispatch('user/setRouteType', 'personalCenter')
|
||||
this.$router.push({ path: '/personalCenter/pointManagement' })
|
||||
},
|
||||
toSetting() {
|
||||
this.$store.dispatch('user/setRouteType', 'setting')
|
||||
this.$router.push({ path: '/setting/dictManagement' })
|
||||
|
@ -181,7 +195,7 @@ export default {
|
|||
},
|
||||
async logout() {
|
||||
await this.$store.dispatch('user/logout')
|
||||
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
|
||||
this.$router.push(`/login`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
import { getNodeList } from '@/api/blockchain/blockchain'
|
||||
import { getDictByCode } from '@/api/common/setting'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
nodeList: [], // 节点列表
|
||||
typeNameList: [], // 记录类型
|
||||
pointsList: [] // 积分变动类型
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
getNodeList().then(e => { this.nodeList = e.data })
|
||||
getDictByCode('contract-type-dict').then(e => { this.typeNameList = e.data.list })
|
||||
getDictByCode('point-type-dict').then(res => { this.pointsList = res.data?.list || [] })
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ import getPageTitle from '@/utils/get-page-title'
|
|||
|
||||
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
||||
|
||||
const whiteList = ['/login', '/auth-redirect'] // no redirect whitelist
|
||||
const whiteList = ['/login', '/register', '/auth-redirect'] // no redirect whitelist
|
||||
|
||||
router.beforeEach(async(to, from, next) => {
|
||||
// start progress bar
|
||||
|
@ -43,16 +43,16 @@ router.beforeEach(async(to, from, next) => {
|
|||
await store.dispatch('cluster/getClusterList')
|
||||
}
|
||||
// get user info
|
||||
const { roleName } = await store.dispatch('user/getInfo')
|
||||
const { roles, menuNames, id } = await store.dispatch('user/getInfo')
|
||||
|
||||
// get user menus
|
||||
const menus = await store.dispatch('user/getMenus')
|
||||
store.dispatch('user/getUserID', id)
|
||||
// // get user menus
|
||||
// const menus = await store.dispatch('user/getMenus')
|
||||
|
||||
store.dispatch('user/getDict')
|
||||
|
||||
// generate accessible routes map based on roles
|
||||
const accessRoutes = await store.dispatch('permission/generateRoutes', { menus, roleName })
|
||||
|
||||
const accessRoutes = await store.dispatch('permission/generateRoutes', { menuNames, roles })
|
||||
// dynamically add accessible routes
|
||||
router.addRoutes(accessRoutes)
|
||||
|
||||
|
@ -71,7 +71,6 @@ router.beforeEach(async(to, from, next) => {
|
|||
}
|
||||
} else {
|
||||
/* has no token*/
|
||||
|
||||
if (whiteList.indexOf(to.path) !== -1) {
|
||||
// in the free login whitelist, go directly
|
||||
next()
|
||||
|
|
|
@ -7,7 +7,8 @@ import Layout from '@/layout'
|
|||
// import emptyLayout from '@/layout/emptyLayout'
|
||||
import podRouter from './modules/pod'
|
||||
import virtualMachineRouter from './modules/virtualMachine'
|
||||
import blockChainRouter from './modules/blockChain'
|
||||
import blockchainManagementRouter from './modules/blockchain'
|
||||
import personalCenter from './modules/personalCenter'
|
||||
import functionsRouter from './modules/functions'
|
||||
import permissionRouter from './modules/permissionManagement'
|
||||
import monitorRouter from './modules/warnManagement'
|
||||
|
@ -68,6 +69,13 @@ export const constantRoutes = [
|
|||
meta: { title: 'login' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/register',
|
||||
component: () => import('@/views/login/register'),
|
||||
meta: { title: 'register' },
|
||||
name: 'register',
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: '/auth-redirect',
|
||||
component: () => import('@/views/login/auth-redirect'),
|
||||
|
@ -155,7 +163,7 @@ export const asyncRoutes = [
|
|||
},
|
||||
podRouter,
|
||||
virtualMachineRouter,
|
||||
blockChainRouter,
|
||||
blockchainManagementRouter,
|
||||
functionsRouter,
|
||||
permissionRouter,
|
||||
monitorRouter,
|
||||
|
@ -166,7 +174,8 @@ export const asyncRoutes = [
|
|||
taskManagementRouter,
|
||||
strategyManagementRouter,
|
||||
adapterMangementRouter,
|
||||
fileManagementRouter
|
||||
fileManagementRouter,
|
||||
personalCenter
|
||||
]
|
||||
|
||||
const createRouter = () => new Router({
|
||||
|
|
|
@ -1,40 +1,27 @@
|
|||
import Layout from '@/layout'
|
||||
import emptyLayout from '@/layout/emptyLayout'
|
||||
const blockChainRouter = {
|
||||
path: '/blockChain',
|
||||
const blockchainManagementRouter = {
|
||||
path: '/blockchain',
|
||||
component: Layout,
|
||||
name: '云际记账',
|
||||
name: 'blockchain',
|
||||
meta: {
|
||||
title: '云际记账',
|
||||
icon: 'yunjijizhang'
|
||||
title: 'blockchain',
|
||||
icon: 'qukuailian'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'blockChainBrowser',
|
||||
component: () => import('@/views/blockChain/blockChainBrowser'),
|
||||
name: 'blockChainBrowser',
|
||||
meta: { title: '块链浏览器', icon: 'gailan', affix: true }
|
||||
path: 'blockchainBrowser',
|
||||
component: () => import('@/views/blockChain/blockchainBrowser'),
|
||||
name: 'blockchainBrowser',
|
||||
meta: { title: 'blockchainBrowser', icon: 'gailan', affix: true },
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
path: 'blockList',
|
||||
component: emptyLayout,
|
||||
meta: { activeMenu: '/block/blockChainBrowser' },
|
||||
hidden: true,
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: () => import('@/views/blockChain/blockList'),
|
||||
name: 'blockList'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: 'blockChainDataCheck',
|
||||
component: () => import('@/views/blockChain/blockChainDataCheck'),
|
||||
name: 'blockChainDataCheck',
|
||||
meta: { title: '数据可信核验', icon: 'cunchu-ziyuanshezhi', affix: true },
|
||||
path: 'blockchainLog',
|
||||
component: () => import('@/views/blockChain/blockchainLog'),
|
||||
name: 'blockchainLog',
|
||||
meta: { title: 'blockchainLog', icon: 'qukuailianchaxun', affix: true },
|
||||
hidden: false
|
||||
}
|
||||
]
|
||||
}
|
||||
export default blockChainRouter
|
||||
export default blockchainManagementRouter
|
||||
|
|
|
@ -1,19 +1,57 @@
|
|||
import Layout from '@/layout'
|
||||
// import emptyLayout from '@/layout/emptyLayout'
|
||||
|
||||
const fileManagementRouter = {
|
||||
path: '/fileManagement',
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: 'fileManagement',
|
||||
title: 'storageMana',
|
||||
icon: 'xunijiguanli-juan'
|
||||
},
|
||||
name: 'fileManagement',
|
||||
children: [
|
||||
{
|
||||
path: 'packageList',
|
||||
component: () => import('@/views/fileManagement/fileList/packageList.vue'),
|
||||
meta: { title: 'fileManagement', icon: 'wenjiancunchu', affix: true, keepAlive: true },
|
||||
name: 'packageList',
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
path: 'fileList',
|
||||
component: () => import('@/views/fileManagement/fileList/list'),
|
||||
name: 'fileManagement',
|
||||
meta: { title: 'overview', icon: 'gailan', affix: true },
|
||||
component: () => import('@/views/fileManagement/fileList/fileList.vue'),
|
||||
meta: { activeMenu: '/fileManagement/packageList' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'datasetList',
|
||||
component: () => import('@/views/fileManagement/datasetManagement/list'),
|
||||
name: 'datasetManagement',
|
||||
meta: { title: 'datasetManagement', icon: 'shujuji', affix: true },
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
path: 'algorithmList',
|
||||
component: () => import('@/views/fileManagement/algorithmManagement/list'),
|
||||
name: 'algorithmManagement',
|
||||
meta: { title: 'algorithmManagement', icon: 'suanfa', affix: true },
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
path: 'imageList',
|
||||
component: () => import('@/views/fileManagement/imageManagement/list'),
|
||||
name: 'imageManagement',
|
||||
meta: { title: 'imageManagement', icon: 'jingxiang', affix: true },
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
path: 'modelList',
|
||||
component: () => import('@/views/fileManagement/modelManagement/list'),
|
||||
name: 'modelManagement',
|
||||
meta: { title: 'modelManagement', icon: 'moxing', affix: true },
|
||||
hidden: false
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
export default fileManagementRouter
|
||||
|
|
|
@ -2,6 +2,7 @@ import Layout from '@/layout'
|
|||
const permissionRouter = {
|
||||
path: '/permissionManagement',
|
||||
component: Layout,
|
||||
name: 'permissionManagement',
|
||||
meta: {
|
||||
title: 'authManagement',
|
||||
icon: 'xiangmuguanli'
|
||||
|
@ -35,13 +36,13 @@ const permissionRouter = {
|
|||
component: () => import('@/views/permissionManagement/resourceList'),
|
||||
name: 'resourceList',
|
||||
meta: { title: 'resourceList', icon: 'cunchujuanxinxi', affix: true }
|
||||
},
|
||||
{
|
||||
path: 'oplList',
|
||||
component: () => import('@/views/permissionManagement/oplList'),
|
||||
name: 'oplList',
|
||||
meta: { title: 'oplList', icon: 'gongzuofuzai', affix: true }
|
||||
}
|
||||
// {
|
||||
// path: 'oplList',
|
||||
// component: () => import('@/views/permissionManagement/resourceCategoryList'),
|
||||
// name: 'oplList',
|
||||
// meta: { title: 'oplList', icon: 'gongzuofuzai', affix: true }
|
||||
// }
|
||||
]
|
||||
}
|
||||
export default permissionRouter
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import Layout from '@/layout'
|
||||
const personalCenterRouter = {
|
||||
path: '/personalCenter',
|
||||
component: Layout,
|
||||
meta: {
|
||||
title: 'personalCenter',
|
||||
icon: 'qukuailian'
|
||||
},
|
||||
name: 'personalCenter',
|
||||
children: [
|
||||
{
|
||||
path: 'pointManagement',
|
||||
component: () => import('@/views/blockChain/pointManagement'),
|
||||
name: 'pointManagement',
|
||||
meta: { title: 'pointManagement', icon: 'gailan', affix: true },
|
||||
hidden: false
|
||||
}
|
||||
]
|
||||
}
|
||||
export default personalCenterRouter
|
|
@ -5,7 +5,7 @@ const taskManagementRouter = {
|
|||
name: 'taskManagement',
|
||||
meta: {
|
||||
title: 'taskManagement',
|
||||
icon: 'rongqizu'
|
||||
icon: 'renwuguanli1'
|
||||
},
|
||||
children: [
|
||||
{
|
||||
|
@ -36,33 +36,47 @@ const taskManagementRouter = {
|
|||
meta: { activeMenu: '/taskManagement/taskList' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'result',
|
||||
component: () => import('@/views/taskManagement/taskList/result'),
|
||||
name: 'result',
|
||||
meta: { activeMenu: '/taskManagement/taskList' },
|
||||
hidden: true
|
||||
},
|
||||
{
|
||||
path: 'taskList',
|
||||
component: () => import('@/views/taskManagement/taskList/list'),
|
||||
name: 'taskList',
|
||||
meta: { title: 'taskList', icon: 'gailan', affix: true },
|
||||
meta: { title: 'taskList', icon: 'renwuliebiao1', affix: true },
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
path: 'cloudList',
|
||||
component: () => import('@/views/taskManagement/cloudList/taskList'),
|
||||
name: 'cloudList',
|
||||
meta: { title: 'cloudList', icon: 'gailan', affix: true },
|
||||
meta: { title: 'cloudList', icon: 'shusuanziyuan', affix: true },
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
path: 'aiList',
|
||||
component: () => import('@/views/taskManagement/aiList/taskList'),
|
||||
name: 'aiList',
|
||||
meta: { title: 'aiList', icon: 'gailan', affix: true },
|
||||
meta: { title: 'aiList', icon: 'zhisuanrenwu', affix: true },
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
path: 'hpcList',
|
||||
component: () => import('@/views/taskManagement/hpcList/taskList'),
|
||||
name: 'hpcList',
|
||||
meta: { title: 'hpcList', icon: 'gailan', affix: true },
|
||||
meta: { title: 'hpcList', icon: 'chaosuan', affix: true },
|
||||
hidden: false
|
||||
},
|
||||
{
|
||||
path: 'appCenter',
|
||||
component: () => import('@/views/taskManagement/hpcList/appCenter'),
|
||||
name: 'appCenter',
|
||||
meta: { activeMenu: '/taskManagement/hpcList' },
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ const getters = {
|
|||
token: state => state.user.token,
|
||||
avatar: state => state.user.avatar,
|
||||
name: state => state.user.name,
|
||||
id: state => state.user.id,
|
||||
userID: state => state.user.userID,
|
||||
introduction: state => state.user.introduction,
|
||||
roles: state => state.user.roles,
|
||||
permission_routes: state => state.permission.routes,
|
||||
|
|
|
@ -5,14 +5,14 @@ import { asyncRoutes, constantRoutes } from '@/router'
|
|||
* @param routes asyncRoutes
|
||||
* @param roles
|
||||
*/
|
||||
export function filterAsyncRoutes(routes, menus) {
|
||||
export function filterAsyncRoutes(routes, menuNames) {
|
||||
const res = []
|
||||
|
||||
routes.forEach(route => {
|
||||
const tmp = { ...route }
|
||||
if (menus.includes(tmp.name)) {
|
||||
if (menuNames.includes(tmp.name)) {
|
||||
if (tmp.children) {
|
||||
tmp.children = filterAsyncRoutes(tmp.children, menus)
|
||||
tmp.children = filterAsyncRoutes(tmp.children, menuNames)
|
||||
}
|
||||
res.push(tmp)
|
||||
}
|
||||
|
@ -33,13 +33,13 @@ const mutations = {
|
|||
}
|
||||
|
||||
const actions = {
|
||||
generateRoutes({ commit }, { menus, roleName }) {
|
||||
generateRoutes({ commit }, { roles, menuNames }) {
|
||||
return new Promise(resolve => {
|
||||
let accessedRoutes = []
|
||||
if (roleName === 'admin') {
|
||||
if (roles.includes('admin')) {
|
||||
accessedRoutes = asyncRoutes
|
||||
} else {
|
||||
accessedRoutes = filterAsyncRoutes(asyncRoutes, menus)
|
||||
accessedRoutes = filterAsyncRoutes(asyncRoutes, menuNames)
|
||||
}
|
||||
commit('SET_ROUTES', accessedRoutes)
|
||||
resolve(accessedRoutes)
|
||||
|
|
|
@ -2,14 +2,18 @@
|
|||
import {
|
||||
login,
|
||||
logout,
|
||||
getInfo } from '@/api/authority/user'
|
||||
import { getUserMenus } from '@/api/authority/menu'
|
||||
import { getToken, setToken, removeToken } from '@/utils/auth'
|
||||
getInfo
|
||||
// , getUserMenus
|
||||
} from '@/api/authority/permissionManagement'
|
||||
import { getUserID } from '@/api/jcs/jcs'
|
||||
import { getToken, setToken, removeToken, setBCToken } from '@/utils/auth'
|
||||
import { resetRouter } from '@/router'
|
||||
import { getDictByCode } from '@/api/common/setting'
|
||||
const state = {
|
||||
token: getToken(),
|
||||
name: '',
|
||||
id: '',
|
||||
userID: Number(localStorage.getItem('userID')) || '',
|
||||
avatar: '',
|
||||
introduction: '',
|
||||
roles: [],
|
||||
|
@ -29,6 +33,12 @@ const mutations = {
|
|||
SET_NAME: (state, name) => {
|
||||
state.name = name
|
||||
},
|
||||
SET_ID: (state, id) => {
|
||||
state.id = id
|
||||
},
|
||||
SET_USERID: (state, userID) => {
|
||||
state.userID = Number(userID)
|
||||
},
|
||||
SET_AVATAR: (state, avatar) => {
|
||||
state.avatar = avatar
|
||||
},
|
||||
|
@ -55,9 +65,10 @@ const actions = {
|
|||
const { username, password } = userInfo
|
||||
return login(username, password).then(response => {
|
||||
const data = response.data
|
||||
const tokenStr = data.token
|
||||
const tokenStr = data.tokenHead + data.token
|
||||
commit('SET_TOKEN', tokenStr)
|
||||
setToken(tokenStr)
|
||||
setBCToken(tokenStr)
|
||||
})
|
||||
},
|
||||
|
||||
|
@ -75,7 +86,6 @@ const actions = {
|
|||
res.forEach((e, index) => {
|
||||
data[dictMap[index]] = e.data.list
|
||||
})
|
||||
|
||||
commit('SET_DICT', data)
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
|
@ -86,15 +96,39 @@ const actions = {
|
|||
|
||||
// get user info
|
||||
getInfo({ commit, state }) {
|
||||
function collectId(arr, names = []) {
|
||||
arr.forEach(({ name }) => {
|
||||
if (name) {
|
||||
names.push(name)
|
||||
}
|
||||
})
|
||||
return names
|
||||
}
|
||||
var names = []
|
||||
return new Promise((resolve, reject) => {
|
||||
getInfo().then(response => {
|
||||
const { data } = response
|
||||
if (!data) {
|
||||
reject('Verification failed, please Login again.')
|
||||
}
|
||||
const { roleName, username } = data
|
||||
commit('SET_ROLES', [roleName])
|
||||
const { roles, username, menus, id } = data
|
||||
const menuNames = collectId(menus, names)
|
||||
commit('SET_MENU', menuNames)
|
||||
commit('SET_ROLES', roles)
|
||||
commit('SET_NAME', username)
|
||||
commit('SET_ID', id)
|
||||
resolve({ menuNames, roles, id })
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
getUserID({ commit }, id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
getUserID({ ssoID: id }).then(response => {
|
||||
const { data } = response
|
||||
commit('SET_USERID', data.userID)
|
||||
localStorage.setItem('userID', data.userID)
|
||||
resolve(data)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
|
@ -102,35 +136,35 @@ const actions = {
|
|||
})
|
||||
},
|
||||
|
||||
// get user menus
|
||||
getMenus({ commit, state }) {
|
||||
function collectId(arr, names = []) {
|
||||
arr.forEach(({ name, children }) => {
|
||||
if (name) {
|
||||
names.push(name)
|
||||
}
|
||||
if (children) {
|
||||
collectId(children, names)
|
||||
}
|
||||
})
|
||||
return names
|
||||
}
|
||||
var names = []
|
||||
// // get user menus
|
||||
// getMenus({ commit, state }) {
|
||||
// function collectId(arr, names = []) {
|
||||
// arr.forEach(({ name, children }) => {
|
||||
// if (name) {
|
||||
// names.push(name)
|
||||
// }
|
||||
// if (children) {
|
||||
// collectId(children, names)
|
||||
// }
|
||||
// })
|
||||
// return names
|
||||
// }
|
||||
// var names = []
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
getUserMenus().then(response => {
|
||||
const { data } = response
|
||||
if (!data) {
|
||||
reject('Verification failed, please Login again.')
|
||||
}
|
||||
const menuNames = collectId(data, names)
|
||||
commit('SET_MENU', menuNames)
|
||||
resolve(menuNames)
|
||||
}).catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
// return new Promise((resolve, reject) => {
|
||||
// getUserMenus().then(response => {
|
||||
// const { data } = response
|
||||
// if (!data) {
|
||||
// reject('Verification failed, please Login again.')
|
||||
// }
|
||||
// const menuNames = collectId(data, names)
|
||||
// commit('SET_MENU', menuNames)
|
||||
// resolve(menuNames)
|
||||
// }).catch(error => {
|
||||
// reject(error)
|
||||
// })
|
||||
// })
|
||||
// },
|
||||
|
||||
setRouteType({ commit }, type) {
|
||||
commit('SET_ROUTESTYPE', type)
|
||||
|
|
|
@ -21,18 +21,18 @@
|
|||
> .el-tabs__header {
|
||||
border-bottom: 1px solid var(--tabsHeaderBorderColor);
|
||||
.el-tabs__item {
|
||||
border-left: 1px solid var(--tabsHeaderBorderColor);
|
||||
border-bottom: none;
|
||||
border-left: none;
|
||||
background: rgba(255,255,255,0.1);
|
||||
margin-right: 0.2rem;
|
||||
&:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
&.is-active {
|
||||
border-bottom-color: var(--tabsHeaderBorderColor);
|
||||
border-bottom: 0.15rem solid #3C9CFF;
|
||||
}
|
||||
}
|
||||
.el-tabs__nav {
|
||||
border: 1px solid var(--tabsHeaderBorderColor);
|
||||
border-bottom: none;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,3 +192,25 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-date-editor .el-range-input {
|
||||
background-color: inherit;
|
||||
}
|
||||
.el-date-range-picker .el-picker-panel__body {
|
||||
background: var(--selectDropdownBgC);
|
||||
}
|
||||
.el-picker-panel__footer {
|
||||
background: var(--selectDropdownBgC);
|
||||
}
|
||||
.el-picker-panel, .el-picker-panel__icon-btn, .el-date-table th{
|
||||
color:white
|
||||
}
|
||||
.el-date-table td.in-range div{
|
||||
background-color: rgba(255,255,255,0.2);
|
||||
}
|
||||
.el-date-editor .el-range-separator{
|
||||
color: white;
|
||||
}
|
||||
.el-date-editor .el-range-input{
|
||||
color: white;
|
||||
}
|
|
@ -477,7 +477,8 @@ span.default {
|
|||
padding-left: 40px;
|
||||
}
|
||||
.el-tabs--card > .el-tabs__header .el-tabs__nav {
|
||||
border-radius: 0.75rem 2px 0 0;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
}
|
||||
.el-tabs__header {
|
||||
margin: 0 0 1.5rem;
|
||||
|
@ -800,16 +801,30 @@ span.default {
|
|||
.el-radio-button__orig-radio:checked + .el-radio-button__inner {
|
||||
background-color: rgba(60, 156, 255, 0.5);
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
}
|
||||
.el-radio-button__inner {
|
||||
.el-checkbox-button.is-checked .el-checkbox-button__inner{
|
||||
background-color: rgba(60, 156, 255, 0.5);
|
||||
// border: none;
|
||||
box-shadow: none;
|
||||
-webkit-box-shadow: none;
|
||||
}
|
||||
.el-radio-button__inner, .el-checkbox-button__inner {
|
||||
background: rgba(255, 255, 255, 0.4);
|
||||
border: none;
|
||||
color: #FFFFFF;
|
||||
padding: 0.75rem 1.25rem;
|
||||
}
|
||||
.el-radio-button:first-child .el-radio-button__inner{
|
||||
.el-checkbox-group{
|
||||
text-align: left;
|
||||
}
|
||||
.el-radio-button:first-child .el-radio-button__inner, .el-checkbox-button:first-child .el-checkbox-button__inner{
|
||||
border: none;
|
||||
}
|
||||
.el-checkbox-button__inner{
|
||||
border-left: 1px solid #dddddd;
|
||||
}
|
||||
.el-radio-button__inner:hover {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
@ -921,3 +936,75 @@ span.default {
|
|||
.el-table--medium th, .el-table--medium td {
|
||||
padding: 0.625rem 0;
|
||||
}
|
||||
|
||||
.el-radio input[aria-hidden="true"] {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
.el-table .operateA{
|
||||
text-decoration: none;
|
||||
color: #1890ff !important;
|
||||
}
|
||||
.el-date-editor .el-range-input{
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.el-date-editor .el-range__icon{
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.el-date-editor .el-range-separator{
|
||||
line-height: 2rem;
|
||||
padding: 0 0.4rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.el-date-editor--datetimerange.el-input, .el-date-editor--datetimerange.el-input__inner{
|
||||
width: 25rem;
|
||||
}
|
||||
.el-date-range-picker{
|
||||
width: 40rem;
|
||||
}
|
||||
.el-date-table{
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
.el-date-range-picker .el-picker-panel__body {
|
||||
min-width: 32rem;
|
||||
}
|
||||
.el-picker-panel__icon-btn{
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.el-date-table td div {
|
||||
height: 1.9rem;
|
||||
padding: 0.2rem 0;
|
||||
}
|
||||
.el-date-table td span {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
line-height: 1.5rem;
|
||||
}
|
||||
.tableInput{
|
||||
width: 50%;
|
||||
border: 1px solid gray;
|
||||
border-collapse: collapse;
|
||||
.el-form-item{
|
||||
margin: 0!important;
|
||||
}
|
||||
td, th{
|
||||
padding: 1em;
|
||||
border-left: 1px solid gray;
|
||||
|
||||
}
|
||||
td:first-child, th:first-child{
|
||||
border-left: 0;
|
||||
}
|
||||
tr{
|
||||
border-top: 1px solid gray;
|
||||
}
|
||||
tr:first-child {
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
.width100{
|
||||
width: 100%!important;
|
||||
}
|
|
@ -9,6 +9,12 @@ export function getToken() {
|
|||
export function setToken(token) {
|
||||
return Cookies.set(TokenKey, token)
|
||||
}
|
||||
export function setBCToken(token) {
|
||||
return Cookies.set('blockChainToken', token)
|
||||
}
|
||||
export function getBCToken() {
|
||||
return Cookies.get('blockChainToken')
|
||||
}
|
||||
|
||||
export function removeToken() {
|
||||
document.cookie.split(';').map(e => e.split('=')[0].trim()).forEach(e => {
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
import axios from 'axios'
|
||||
import {
|
||||
Message } from 'element-ui'
|
||||
import { getBCToken } from '@/utils/auth'
|
||||
// create an axios instance
|
||||
const service = axios.create({
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
baseURL: process.env.NODE_ENV !== 'production' ? '/' : '/', // url = base url + request url
|
||||
withCredentials: true, // send cookies when cross-domain requests
|
||||
timeout: 600000 // request timeout
|
||||
})
|
||||
|
||||
// request interceptor
|
||||
service.interceptors.request.use(
|
||||
config => {
|
||||
// do something before request is sent
|
||||
config.headers['Authorization'] = getBCToken()
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
// do something with request error
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// response interceptor
|
||||
service.interceptors.response.use(
|
||||
/**
|
||||
* If you want to get http information such as headers or status
|
||||
* Please return response => response
|
||||
*/
|
||||
|
||||
/**
|
||||
* Determine the request status by custom code
|
||||
* Here is just an example
|
||||
* You can also judge the status by HTTP Status Code
|
||||
*/
|
||||
response => {
|
||||
const res = response.data
|
||||
// if the custom code is not 20000, it is judged as an error.
|
||||
if (res.code && res.code !== 'OK') {
|
||||
Message({
|
||||
message: res.message || res.msg || 'Error',
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(new Error(res || 'Error'))
|
||||
} else {
|
||||
return res
|
||||
}
|
||||
},
|
||||
error => {
|
||||
Message({
|
||||
message: error?.response?.data?.message || error?.response?.data?.msg || 'Error',
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default service
|
|
@ -21,7 +21,6 @@
|
|||
:pagination="true"
|
||||
page-key="pageNum"
|
||||
limit-key="pageSize"
|
||||
:default-sort="{prop: 'createTime', order: 'ascending'}"
|
||||
tooltip-effect="dark"
|
||||
@total-fetched="getTotalAdapter"
|
||||
>
|
||||
|
|
|
@ -1,46 +1,18 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-card>
|
||||
<Exhibition :data="exhibitionArray" />
|
||||
</el-card>
|
||||
<div class="blockchainBrowser">
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-card class="blockList">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>区块</span>
|
||||
<el-button style="float: right; padding: 0" type="text" @click="toBlockList">更多</el-button>
|
||||
</div>
|
||||
<!-- <List
|
||||
ref="multipleTable"
|
||||
class="multipleTable"
|
||||
:columns="columns1"
|
||||
:table-list-data="blockList"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
-->
|
||||
<div v-for="(item, index) in blockList" :key="index" class="blockListItem">
|
||||
<div class="item">
|
||||
<p>区块{{ item.blocknum }}</p> <div class="txcount">{{ item.txcount }}TXNS</div>
|
||||
<div class="txcount">{{ item.txcount }}TXNS</div>
|
||||
|
||||
<span class="tips">区块哈希:{{ item.blockhash }}</span>
|
||||
<div class="time">{{ new Date(item.createdt).toLocaleString() }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-col :span="15">
|
||||
<el-card>
|
||||
<el-row>
|
||||
<el-col v-for="(item, index) in numList" :key="item+index" class="num" :span="8">
|
||||
<img :src="getImg('icon'+(index+1))" alt="">
|
||||
<div><p> {{ item.title }}</p>{{ item.num }}</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-card style="height:350px" class="blockList">
|
||||
<div class="money">
|
||||
<div>合同交易总金额</div>
|
||||
<p>{{ tradeCount }}</p>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-card style="height:350px">
|
||||
<el-col :span="9">
|
||||
<el-card>
|
||||
<div slot="header" class="clearfix">
|
||||
<span>最近7日交易量</span>
|
||||
</div>
|
||||
|
@ -49,347 +21,384 @@
|
|||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-card class="blockList" style="min-height: 380px">
|
||||
<el-col :span="12">
|
||||
<el-card>
|
||||
<div slot="header" class="clearfix">
|
||||
<span>交易</span>
|
||||
<span>最新区块</span>
|
||||
</div>
|
||||
<div class="block">
|
||||
<el-row v-for="(item,index) in blockList" :key="item.hash + index" :class="(currentBlock && item.number === currentBlock.number)? 'active' : ''">
|
||||
<a @click="changeBlock(item)">
|
||||
<el-col :span="4">
|
||||
<img src="../../assets/images/blockchain/block.png" alt="">
|
||||
</el-col>
|
||||
<el-col :span="14" class="mid">
|
||||
<p>区块{{ item.number }}</p><p class="node">区块哈希:{{ item.hash }}</p>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<p>{{ new Date(item.timestamp).toLocaleString() }}</p>
|
||||
<div class="tag">交易数:{{ item.transactionsNum }}</div>
|
||||
</el-col>
|
||||
</a>
|
||||
</el-row>
|
||||
</div>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
class="multipleTable"
|
||||
:columns="columns2"
|
||||
:pagination="true"
|
||||
tooltip-effect="dark"
|
||||
:get-list-action="$Api.getTradeList"
|
||||
list-key="records"
|
||||
page-key="pageNum"
|
||||
limit-key="pageSize"
|
||||
/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card class="blockList" style="min-height: 380px">
|
||||
<el-col :span="12">
|
||||
<el-card :class="currentBlock === null ? '' : 'arrow-left'">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>评论</span>
|
||||
<span>{{ currentBlock === null ? '最新交易' : '区块'+currentBlock.number+'的交易' }}</span>
|
||||
<el-button v-if="currentBlock!== null" style="float: right; padding: 0;" type="text" @click="getFiveRecord()">返回</el-button>
|
||||
</div>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
class="multipleTable"
|
||||
:columns="columns2"
|
||||
:pagination="true"
|
||||
tooltip-effect="dark"
|
||||
:get-list-action="$Api.getEvaluationList"
|
||||
list-key="records"
|
||||
page-key="pageNum"
|
||||
limit-key="pageSize"
|
||||
/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-card class="blockList" style="min-height: 380px">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>监控</span>
|
||||
<div class="block">
|
||||
<el-row v-for="(item,index) in transactionList" :key="item.txHash + index">
|
||||
<a @click="selectTrans(item.id)">
|
||||
<el-col :span="4">
|
||||
<img src="../../assets/images/blockchain/transaction.png" alt="">
|
||||
</el-col>
|
||||
<el-col :span="20">
|
||||
<p class="text">交易哈希 {{ item.txHash }}</p>
|
||||
<div>
|
||||
<span style="font-size: 0.875rem;">{{ new Date(item.createTime).toLocaleString() }}</span>
|
||||
<span class="tag">调用合约:{{ item.contractName }}</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</a>
|
||||
</el-row>
|
||||
</div>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
class="multipleTable"
|
||||
:columns="columns2"
|
||||
:pagination="true"
|
||||
tooltip-effect="dark"
|
||||
:get-list-action="$Api.getMonitorList"
|
||||
list-key="records"
|
||||
page-key="pageNum"
|
||||
limit-key="pageSize"
|
||||
/>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-dialog :close-on-click-modal="false" width="30%" title="交易详情" class="list-detail" :visible.sync="dialogDetailVisible">
|
||||
<FormData :columns="1" :data="detailData" :data-map="dataMap" />
|
||||
<el-button style="margin-left: 40%;" type="primary" @click="viewCredential(detailData)">查看证书</el-button>
|
||||
</el-dialog>
|
||||
<el-dialog :close-on-click-modal="false" width="40%" title="交易证书" :visible.sync="dialogCertVisible">
|
||||
<div class="certification">
|
||||
<p v-if="certType === 'record'">兹证明:<br>
|
||||
申请人 {{ certificationData.buyerName }} 于 {{ new Date(certificationData.transTime).toLocaleString() }} 通过 {{ certificationData.sellerName }} 平台提交了以下电子数据及信息:
|
||||
</p>
|
||||
<p v-if="certType === 'evaluation'">兹证明:<br>
|
||||
申请人 {{ certificationData.memberName }} 通过 云际计算 平台提交了以下电子数据及信息:
|
||||
</p>
|
||||
<p v-if="certType === 'monitor'">兹证明:<br>
|
||||
记录 {{ new Date(certificationData.date).toLocaleString() }} , 生成服务监控运维数据如下:
|
||||
</p>
|
||||
<FormData v-if="certType === 'record'" :column="1" :data="certificationData" :data-map="certTransactionMap" />
|
||||
<FormData v-if="certType === 'evaluation'" :column="1" :data="certificationData" :data-map="certEvaluationMap" />
|
||||
<FormData v-if="certType === 'monitor'" :column="1" :data="certificationData" :data-map="certMonitorMap" />
|
||||
<el-dialog width="50%" title="交易信息" :visible.sync="blockchainDetail">
|
||||
<div>
|
||||
<FormData
|
||||
:columns="1"
|
||||
:data="transactionData"
|
||||
:data-map="transactionMap"
|
||||
/>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<!-- <el-button @click="selectCert()">查看数据</el-button> -->
|
||||
<el-button type="info" @click="blockchainDetail = false">关闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- <DataList v-model="dialogCertVisible" :transaction-data="transactionData" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FormData } from '@/components/FormData'
|
||||
|
||||
import moment from 'moment'
|
||||
import List from '@/components/list'
|
||||
import Exhibition from '@/components/Exhibition'
|
||||
import viewCertification from '@/mixin/viewCertification'
|
||||
import * as echarts from 'echarts'
|
||||
import { FormData } from '@/components/FormData'
|
||||
import blockChain from '@/mixin/blockChain'
|
||||
// import DataList from './components/dataList'
|
||||
import { getBlockList, getBlockChain, getRecordPage, getRecordDetail, get7dayChart, getTransactions } from '@/api/blockchain/blockchain'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
FormData,
|
||||
Exhibition,
|
||||
List
|
||||
},
|
||||
mixins: [viewCertification],
|
||||
// DataList,
|
||||
FormData },
|
||||
mixins: [blockChain],
|
||||
data() {
|
||||
return {
|
||||
exhibitionArray: [
|
||||
{ name: '交易数量', src: 'blockChainBrowser-1', value: '0' },
|
||||
{ name: '参与交易用户数量', src: 'blockChainBrowser-1', value: '0' },
|
||||
{ name: '当前区块高度', src: 'blockChainBrowser-1', value: '0' },
|
||||
{ name: '排序服务总数', src: 'blockChainBrowser-1', value: '0' },
|
||||
{ name: '节点服务总数', src: 'blockChainBrowser-1', value: '0' }
|
||||
],
|
||||
columns1: [
|
||||
{ prop: 'blocknum', label: '区块高度', formatter: (row) =>
|
||||
<div class='block-name'>
|
||||
<div>区块{row.blocknum}</div>
|
||||
<div class='node-hash'>区块哈希: {row.blockhash}</div>
|
||||
</div>
|
||||
},
|
||||
{ prop: 'txcount', width: '70', label: this.$t('page.status'), formatter: (row) => <div class='txcount'>{row.txcount}TXNS</div> },
|
||||
{ prop: 'createdt', width: '160', label: '创建时间', formatter: (row) => new Date(row.createdt).toLocaleString() }
|
||||
],
|
||||
columns2: [
|
||||
{ prop: 'blocknum', label: '交易ID', formatter: (row) => <div class='hash-name'>
|
||||
<a onClick={() => this.getTradeDetail(row)}>交易ID</a>
|
||||
<span class='tips'>交易哈希: {row.txhash}</span></div> },
|
||||
{ prop: 'createdt', width: '160', label: '创建时间', formatter: (row) => new Date(row.createdt).toLocaleString() }
|
||||
],
|
||||
tradeCount: '0',
|
||||
currentChannel: '',
|
||||
blockList: [],
|
||||
tradeList: [],
|
||||
dialogDetailVisible: false,
|
||||
detailData: {},
|
||||
dataMap: {
|
||||
transId: '交易ID',
|
||||
ledgerName: '数据标题',
|
||||
currentBlock: null,
|
||||
blockchainDetail: false,
|
||||
dialogCertVisible: false,
|
||||
transactionData: {},
|
||||
certificationData: {},
|
||||
transactionMap: {
|
||||
id: '交易ID',
|
||||
typeName: '记录类型',
|
||||
txHash: '交易哈希',
|
||||
createDate: '交易时间',
|
||||
blockHash: '区块哈希',
|
||||
blockNum: '区块高度'
|
||||
createTime: '区块时间',
|
||||
blockNumber: '所在区块',
|
||||
blockHash: '所在区块哈希',
|
||||
from: '交易发送者',
|
||||
number: '积分变动额',
|
||||
contractName: '调用合约',
|
||||
contractAddress: '合约地址'
|
||||
},
|
||||
numList: [
|
||||
{
|
||||
title: '参与交易用户数量',
|
||||
num: 0
|
||||
},
|
||||
{
|
||||
title: '交易总量',
|
||||
num: 0
|
||||
},
|
||||
{
|
||||
title: '存证查询次数',
|
||||
num: 0
|
||||
},
|
||||
{
|
||||
title: '当前区块高度',
|
||||
num: 0
|
||||
},
|
||||
{
|
||||
title: '合约总数',
|
||||
num: 0
|
||||
},
|
||||
{
|
||||
title: '节点服务总数',
|
||||
num: 0
|
||||
}
|
||||
],
|
||||
blockList: [],
|
||||
transactionList: [],
|
||||
lineChartOption: {
|
||||
color: ['#33D1C9'],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: '#000033',
|
||||
textStyle: { fontSize: this.fontSize(1.4), color: '#fff' }
|
||||
},
|
||||
legend: {
|
||||
data: ['交易量'],
|
||||
textStyle: {
|
||||
fontSize: this.fontSize(1.4),
|
||||
color: '#ffffff'
|
||||
},
|
||||
icon: 'roundRect',
|
||||
right: '25%',
|
||||
itemGap: this.fontSize(2),
|
||||
itemWidth: this.fontSize(2.5)
|
||||
},
|
||||
grid: {
|
||||
left: '4%',
|
||||
right: '5%',
|
||||
bottom: '3%',
|
||||
top: '18%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(22, 208, 255, 0.3)'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
formatter: function(value) {
|
||||
const arr = value.split('-')
|
||||
return arr[1] + '/' + arr[2]
|
||||
},
|
||||
textStyle: {
|
||||
color: '#96AAC4',
|
||||
fontSize: this.fontSize(1.4)
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: '#96AAC4',
|
||||
fontSize: this.fontSize(1.4)
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '交易量',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
smooth: true,
|
||||
// lineStyle: {
|
||||
// width: 0
|
||||
// },
|
||||
showSymbol: false,
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tradeListLength() {
|
||||
return this.tradeList.length >= 5 ? 5 : this.tradeList.length
|
||||
watch: {
|
||||
dialogCertVisible(val) {
|
||||
if (val === false) {
|
||||
this.getSearch()
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$Api.getCurrentChannel().then(res => {
|
||||
this.currentChannel = res.currentChannel
|
||||
localStorage.setItem('currentChannel', this.currentChannel)
|
||||
this.getBlockList()
|
||||
|
||||
this.getStatisticsCount()
|
||||
this.getUserCount()
|
||||
this.getTradeCount()
|
||||
this.getChartData()
|
||||
this.$nextTick(() => {
|
||||
this.getSearch()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getChartData() {
|
||||
this.$Api.getTradeMapByDate({ days: 7 }).then(res => {
|
||||
const transCount = res.map(i => i.transCount)
|
||||
const transDate = res.map(i => i.transDate)
|
||||
const chartOption = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
axisLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
data: transDate
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: { lineStyle: { color: '#999999' }}
|
||||
},
|
||||
series: [{
|
||||
data: transCount,
|
||||
symbol: 'none',
|
||||
type: 'line',
|
||||
itemStyle: {
|
||||
color: '#3182CE'
|
||||
},
|
||||
markPoint: {
|
||||
data: [
|
||||
{ type: 'max', name: 'Max' }
|
||||
]
|
||||
},
|
||||
smooth: true
|
||||
}]
|
||||
getSearch() {
|
||||
getBlockList().then(e => {
|
||||
this.blockList = e.data || []
|
||||
})
|
||||
this.getFiveRecord()
|
||||
getBlockChain().then(e => {
|
||||
this.numList[0].num = e.data?.userNum
|
||||
this.numList[1].num = e.data?.recordNum
|
||||
this.numList[2].num = e.data?.recordQueryNum
|
||||
this.numList[3].num = e.data?.blockNum
|
||||
this.numList[4].num = e.data?.contractNum
|
||||
this.numList[5].num = e.data?.peerNum
|
||||
})
|
||||
this.searchRecord()
|
||||
},
|
||||
// 获取最新交易列表
|
||||
getFiveRecord() {
|
||||
this.currentBlock = null
|
||||
getRecordPage({ current: 1, size: 5 }).then(e => {
|
||||
this.transactionList = e.data.records || []
|
||||
})
|
||||
},
|
||||
// 查询区块下的交易
|
||||
changeBlock(item) {
|
||||
this.currentBlock = item
|
||||
getTransactions(item.number).then(e => {
|
||||
this.transactionList = e.data.map(n => ({ ...n, txHash: n.hash, createTime: n.importTime })) || []
|
||||
})
|
||||
},
|
||||
// 查看交易详情
|
||||
selectTrans(id) {
|
||||
getRecordDetail({ id }).then(e => {
|
||||
this.transactionData = { ...e.data, typeName: this.typeNameList.find(n => n.itemValue === e.data.type).itemText }
|
||||
this.blockchainDetail = true
|
||||
})
|
||||
},
|
||||
// // 查看数据弹框
|
||||
// selectCert() {
|
||||
// this.blockchainDetail = false
|
||||
// this.dialogCertVisible = true
|
||||
// },
|
||||
getImg(src) {
|
||||
return require('@/assets/images/blockchain/' + src + '.png')
|
||||
},
|
||||
fontSize(rem) {
|
||||
const scale = window.innerHeight / 100
|
||||
return parseInt(scale * rem)
|
||||
},
|
||||
// 最近7天交易量
|
||||
searchRecord() {
|
||||
const lineChart = echarts.init(this.$refs.lineChart)
|
||||
get7dayChart().then(e => {
|
||||
this.lineChartOption.xAxis.data = e.data.dateList
|
||||
this.lineChartOption.series[0].data = e.data.volumeList
|
||||
// this.lineChartOption.series[1].data = e.data.volumeList
|
||||
const that = this
|
||||
function getSuanli() {
|
||||
lineChart.clear()
|
||||
lineChart.setOption(that.lineChartOption)
|
||||
window.onresize = function() {
|
||||
lineChart.resize()
|
||||
}
|
||||
return getSuanli
|
||||
}
|
||||
const lineChart = echarts.init(this.$refs.lineChart)
|
||||
lineChart.setOption(chartOption)
|
||||
})
|
||||
},
|
||||
getTradeDetail(row) {
|
||||
this.certType = row.chaincodename
|
||||
this.$Api.getTradeDetail(row.txhash).then(res => {
|
||||
this.detailData = res.data
|
||||
this.dialogDetailVisible = true
|
||||
})
|
||||
},
|
||||
getStatisticsCount() {
|
||||
this.$Api.getStatisticsCount(this.currentChannel).then(res => {
|
||||
this.exhibitionArray[0].value = res.txCount
|
||||
this.exhibitionArray[2].value = res.latestBlock
|
||||
this.exhibitionArray[3].value = res.chaincodeCount
|
||||
this.exhibitionArray[4].value = res.peerCount
|
||||
})
|
||||
},
|
||||
getUserCount() {
|
||||
this.$Api.getUserCount().then(res => {
|
||||
this.exhibitionArray[1].value = res.data
|
||||
})
|
||||
},
|
||||
getTradeCount() {
|
||||
this.$Api.getTradeCount().then(res => {
|
||||
this.tradeCount = res.data
|
||||
})
|
||||
},
|
||||
toBlockList() {
|
||||
this.$router.push({ path: `/blockChain/blockList` })
|
||||
},
|
||||
getBlockList() {
|
||||
this.$Api.getBlockList(this.currentChannel, { from: moment().subtract(1, 'months').format('YYYY-MM-DD HH:mm:ss.SSS'), to: moment().add(1, 'days').format('YYYY-MM-DD HH:mm:ss.SSS') }).then(res => {
|
||||
this.blockList = res.rows.splice(0, 4)
|
||||
getSuanli()
|
||||
})
|
||||
}
|
||||
// getTradeList() {
|
||||
// this.$Api.getTradeList('evaluation', { from: moment().subtract(1, 'months').format('YYYY-MM-DD HH:mm:ss.SSS'), to: moment().add(1, 'days').format('YYYY-MM-DD HH:mm:ss.SSS') }).then(res => {
|
||||
// console.log(res.rows)
|
||||
// this.tradeList = res.rows
|
||||
// })
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.txcount{
|
||||
background: #333333;
|
||||
box-shadow: 0px 3px 7px 0px rgba(51, 51, 51, 0.35);
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
color: #FFFFFF;
|
||||
padding: 0 4px;
|
||||
}
|
||||
.blockList{
|
||||
min-height: 200px;
|
||||
.el-card__body {
|
||||
padding-top: 0;
|
||||
}
|
||||
.money{
|
||||
width: 290px;
|
||||
height: 290px;
|
||||
border: 30px solid var(--blockListMoney);
|
||||
background: linear-gradient(90deg, #21B8AF 0%, #3182CE 100%);
|
||||
box-shadow: 0px 10px 26px 5px rgb(52 72 90 / 20%);
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-family: PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #FFFFFF;
|
||||
padding-top: 70px;
|
||||
margin: 0 auto;
|
||||
margin-top: 33px;
|
||||
p{
|
||||
<style lang="scss" scoped>
|
||||
.blockchainBrowser{
|
||||
.num{
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
img{
|
||||
height: 10vh;
|
||||
margin-right: 0.625rem;
|
||||
}
|
||||
>div{
|
||||
font-family: Impact;
|
||||
font-size: 36px;
|
||||
font-size: 1.625rem;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
p{
|
||||
font-size: 0.9rem;
|
||||
color: #9EACBE;
|
||||
}
|
||||
}
|
||||
.block-name{
|
||||
.block{
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
min-height: 46vh;
|
||||
|
||||
}
|
||||
.hash-name{
|
||||
|
||||
}
|
||||
.blockListItem{
|
||||
width: 25%;
|
||||
float: left;
|
||||
// margin: 10px;
|
||||
padding: 10px;
|
||||
.item{
|
||||
border: 1px solid #eeeeee;
|
||||
padding: 5px 10px;
|
||||
padding-top: 15px;
|
||||
position: relative;
|
||||
.el-row{
|
||||
transition: all .3s cubic-bezier(.7, .3, .1, 1);
|
||||
background: rgba(255,255,255,0.1);
|
||||
border-radius: 2px;
|
||||
margin-bottom: 1.5vh;
|
||||
padding: 0 1vh;
|
||||
img{
|
||||
height: 2.6vh;
|
||||
margin: 2.5vh 3vh;
|
||||
}
|
||||
.text{
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.node{
|
||||
font-size: 0.875rem;
|
||||
color: #AAAAAA;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
box-sizing: border-box;
|
||||
.txcount{
|
||||
padding: 5px;
|
||||
margin: 5px;
|
||||
margin-top: 0;
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
top: 8px;
|
||||
// float: right;
|
||||
}
|
||||
p{ margin-top: 0; margin-bottom: 2rem; font-size: 0.8rem;}
|
||||
.time{
|
||||
font-size: 0.8rem;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 40px;
|
||||
}
|
||||
.tips{
|
||||
margin: 20px 0;
|
||||
.active{
|
||||
background-color: #5b7595;
|
||||
transition: all .3s cubic-bezier(.7, .3, .1, 1);
|
||||
}
|
||||
}
|
||||
.node-hash{
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
}
|
||||
cursor: pointer;
|
||||
}
|
||||
.certification{
|
||||
width: 100%;
|
||||
height: 750px;
|
||||
background: url('../../assets/cert_bg.png') white center no-repeat;
|
||||
background-size: auto 100%;
|
||||
text-align: center;
|
||||
padding-top: 130px;
|
||||
p{
|
||||
.tag{
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 0.75rem;
|
||||
font-size: 0.8rem;
|
||||
text-align: left;
|
||||
width: 410px;
|
||||
margin: auto;
|
||||
padding: 10px 15px;
|
||||
margin: 0 0.5rem;
|
||||
padding: 0.5vh 0.7vh;
|
||||
float: right;
|
||||
}
|
||||
table.table.formData {
|
||||
width: 410px;
|
||||
margin: 0 auto;
|
||||
font-size: 0.5rem;
|
||||
td {
|
||||
line-height: 0.9rem;
|
||||
text-align: left;
|
||||
}
|
||||
td:nth-child(odd) {
|
||||
width: 40%;
|
||||
}
|
||||
#lineChart{
|
||||
width: 100%;
|
||||
height: 16vh;
|
||||
}
|
||||
}
|
||||
#lineChart{
|
||||
width: 100%;
|
||||
height: 30vh;
|
||||
.arrow-left{
|
||||
transition: all .3s cubic-bezier(.7, .3, .1, 1);
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
&::before {
|
||||
content: '';
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 1rem solid transparent;
|
||||
border-right: 1rem solid rgba(126,165,202,0.1);
|
||||
border-bottom: 1rem solid transparent;
|
||||
// border-radius: 50%;
|
||||
position: absolute;
|
||||
left: -1rem;
|
||||
top: 5rem;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-card>
|
||||
<h4>上链数据真实性与完整性查验</h4>
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick">
|
||||
<el-tab-pane label="证书查验" name="1" />
|
||||
<el-tab-pane label="身份查验" name="2" />
|
||||
</el-tabs>
|
||||
<el-input v-model="content" :placeholder="`${activeName === '1' ? '请输入您想要校验的内容' : '请输入身份指纹'}`">
|
||||
<el-button slot="append" icon="el-icon-search" type="primary" @click="search">校验查询</el-button>
|
||||
</el-input>
|
||||
<List
|
||||
v-if="listData.length>=1"
|
||||
ref="multipleTable"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="listData"
|
||||
:pagination="false"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
</el-card>
|
||||
<el-dialog :close-on-click-modal="false" width="40%" title="交易证书" :visible.sync="dialogCertVisible">
|
||||
<div class="certification">
|
||||
<p>兹证明:<br>
|
||||
申请人 {{ certificationData.buyerName }} 于 {{ new Date(certificationData.transTime).toLocaleString() }} 通过 {{ certificationData.sellerName }} 平台提交了以下电子数据及信息:
|
||||
</p>
|
||||
<FormData :column="1" :data="certificationData" :data-map="certDataMap" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list.vue'
|
||||
import viewCertification from '@/mixin/viewCertification'
|
||||
import { FormData } from '@/components/FormData'
|
||||
|
||||
export default {
|
||||
components: { List, FormData },
|
||||
mixins: [viewCertification],
|
||||
data() {
|
||||
return {
|
||||
activeName: '1',
|
||||
columns: [
|
||||
{ prop: 'certNum', label: '证书编号' },
|
||||
{ prop: 'fingerPrint', label: '身份指纹' },
|
||||
{ prop: 'createDate', label: '创建时间', formatter: (row) => {
|
||||
return <div>{new Date(row.createDate).toLocaleString() || '-'}</div>
|
||||
} },
|
||||
{ prop: 'more', label: '操作', formatter: (row) => {
|
||||
return <div>
|
||||
<el-button onClick={() => this.viewCredential(row)} type='text' size='small'>查看</el-button>
|
||||
</div>
|
||||
} }
|
||||
],
|
||||
listData: [],
|
||||
content: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.currentChannel = localStorage.getItem('currentChannel')
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
this.content = ''
|
||||
this.listData = []
|
||||
},
|
||||
search() {
|
||||
this.$Api.getCertificationByType(this.activeName === '1' ? { certId: this.content } : { fingerPrint: this.content }, this.activeName === '1' ? 'getCertById' : 'getCertByFP').then(res => {
|
||||
this.listData = res
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.certification{
|
||||
width: 100%;
|
||||
height: 750px;
|
||||
background: url('../../assets/cert_bg.png') white center no-repeat;
|
||||
background-size: auto 100%;
|
||||
text-align: center;
|
||||
padding-top: 120px;
|
||||
p{
|
||||
font-size: 0.8rem;
|
||||
text-align: left;
|
||||
width: 370px;
|
||||
margin: auto;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
table.table.formData {
|
||||
width: 370px;
|
||||
margin: 0 auto;
|
||||
font-size: 0.5rem;
|
||||
td {
|
||||
line-height: 0.9rem;
|
||||
text-align: left;
|
||||
}
|
||||
td:nth-child(odd) {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,56 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-card class="list-detail">
|
||||
<el-page-header content="区块列表(最近一个月的数据)" @back="goBack" />
|
||||
<List
|
||||
v-if="listData.length>=1"
|
||||
ref="multipleTable"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="listData"
|
||||
:pagination="false"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list.vue'
|
||||
import moment from 'moment'
|
||||
|
||||
export default {
|
||||
components: { List },
|
||||
data() {
|
||||
return {
|
||||
filterMap: {
|
||||
},
|
||||
columns: [
|
||||
{ prop: 'blocknum', label: '区块高度' },
|
||||
{ prop: 'blockhash', label: '区块哈希' },
|
||||
{ prop: 'createdt', label: '创建时间', formatter: (row) => new Date(row.createdt).toLocaleString() }
|
||||
],
|
||||
listData: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.currentChannel = localStorage.getItem('currentChannel')
|
||||
this.getBlockList()
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$router.go(-1)
|
||||
},
|
||||
getBlockList() {
|
||||
this.$Api.getBlockList(this.currentChannel, { from: moment().subtract(1, 'months').format('YYYY-MM-DD HH:mm:ss.SSS'), to: moment().add(1, 'days').format('YYYY-MM-DD HH:mm:ss.SSS') }).then(res => {
|
||||
this.listData = res.rows
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,353 @@
|
|||
<template>
|
||||
<el-card class="blockChainLog">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>上链数据真实性与完整性查验</span>
|
||||
</div>
|
||||
<el-tabs v-model="activeName" type="card" @tab-click="switchTab">
|
||||
<el-tab-pane>
|
||||
<span slot="label">交易数据查验</span>
|
||||
<el-form v-if="activeName==='0'" ref="dataForm" :model="dataForm" :rules="dataFormRules" label-width="auto">
|
||||
<el-row>
|
||||
<el-col :span="16">
|
||||
<el-form-item prop="nodesName" label="校验节点选择">
|
||||
<el-select v-model="dataForm.nodesName" multiple style="width: 90%">
|
||||
<el-option
|
||||
v-for="(item, index) in nodeList"
|
||||
:key="item+ index"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-form-item prop="id" label="交易日志编号">
|
||||
<el-input v-model="dataForm.id" placeholder="请输入交易日志编号" style="width: 90%" @enter="onSearchClick('searchId')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<el-form-item>
|
||||
<el-button size="medium" type="info" @click="onSearchClick('searchId')">{{ $t('message.search') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<img v-if="activeName ==='0' && certificateList.length === 0" class="emptyImg" src="../../assets/images/blockchain/blockList.png" alt="">
|
||||
<List
|
||||
v-if="activeName==='0'"
|
||||
ref="multipleTable0"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns0"
|
||||
:height="height"
|
||||
:table-list-data="certificateList"
|
||||
:pagination="false"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane>
|
||||
<span slot="label">交易身份查验</span>
|
||||
<el-form v-if="activeName==='1'" ref="identityForm" :model="identityForm" :rules="identityFormRules" label-width="auto">
|
||||
<el-row>
|
||||
<el-col :span="16">
|
||||
<el-form-item prop="nodesName" label="单校验节点选择">
|
||||
<el-select v-model="identityForm.nodesName" style="width: 90%">
|
||||
<el-option
|
||||
v-for="(item, index) in nodeList"
|
||||
:key="item+ index"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-form-item prop="accountAddress" label="提交人身份地址">
|
||||
<el-input v-model="identityForm.accountAddress" placeholder="请输入提交人身份地址" style="width: 90%" @enter="onSearchClick('searchId')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item>
|
||||
<el-button size="medium" type="info" @click="onSearchClick('accountAddress')">{{ $t('message.search') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<img v-if="activeName==='1' && identityList.length === 0" class="emptyImg" src="../../assets/images/blockchain/blockList.png" alt="">
|
||||
<List
|
||||
v-if="activeName==='1'"
|
||||
ref="multipleTable1"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns1"
|
||||
:height="height"
|
||||
:table-list-data="identityList"
|
||||
:pagination="false"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane>
|
||||
<span slot="label">智能合约查验</span>
|
||||
<el-form v-if="activeName==='2'" ref="contractForm" :model="contractForm" :rules="contractFormRules" label-width="auto">
|
||||
<el-row>
|
||||
<el-col :span="16">
|
||||
<el-form-item prop="nodesName" label="校验节点选择">
|
||||
<el-select v-model="contractForm.nodesName" multiple style="width: 90%">
|
||||
<el-option
|
||||
v-for="(item, index) in nodeList"
|
||||
:key="item+ index"
|
||||
:label="item"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-form-item prop="name" label="合约名称">
|
||||
<el-input v-model="contractForm.name" style="width: 90%" placeholder="请输入合约名称" @enter="onSearchClick('searchId')" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item>
|
||||
<el-button size="medium" type="info" @click="onSearchClick('contract')">{{ $t('message.search') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<img v-if=" activeName==='2' && contractList.length === 0" class="emptyImg" src="../../assets/images/blockchain/blockList.png" alt="">
|
||||
<List
|
||||
v-if="activeName==='2'"
|
||||
ref="multipleTable2"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns2"
|
||||
:height="height"
|
||||
:table-list-data="contractList"
|
||||
:pagination="false"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<DataList v-model="dialogCertVisible" :transaction-data="transactionData" />
|
||||
</el-card>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import DataList from './components/dataList'
|
||||
import blockChain from '@/mixin/blockChain'
|
||||
import { getRecordPage, getContractList } from '@/api/blockchain/blockchain'
|
||||
export default {
|
||||
components: { List, DataList },
|
||||
mixins: [blockChain],
|
||||
data() {
|
||||
return {
|
||||
activeName: '0',
|
||||
height: Math.round(document.body.offsetHeight * 0.45).toString(),
|
||||
certificateList: [],
|
||||
identityList: [],
|
||||
contractList: [],
|
||||
dialogCertVisible: false,
|
||||
certificationData: {},
|
||||
transactionData: {},
|
||||
searchId: '',
|
||||
accountAddress: '',
|
||||
contractType: [{ itemText: '存证合约', itemValue: '0' }, { itemValue: '1', itemText: '积分合约' }], // 合约类型
|
||||
dataForm: {
|
||||
nodesName: '',
|
||||
id: '1872209074928050178'
|
||||
},
|
||||
identityForm: {
|
||||
nodesName: '',
|
||||
accountAddress: '0x74d6307a016c7ed2ee8733cb07dfc4533c46c5ab'
|
||||
},
|
||||
contractForm: {
|
||||
nodesName: '',
|
||||
name: 'EvidenceStorage' // LoyaltyPoints
|
||||
},
|
||||
dataFormRules: {
|
||||
nodesName: [{ required: true, message: '请选择节点', trigger: 'select' }],
|
||||
id: [{ required: true, message: '请输入交易日志编号', trigger: 'blur' }]
|
||||
},
|
||||
identityFormRules: {
|
||||
nodesName: [{ required: true, message: '请选择节点', trigger: 'select' }],
|
||||
accountAddress: [{ required: true, message: '请输入提交人身份地址', trigger: 'blur' }]
|
||||
},
|
||||
contractFormRules: {
|
||||
nodesName: [{ required: true, message: '请选择节点', trigger: 'select' }],
|
||||
name: [{ required: true, message: '请输入合约名称', trigger: 'blur' }]
|
||||
},
|
||||
columns0: [
|
||||
{ prop: 'id', label: '交易日志编号' },
|
||||
{ prop: 'type', label: '记录类型', formatter: (row) => {
|
||||
return this.typeNameList.find(n => n.itemValue === row.type).itemText
|
||||
} },
|
||||
{ prop: 'accountAddress', label: '提交人身份名称' },
|
||||
{ prop: 'createTime', label: '提交时间', sortable: true, formatter: (row) => {
|
||||
return <div>{new Date(row.createTime).toLocaleString()}</div>
|
||||
} },
|
||||
{ prop: 'consistent', label: '节点对比结果', formatter: (row) => {
|
||||
if (row.consistent) {
|
||||
return <div><svg-icon icon-class='yizhixing' style='color: #2897FF;margin: 0.2rem' />一致</div>
|
||||
} else {
|
||||
return <div><svg-icon icon-class='mimabuyizhi' style='color: #D66C6C;margin: 0.2rem'/>不一致</div>
|
||||
}
|
||||
} },
|
||||
{ prop: 'more', label: '操作', width: 160, formatter: (row) => {
|
||||
return <div>
|
||||
<el-dropdown>
|
||||
<el-button className='el-dropdown-link' size='mini' icon='el-icon-more' circle>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => { this.selectCert(row) }}> <el-dropdown-item> {'查看数据'} </el-dropdown-item> </span>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
} }
|
||||
],
|
||||
columns1: [
|
||||
{ prop: 'id', label: '记录日志编号' },
|
||||
{ prop: 'type', label: '记录类型', formatter: (row) => {
|
||||
return this.typeNameList.find(n => n.itemValue === row.type).itemText
|
||||
} },
|
||||
{ prop: 'accountAddress', label: '提交人身份名称' },
|
||||
{ prop: 'createTime', label: '提交时间', sortable: true, formatter: (row) => {
|
||||
return <div>{new Date(row.createTime).toLocaleString()}</div>
|
||||
} },
|
||||
{ prop: 'more', label: '操作', width: 160, formatter: (row) => {
|
||||
return <div>
|
||||
<el-dropdown>
|
||||
<el-button className='el-dropdown-link' size='mini' icon='el-icon-more' circle>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => { this.selectCert(row) }}> <el-dropdown-item> {'查看数据'} </el-dropdown-item> </span>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
} }
|
||||
],
|
||||
columns2: [
|
||||
{ prop: 'id', label: '合约ID' },
|
||||
{ prop: 'name', label: '合约名称' },
|
||||
{ prop: 'type', label: '合约类型', formatter: (row) => {
|
||||
return this.contractType.find(n => n.itemValue === row.type).itemText
|
||||
} },
|
||||
{ prop: 'address', label: '合约地址' },
|
||||
{ prop: 'consistent', label: '节点对比结果', formatter: (row) => {
|
||||
if (row.consistent) {
|
||||
return <div><svg-icon icon-class='yizhixing' style='color: #2897FF;margin: 0.2rem' />一致</div>
|
||||
} else {
|
||||
return <div><svg-icon icon-class='mimabuyizhi' style='color: #D66C6C;margin: 0.2rem'/>不一致</div>
|
||||
}
|
||||
} },
|
||||
{ prop: 'createTime', label: '提交时间', sortable: true, formatter: (row) => {
|
||||
return <div>{new Date(row.createTime).toLocaleString()}</div>
|
||||
} }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.onSearchClick()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
resetSearch() {
|
||||
this.searchForm = {
|
||||
nodesName: '',
|
||||
id: ''
|
||||
}
|
||||
},
|
||||
selectCert(row) {
|
||||
this.transactionData = row
|
||||
this.dialogCertVisible = true
|
||||
},
|
||||
onSearchClick(type) {
|
||||
if (type === 'searchId') {
|
||||
this.$refs.dataForm.validate((valid) => {
|
||||
if (valid) {
|
||||
console.log(this.dataForm)
|
||||
getRecordPage({ ...this.dataForm, nodesName: this.dataForm.nodesName.join(', '), current: 1, size: 99999 }).then(e => {
|
||||
this.certificateList = e.data.records
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
} else if (type === 'accountAddress') {
|
||||
this.$refs.identityForm.validate((valid) => {
|
||||
if (valid) {
|
||||
getRecordPage({ ...this.identityForm }).then(e => {
|
||||
this.identityList = e.data.records
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
} else if (type === 'contract') {
|
||||
this.$refs.contractForm.validate((valid) => {
|
||||
if (valid) {
|
||||
getContractList({ ...this.contractForm, nodesName: this.contractForm.nodesName.join(', ') }).then(e => {
|
||||
this.contractList = e.data
|
||||
})
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
switchTab() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.blockChainLog{
|
||||
.el-tab-pane{
|
||||
text-align: center;
|
||||
}
|
||||
.search{
|
||||
.el-button{
|
||||
padding: 1.15rem 2.5rem !important;
|
||||
margin-left: 2vh;
|
||||
}
|
||||
.el-input{
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
.emptyImg{
|
||||
height: 30vh;
|
||||
margin: 4vh 0 16vh 0;
|
||||
}
|
||||
.certification {
|
||||
width: 100%;
|
||||
height: 72vh;
|
||||
background: url('../../assets/images/blockchain/certificate.png') center no-repeat;
|
||||
background-size: auto 100%;
|
||||
text-align: center;
|
||||
padding-top: 120px;
|
||||
p {
|
||||
font-size: 0.8rem;
|
||||
text-align: left;
|
||||
width: 370px;
|
||||
margin: auto;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
table.table.formData {
|
||||
width: 370px;
|
||||
margin: 0 auto;
|
||||
font-size: 0.5rem;
|
||||
td {
|
||||
line-height: 0.9rem;
|
||||
text-align: left;
|
||||
}
|
||||
td:nth-child(odd) {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,97 @@
|
|||
<template>
|
||||
<div class="podInfo">
|
||||
<el-card class="basicInfo">
|
||||
<h4>数据可信核验</h4>
|
||||
<!-- <span class="tips title-tips">数据可信核验</span> -->
|
||||
</el-card>
|
||||
<el-card>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:filter-map="filterMap"
|
||||
list-key="records"
|
||||
:get-list-action="getBusinessLog"
|
||||
:default-sort="{prop: 'createTime', order: 'descending'}"
|
||||
:pagination="true"
|
||||
page-key="current"
|
||||
limit-key="size"
|
||||
/>
|
||||
</el-card>
|
||||
<DataList v-model="dialogCertVisible" :transaction-data="transactionData" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import { getBusinessLog } from '@/api/blockchain/blockchain'
|
||||
import blockChain from '@/mixin/blockChain'
|
||||
import DataList from './components/dataList'
|
||||
export default {
|
||||
components: { List, DataList },
|
||||
mixins: [blockChain],
|
||||
data() {
|
||||
return {
|
||||
getBusinessLog,
|
||||
dialogCertVisible: false,
|
||||
transactionData: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filterMap() {
|
||||
return {
|
||||
type: {
|
||||
label: '业务日志类型',
|
||||
type: 'select',
|
||||
dataSource: this.typeNameList?.filter(n => !['0', '1'].includes(n.itemValue)).map(n => ({
|
||||
label: n.itemText,
|
||||
value: n.itemValue
|
||||
}))
|
||||
},
|
||||
time: {
|
||||
label: '操作时间过滤',
|
||||
type: 'datetimerange'
|
||||
},
|
||||
userIp: {
|
||||
label: '提交人IP过滤'
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
columns() {
|
||||
return this.setColumn()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectCert(row) {
|
||||
this.transactionData = { ...row, logType: row.type }
|
||||
this.dialogCertVisible = true
|
||||
},
|
||||
setColumn() {
|
||||
return [
|
||||
{ prop: 'username', label: '提交人', minWidth: '8%' },
|
||||
{ prop: 'type', label: '业务日志类型', minWidth: '10%', formatter: (row) => {
|
||||
return <div>{this.typeNameList.find(n => n.itemValue === row.type)?.itemText }</div>
|
||||
} },
|
||||
{
|
||||
prop: 'content', label: '日志信息', minWidth: '42%'
|
||||
},
|
||||
{ prop: 'createTime', label: '发生时间', minWidth: '20%', sortable: true, formatter: (row) => {
|
||||
return <div>{row.createTime && new Date(row.createTime).toLocaleString() || '-'}</div>
|
||||
} },
|
||||
{ prop: 'userIp', label: '提交人IP', minWidth: '12%' },
|
||||
{ prop: 'more', label: '操作', minWidth: '8%', formatter: (row) => {
|
||||
return <div>
|
||||
<a class='operateA' onClick={() => this.selectCert(row)}> 查询合约 </a>
|
||||
</div>
|
||||
} }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
|
@ -0,0 +1,109 @@
|
|||
<template>
|
||||
<el-dialog v-if="dialogCertVisible" :close-on-click-modal="false" width="40%" title="交易证书" :visible.sync="dialogCertVisible">
|
||||
<div class="certification">
|
||||
<p>
|
||||
兹证明:<br>
|
||||
申请人 {{ certificationData.accountAddress }} 于
|
||||
{{ new Date(certificationData.createTime).toLocaleString() }} 通过
|
||||
云际计算 平台提交了以下电子数据及信息:
|
||||
</p>
|
||||
<FormData
|
||||
:columns="1"
|
||||
:data="certificationData.type === '2' ? certificationData.taskDTO : certificationData.fileDTO "
|
||||
:data-map="certificationData.type === '2' ? taskDataMap : fileDataMap"
|
||||
/>
|
||||
<p> 申请人提交的源数据自申请保全之时(授时时间 {{ certificationData.createTime }}已经存在,且保全之后一直数据完整、未被篡改,经中国科学院国家授时中心可信时间服务授时,优版权进行电子数据保全,信息上链公示至版权联盟链,并由马栏山版权服务中心颁发保全证书,任何团体及个人均可通过上述机构核验。
|
||||
</p>
|
||||
<div class="bottom">
|
||||
<div>核验单位:</div>
|
||||
<div>中国科学院国家授时中心</div>
|
||||
<div>版权联盟链</div>
|
||||
<div>优版权</div>
|
||||
<div>马栏山版权服务中心</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FormData } from '@/components/FormData'
|
||||
export default {
|
||||
components: { FormData },
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
certificationData: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
taskDataMap: {
|
||||
id: '任务id',
|
||||
name: '任务名称',
|
||||
status: '任务状态',
|
||||
commitTime: '提交时间'
|
||||
},
|
||||
fileDataMap: {
|
||||
type: '类型',
|
||||
fileNo: '文件编号',
|
||||
fileName: '文件名',
|
||||
fileHash: '文件Hash',
|
||||
createTime: '提交时间'
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dialogCertVisible: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.certification {
|
||||
width: 100%;
|
||||
height: 72vh;
|
||||
background: url('../../../assets/images/blockchain/certificate.png') center no-repeat;
|
||||
background-size: auto 100%;
|
||||
text-align: left;
|
||||
padding-top: 12vh;
|
||||
color: black;
|
||||
::v-deep table td{
|
||||
color: black;
|
||||
}
|
||||
p {
|
||||
font-size: 1rem;
|
||||
text-align: left;
|
||||
width: 40vh;
|
||||
margin: auto;
|
||||
padding: 0.9rem 1rem;
|
||||
}
|
||||
.bottom{
|
||||
width: 40vh;
|
||||
margin: auto;
|
||||
}
|
||||
table.table.formData {
|
||||
width: 40vh;
|
||||
margin: 0 auto;
|
||||
font-size: 1rem;
|
||||
td {
|
||||
line-height: 0.9rem;
|
||||
text-align: left;
|
||||
}
|
||||
td:nth-child(odd) {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,237 @@
|
|||
<template>
|
||||
<el-dialog v-if="dialogCertVisible" :close-on-click-modal="false" width="50%" title="交易数据" :visible.sync="dialogCertVisible">
|
||||
<div>
|
||||
<el-tabs v-model="eventTab" type="card" @tab-click="getData">
|
||||
<el-tab-pane v-for="(item,index) in nodeList" :key="item+index" :label="item" :name="item" />
|
||||
</el-tabs>
|
||||
<FormData
|
||||
v-if="JSON.stringify(certificationData) !== '{}'"
|
||||
:columns="1"
|
||||
:data="['2','3','4'].includes(transactionData.logType) ? certificationData : (['5','6','7'].includes(transactionData.logType) ? certificationData.fileDTO : certificationData.taskDTO)"
|
||||
:data-map="dataMap[transactionData.logType]"
|
||||
/>
|
||||
<!-- 2、3、4积分相关 5、6、7文件相关 8、9任务相关 -->
|
||||
<div v-else>暂无数据</div>
|
||||
<h3>积分交易:</h3>
|
||||
<table class="tableInput width100">
|
||||
<tr>
|
||||
<th />
|
||||
<th> 用户 </th>
|
||||
<th> 积分变动情况 </th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>积分消费方</td>
|
||||
<td>{{ jifenData && jifenData.relatedAddress || '-' }}</td>
|
||||
<td>{{ jifenData && jifenData.consume || '-' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>积分获得方</td>
|
||||
<td>{{ jifenData && jifenData.accountAddress || '-' }}</td>
|
||||
<td>{{ jifenData && jifenData.obtained || '-' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>平台抽成</td>
|
||||
<td>{{ jifenData && jifenData.platformAddress || '-' }}</td>
|
||||
<td>{{ jifenData && jifenData.platformCommissionAmount|| '-' }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FormData } from '@/components/FormData'
|
||||
import blockChain from '@/mixin/blockChain'
|
||||
import { getRecordQuery } from '@/api/blockchain/blockchain'
|
||||
import { getPointByHash } from '@/api/blockchain/pointManagement'
|
||||
export default {
|
||||
components: { FormData },
|
||||
mixins: [blockChain],
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
transactionData: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
jifenData: {},
|
||||
eventTab: 'node1',
|
||||
jifenMap: {
|
||||
relatedAddress: '积分消费方ID',
|
||||
consume: '消费积分',
|
||||
accountAddress: '积分获得方ID',
|
||||
number: '获得积分',
|
||||
platformCommissionAmount: '平台抽成'
|
||||
},
|
||||
certificationData: {},
|
||||
dataMap: [
|
||||
{
|
||||
id: '合约部署人ID',
|
||||
type: '部署类型',
|
||||
hash: '部署哈希',
|
||||
time: '部署时间'
|
||||
}, // 合约部署0
|
||||
{
|
||||
id: '合约查询人ID',
|
||||
time: '查询时间',
|
||||
hash: '所查合约哈希'
|
||||
}, // 合约查询 1
|
||||
{
|
||||
typeName: '积分变动类型',
|
||||
accountAddress: '注册人地址',
|
||||
createTime: '注册时间'
|
||||
}, // 账户注册2
|
||||
{
|
||||
typeName: '积分变动类型',
|
||||
id: '初始化账户ID',
|
||||
time: '初始化时间'
|
||||
}, // 账户积分初始化3
|
||||
{
|
||||
typeName: '积分变动类型',
|
||||
fromAddress: '积分消费方ID',
|
||||
consume: '消费积分',
|
||||
accountAddress: '积分获得方ID',
|
||||
number: '获得积分',
|
||||
tax: '平台抽成',
|
||||
createTime: '交易时间'
|
||||
}, // 积分转账4
|
||||
{
|
||||
type: '类型:',
|
||||
userID: '用户id:',
|
||||
fileNo: '文件编号:',
|
||||
fileName: '文件名:',
|
||||
fileHash: '文件哈希:',
|
||||
fileSize: '文件大小:',
|
||||
objectID: '对象id:',
|
||||
createTime: '创建时间:'
|
||||
}, // 数据上传5
|
||||
{
|
||||
userID: '用户id',
|
||||
fileHash: '文件哈希:',
|
||||
objectID: '对象id:',
|
||||
targetCluster: '目标集群',
|
||||
createTime: '提交时间:',
|
||||
integral: '积分交易:'
|
||||
}, // 数据调度6
|
||||
{
|
||||
id: '访问者ID',
|
||||
md5: '被访问数据MD5',
|
||||
userid: '被访问数据ID',
|
||||
time: '访问时间'
|
||||
}, // 数据访问7
|
||||
{
|
||||
id: '任务id',
|
||||
name: '任务名称',
|
||||
description: '任务描述',
|
||||
status: '状态',
|
||||
commitTime: '提交时间'
|
||||
}, // 任务创建8
|
||||
{
|
||||
id: '任务id',
|
||||
name: '任务名称',
|
||||
description: '任务描述',
|
||||
status: '状态',
|
||||
commitTime: '提交时间',
|
||||
startTime: '开始时间',
|
||||
endTime: '结束时间',
|
||||
runningTime: '运行时间',
|
||||
result: '结果'
|
||||
}// 任务结束9
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dialogCertVisible: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
if (val === true) {
|
||||
this.getData()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
tabSwitch() {
|
||||
|
||||
},
|
||||
getData() {
|
||||
if (['2', '3', '4'].includes(this.transactionData.logType)) {
|
||||
// 积分变动接口
|
||||
getPointByHash({
|
||||
txHash: this.transactionData.txHash,
|
||||
nodeName: this.eventTab
|
||||
}).then(e => {
|
||||
this.certificationData = e.data || {}
|
||||
this.jifenData = this.transactionData.logType === '2' ? this.certificationData : this.certificationData.pointsRecordDTO
|
||||
if (e.data) {
|
||||
this.certificationData.typeName = this.pointsList.find(item => item.itemValue === e.data.type).itemText
|
||||
} else {
|
||||
this.certificationData = {}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
getRecordQuery({
|
||||
txHash: this.transactionData.txHash,
|
||||
nodeName: this.eventTab
|
||||
}).then(e => {
|
||||
this.certificationData = e.data || {}
|
||||
this.jifenData = this.certificationData.pointsRecordDTO
|
||||
if (e.data) {
|
||||
this.certificationData.logType = this.transactionData.logType
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped >
|
||||
.certification {
|
||||
width: 100%;
|
||||
height: 72vh;
|
||||
background: url('../../../assets/images/blockchain/certificate.png') center no-repeat;
|
||||
background-size: auto 100%;
|
||||
text-align: left;
|
||||
padding-top: 12vh;
|
||||
color: black;
|
||||
::v-deep table td{
|
||||
color: black;
|
||||
}
|
||||
p {
|
||||
font-size: 1rem;
|
||||
text-align: left;
|
||||
width: 40vh;
|
||||
margin: auto;
|
||||
padding: 0.9rem 1rem;
|
||||
}
|
||||
.bottom{
|
||||
width: 40vh;
|
||||
margin: auto;
|
||||
}
|
||||
table.table.formData {
|
||||
width: 40vh;
|
||||
margin: 0 auto;
|
||||
font-size: 1rem;
|
||||
td {
|
||||
line-height: 0.9rem;
|
||||
text-align: left;
|
||||
}
|
||||
td:nth-child(odd) {
|
||||
width: 40%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,288 @@
|
|||
<template>
|
||||
<div class="blockchainBrowser">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-card style="position: relative;">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>积分管理</span>
|
||||
</div>
|
||||
<el-dropdown class="node-select" @command="handleCommand">
|
||||
<el-button type="primary">
|
||||
节点选择<i class="el-icon-arrow-down el-icon--right" />
|
||||
</el-button>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item v-for="item in nodeList" :key="item" :command="item">{{ item }}</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<el-row style="margin: 3vh 0 3vh 0;">
|
||||
<el-col class="num" :span="12">
|
||||
<img src="@/assets/images/blockchain/icon1.png" alt="">
|
||||
<div><p> 当前用户ID</p><div class="impact">{{ id }}</div></div>
|
||||
</el-col>
|
||||
<el-col class="num" :span="12">
|
||||
<img src="@/assets/images/blockchain/icon2.png" alt="">
|
||||
<div><p> 当前用户可用积分</p><div class="impact">{{ jifen }}</div> <div class="node"><span />{{ currentBlock }}</div></div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card>
|
||||
<div slot="header" class="clearfix">
|
||||
<span>最近7日积分变动情况</span>
|
||||
</div>
|
||||
<div id="lineChart" ref="lineChart" />
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-card>
|
||||
<el-row>
|
||||
<List
|
||||
ref="multipleTable2"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns2"
|
||||
:get-list-action="getRecordList"
|
||||
page-key="current"
|
||||
limit-key="size"
|
||||
list-key="records"
|
||||
:pagination="true"
|
||||
/>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-row>
|
||||
<DataList v-model="dialogCertVisible" :transaction-data="transactionData" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import * as echarts from 'echarts'
|
||||
import List from '@/components/list'
|
||||
import blockChain from '@/mixin/blockChain'
|
||||
import DataList from './components/dataList'
|
||||
import { get7dayChart, getBalance, getRecordList } from '@/api/blockchain/pointManagement'
|
||||
|
||||
export default {
|
||||
components: { DataList, List },
|
||||
mixins: [blockChain],
|
||||
data() {
|
||||
return {
|
||||
currentBlock: null,
|
||||
blockchainDetail: false,
|
||||
dialogCertVisible: false,
|
||||
transactionData: {},
|
||||
jifen: 0,
|
||||
getRecordList,
|
||||
columns2: [
|
||||
// { prop: 'id', label: '序号' },
|
||||
{ prop: 'type', label: '积分变动类型', formatter: (row) => {
|
||||
return this.pointsList.find(item => item.itemValue === row.type)?.itemText
|
||||
} },
|
||||
{ prop: 'oldData', label: '原积分' },
|
||||
{ prop: 'variationValue', label: '变化数值' },
|
||||
{ prop: 'currentData', label: '最终积分' },
|
||||
{ prop: 'more', label: '操作', width: 160, formatter: (row) => {
|
||||
return <div>
|
||||
<el-button type='text' onClick={() => this.selectCert(row)}> 查询合约 </el-button>
|
||||
</div>
|
||||
} }
|
||||
],
|
||||
lineChartOption: {
|
||||
color: ['#33D1C9'],
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
backgroundColor: '#000033',
|
||||
textStyle: { fontSize: this.fontSize(1.4), color: '#fff' }
|
||||
},
|
||||
legend: {
|
||||
data: ['积分变动量'],
|
||||
textStyle: {
|
||||
fontSize: this.fontSize(1.4),
|
||||
color: '#ffffff'
|
||||
},
|
||||
icon: 'roundRect',
|
||||
right: '25%',
|
||||
itemGap: this.fontSize(2),
|
||||
itemWidth: this.fontSize(2.5)
|
||||
},
|
||||
grid: {
|
||||
left: '4%',
|
||||
right: '5%',
|
||||
bottom: '3%',
|
||||
top: '18%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: 'rgba(22, 208, 255, 0.3)'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
formatter: function(value) {
|
||||
const arr = value.split('-')
|
||||
return arr[1] + '/' + arr[2]
|
||||
},
|
||||
textStyle: {
|
||||
color: '#96AAC4',
|
||||
fontSize: this.fontSize(1.4)
|
||||
}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: '#96AAC4',
|
||||
fontSize: this.fontSize(1.4)
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '积分变动量',
|
||||
type: 'line',
|
||||
stack: 'Total',
|
||||
smooth: true,
|
||||
// lineStyle: {
|
||||
// width: 0
|
||||
// },
|
||||
showSymbol: false,
|
||||
emphasis: {
|
||||
focus: 'series'
|
||||
},
|
||||
data: []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'id'
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
dialogCertVisible(val) {
|
||||
if (val === false) {
|
||||
this.getSearch()
|
||||
}
|
||||
},
|
||||
currentBlock(val) {
|
||||
if (val) {
|
||||
getBalance({ nodeName: val }).then(res => {
|
||||
this.jifen = res.data || 0
|
||||
})
|
||||
}
|
||||
},
|
||||
nodeList(val) {
|
||||
if (val.length > 0) {
|
||||
this.currentBlock = val[0]
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.getSearch()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
handleCommand(command) {
|
||||
this.currentBlock = command
|
||||
},
|
||||
getSearch() {
|
||||
this.searchRecord()
|
||||
},
|
||||
// 查看数据弹框
|
||||
selectCert(row) {
|
||||
this.transactionData = { ...row, logType: row.type === '1' ? '2' : ['2', '4'].includes(row.type) ? '7' : '8', txHash: row.businessTxHash }
|
||||
this.blockchainDetail = false
|
||||
this.dialogCertVisible = true
|
||||
},
|
||||
fontSize(rem) {
|
||||
const scale = window.innerHeight / 100
|
||||
return parseInt(scale * rem)
|
||||
},
|
||||
// 最近7天交易量
|
||||
searchRecord() {
|
||||
const lineChart = echarts.init(this.$refs.lineChart)
|
||||
get7dayChart().then(e => {
|
||||
this.lineChartOption.xAxis.data = e.data.dateList
|
||||
this.lineChartOption.series[0].data = e.data.volumeList
|
||||
// this.lineChartOption.series[1].data = e.data.volumeList
|
||||
const that = this
|
||||
function getSuanli() {
|
||||
lineChart.clear()
|
||||
lineChart.setOption(that.lineChartOption)
|
||||
window.onresize = function() {
|
||||
lineChart.resize()
|
||||
}
|
||||
return getSuanli
|
||||
}
|
||||
getSuanli()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.blockchainBrowser{
|
||||
.node-select{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 4vh;
|
||||
}
|
||||
.num{
|
||||
display: flex;
|
||||
img{
|
||||
height: 10vh;
|
||||
margin-right: 0.625rem;
|
||||
}
|
||||
.impact{
|
||||
font-family: Impact;
|
||||
font-size: 1.625rem;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
p{
|
||||
font-size: 0.9rem;
|
||||
color: #9EACBE;
|
||||
}
|
||||
.node{
|
||||
font-size: 1rem;
|
||||
span{
|
||||
display: inline-block;
|
||||
height: 1vh;
|
||||
width: 1vh;
|
||||
border-radius: 10vh;
|
||||
background-color: rgba(22, 208, 255, 1);
|
||||
margin: 1vh 1vh 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#lineChart{
|
||||
width: 100%;
|
||||
height: 16vh;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,165 @@
|
|||
<template>
|
||||
<div class="podInfo">
|
||||
<el-card class="basicInfo">
|
||||
<Exhibition :data="exhibitionArray" :span="8" />
|
||||
</el-card>
|
||||
<el-card>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="dataList"
|
||||
tooltip-effect="dark"
|
||||
>
|
||||
<template v-slot:filterBtns>
|
||||
<el-button size="medium" type="primary" @click="handelAdd">{{ $t('message.create') }}</el-button>
|
||||
</template>
|
||||
</List>
|
||||
</el-card>
|
||||
<bind-dataset v-model="addFormVisible" data-type="code" :is-edit="isEdit" :data="updateData" @get-list="getList" />
|
||||
<son-dataset v-if="addSonVisible" v-model="addSonVisible" :data="sonData" @getList="getList" />
|
||||
<el-dialog :close-on-click-modal="false" title="查看子算法" :visible.sync="dialogSonListVisible" width="70%">
|
||||
<p>父算法:{{ fatherName }}</p>
|
||||
<List
|
||||
ref="sonList"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="sonColumns"
|
||||
:table-list-data="sonDataList"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
<span v-if="!sonDataList.length">没有子算法</span>
|
||||
</el-dialog>
|
||||
<!-- <CreateAdapter v-model="createAdapterVisible" :is-edit="isEdit" :data="updateData" @getList="() => this.$refs.multipleTable0.getList()" />
|
||||
<CreateCluster v-model="createClusterVisible" :is-edit="isEdit" :data="updateData" @getList="() => this.$refs.multipleTable1.getList()" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import Exhibition from '@/components/Exhibition'
|
||||
import { deleteCode, queryCodeList } from '@/api/jcs/jcs'
|
||||
import bindDataset from '../datasetManagement/addForm'
|
||||
import { getClusterList } from '@/api/container/cluster'
|
||||
import { mapGetters } from 'vuex'
|
||||
import sonDataset from './sonDataset'
|
||||
export default {
|
||||
components: { Exhibition, List, bindDataset, sonDataset },
|
||||
data() {
|
||||
return {
|
||||
exhibitionArray: [
|
||||
{
|
||||
name: '算法个数',
|
||||
src: 'algo-1',
|
||||
value: '0'
|
||||
}
|
||||
],
|
||||
isEdit: false,
|
||||
// num: 0,
|
||||
activeName: '0',
|
||||
updateData: {},
|
||||
dataList: [],
|
||||
addFormVisible: false,
|
||||
clusterList: [],
|
||||
addSonVisible: false,
|
||||
sonData: {},
|
||||
dialogSonListVisible: false,
|
||||
sonDataList: [],
|
||||
fatherName: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
]),
|
||||
columns() {
|
||||
return [
|
||||
{ prop: 'name', label: this.$t('page.algorithmName'), formatter: (row) => row.name },
|
||||
{ prop: 'description', label: this.$t('page.description'), formatter: (row) => row.description },
|
||||
{ prop: 'createTime', label: this.$t('page.creationTime'), sortable: true, formatter: (row) => {
|
||||
return <div>{new Date(row.createTime).toLocaleString()}</div>
|
||||
} },
|
||||
{ prop: 'clusters', label: this.$t('page.clusterIn'), formatter: (row) => this.getClusterData(row.clusterID) },
|
||||
{ prop: 'more', label: this.$t('page.more'), width: 160, formatter: (row) => {
|
||||
return <el-dropdown>
|
||||
<el-button className='el-dropdown-link' size='mini' icon='el-icon-more' circle>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => { this.getSonList(row.parentPackageID, row.name) }}> <el-dropdown-item> 查看子算法</el-dropdown-item> </span>
|
||||
<span onClick={() => { this.createSon(row) }}> <el-dropdown-item>创建子算法</el-dropdown-item> </span>
|
||||
<span onClick={() => { this.deleteItem(row) }}> <el-dropdown-item> {this.$t('page.delete')} </el-dropdown-item> </span>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
} }
|
||||
]
|
||||
},
|
||||
sonColumns() {
|
||||
return [
|
||||
{ prop: 'name', label: this.$t('page.algorithmName'), formatter: (row) => row.name },
|
||||
{ prop: 'description', label: this.$t('page.description'), formatter: (row) => row.description },
|
||||
{ prop: 'createTime', label: this.$t('page.creationTime'), sortable: true, formatter: (row) => {
|
||||
return <div>{new Date(row.createTime).toLocaleString()}</div>
|
||||
} },
|
||||
{ prop: 'clusters', label: this.$t('page.clusterIn'), formatter: (row) => this.getClusterData(row.clusterID) },
|
||||
{ prop: 'more', label: this.$t('page.more'), width: 160, formatter: (row) => {
|
||||
return <el-button onClick={() => { this.deleteItem(row, true) }}> {this.$t('page.delete')} </el-button>
|
||||
} }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getList()
|
||||
getClusterList({ 'storageSchedule': 1, pageSize: 1000, pageNum: 1 }).then(e => {
|
||||
this.clusterList = e?.data?.list || []
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getSonList(val, name) {
|
||||
this.fatherName = name
|
||||
queryCodeList({ dataType: 'code', userID: this.userID, parentPackageID: val }).then(e => {
|
||||
// const arr = e?.data?.datas?.[0]?.packages?.[0]?.versions || []
|
||||
this.sonDataList = e?.data?.packages || []
|
||||
this.dialogSonListVisible = true
|
||||
})
|
||||
},
|
||||
getClusterData(cluster) {
|
||||
return this.clusterList.find(s => s.id === cluster)?.name || '-'
|
||||
},
|
||||
getList() {
|
||||
queryCodeList({ dataType: 'code', userID: this.userID, parentPackageID: -1 }).then(e => {
|
||||
this.dataList = e?.data?.packages || []
|
||||
this.exhibitionArray[0].value = e?.data?.packages?.length || 0
|
||||
})
|
||||
},
|
||||
handelAdd() {
|
||||
this.addFormVisible = true
|
||||
},
|
||||
createSon(row) {
|
||||
this.sonData = row
|
||||
this.addSonVisible = true
|
||||
},
|
||||
deleteItem(row, isSon) {
|
||||
this.$confirm('确认删除么?', '提示', {
|
||||
confirmButtonText: this.$t('message.confirm'),
|
||||
cancelButtonText: this.$t('message.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
// packageIDs 多选删除
|
||||
deleteCode({ 'userID': this.userID,
|
||||
'type': isSon ? 'children' : 'parent', // 或者parent
|
||||
'packageIDs': [isSon ? row.clonePackageID : row.parentPackageID] }).then((e) => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
|
@ -0,0 +1,370 @@
|
|||
<template>
|
||||
<div id="createContainer">
|
||||
<el-dialog
|
||||
v-if="createFormVisible"
|
||||
width="70%"
|
||||
:close-on-click-modal="false"
|
||||
:title="'创建'+ editInfoForm.packageName +'子算法'"
|
||||
:visible.sync="createFormVisible"
|
||||
>
|
||||
<el-form
|
||||
ref="editInfoForm"
|
||||
:rules="rules"
|
||||
:model="editInfoForm"
|
||||
label-width="auto"
|
||||
label-position="left"
|
||||
>
|
||||
<el-form-item
|
||||
prop="name"
|
||||
label="子算法名称"
|
||||
>
|
||||
<el-input v-model="editInfoForm.name" :maxlength="63" :disabled="isEdit" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="description"
|
||||
label="描述"
|
||||
>
|
||||
<el-input v-model="editInfoForm.description" :disabled="isEdit" type="textarea" :rows="5" :maxlength="200" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="clusterID"
|
||||
:label="'选择子算法创建平台'"
|
||||
>
|
||||
<!-- <el-checkbox-group v-model="editInfoForm.clusterIDs" size="mini" :disabled="isEdit">
|
||||
<el-col v-for="item in clusterList" :key="item.id" :span="8">
|
||||
<el-checkbox :label="item.id" border>{{ item.name }}</el-checkbox>
|
||||
</el-col>
|
||||
</el-checkbox-group> -->
|
||||
<el-radio v-for="item in clusterList" :key="item.id" v-model="editInfoForm.clusterID" :disabled="isEdit" :label="item.id">{{ item.name }}</el-radio>
|
||||
</el-form-item>
|
||||
<el-card>
|
||||
<div class="folder-list">
|
||||
<div class="fold-item">
|
||||
<el-link type="info" :underline="false" @click="intoFold('/', true)">全部文件</el-link>
|
||||
</div>
|
||||
<div v-for="(item, key ) in path.split('/')" :key="key" class="fold-item">
|
||||
<span v-if="item" class="arrow">></span>
|
||||
<el-link v-if="key !== path.split('/').length-1" type="primary" @click="intoFold(item, true)">{{ item }}</el-link>
|
||||
<el-link v-else type="info" :underline="false">{{ item }}</el-link>
|
||||
</div>
|
||||
</div>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale || editInfoForm.filePath"
|
||||
class="multipleTable"
|
||||
:columns="fileColumns"
|
||||
:pagination="false"
|
||||
:table-list-data="allFileList"
|
||||
/>
|
||||
<br>
|
||||
<div class="add-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
hide-on-single-page
|
||||
:current-page="page"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:pager-count="5"
|
||||
@current-change="pageChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="createFormVisible = false">{{ $t("message.cancel") }}</el-button>
|
||||
<el-button type="primary" @click="submitInfoEdit">{{ $t("message.confirm") }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog v-if="codeVisible" :close-on-click-modal="false" title="自定义参数设置" :visible.sync="codeVisible">
|
||||
<codemirror v-model="code" class="code-mirror" :options="cmOption" />
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="closeCodeVisible">{{ $t("message.cancel") }}</el-button>
|
||||
<el-button type="primary" @click="confirmCode">{{ $t("message.confirm") }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { getDictByCode } from '@/api/common/setting'
|
||||
import { getFileList, downloadFile, addCode, uploadData } from '@/api/jcs/jcs'
|
||||
import List from '@/components/list.vue'
|
||||
import { getClusterList } from '@/api/container/cluster'
|
||||
// import editBaseInfo from '@/mixin/editBaseInfo'
|
||||
// import { getModelType } from '@/api/task/task'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: { List },
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
},
|
||||
isEdit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
codeVisible: false,
|
||||
editInfoForm: {
|
||||
clusterID: '',
|
||||
name: '',
|
||||
description: '',
|
||||
packageID: '',
|
||||
filePath: '',
|
||||
packageName: ''
|
||||
},
|
||||
cmOption: {
|
||||
theme: 'darcula',
|
||||
autoCloseBrackets: true,
|
||||
tabSize: 4,
|
||||
styleActiveLine: true,
|
||||
lineNumbers: true,
|
||||
line: true,
|
||||
mode: 'text/x-yaml'
|
||||
},
|
||||
itemList: [],
|
||||
dialogSelectVisible: false,
|
||||
currentList: [],
|
||||
allFileList: [],
|
||||
clusterList: [],
|
||||
categoryList: [],
|
||||
modelTypeList: [],
|
||||
chipList: [],
|
||||
imageList: [],
|
||||
inputVisible: false,
|
||||
inputValue: '',
|
||||
packageID: '',
|
||||
page: 1,
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
path: '/',
|
||||
foldList: [],
|
||||
originCode: '',
|
||||
code: '',
|
||||
storageIDs: [],
|
||||
editedFileList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
]),
|
||||
createFormVisible: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
},
|
||||
columns() {
|
||||
return [
|
||||
{ type: 'selection' },
|
||||
{
|
||||
prop: 'packageName',
|
||||
label: this.$t('page.packageName')
|
||||
},
|
||||
{
|
||||
prop: 'clusters',
|
||||
label: this.$t('page.targetCluster')
|
||||
},
|
||||
{
|
||||
prop: 'createTime',
|
||||
label: this.$t('page.createTime')
|
||||
}
|
||||
]
|
||||
},
|
||||
fileColumns() {
|
||||
return [
|
||||
{ prop: 'name', label: '文件名', formatter: (row) => {
|
||||
const img1 = require('@/assets/img/file-1.png')
|
||||
return <div>
|
||||
{((this.path === '/' ? '' : this.path) + row.path) === this.editInfoForm.filePath ? <i class='el-icon-s-flag' /> : ''}
|
||||
{row.objectID === -1 ? <a onclick={() => this.intoFold(row.path)} ><img style='height: 1.2rem;margin-right: 0.5rem;vertical-align: text-bottom;' src={img1} /><span>{row.path.split('/')[row.path.split('/').length - 1]}</span></a> : <span>{row.path.indexOf('/') === 0 ? row.path.substring(row.path.indexOf('/') + 1) : row.path}</span> }
|
||||
</div>
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'size',
|
||||
label: this.$t('page.size')
|
||||
},
|
||||
{
|
||||
prop: 'createTime', label: this.$t('page.creationTime'), sortable: true, formatter: (row) => {
|
||||
return <div>{new Date(row.createTime).toLocaleString()}</div>
|
||||
} },
|
||||
{ prop: 'more', label: this.$t('message.operation'), formatter: (row) => {
|
||||
return row.objectID !== -1 ? <div>
|
||||
<el-button disabled={((this.path === '/' ? '' : this.path) + row.path) === this.editInfoForm.filePath} onClick={() => this.selectCodeFile(row)}> {((this.path === '/' ? '' : this.path) + row.path) === this.editInfoForm.filePath ? '已选择' : (this.$t('message.select') + '入口文件')} </el-button>
|
||||
<el-button onClick={() => this.downloadCode(row)}> 编辑 </el-button>
|
||||
</div> : ''
|
||||
} }
|
||||
]
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
name: [
|
||||
{ required: true, message: this.$t('message.pleaseInput') }
|
||||
],
|
||||
category: [
|
||||
{ required: true, message: this.$t('message.pleaseChoose') }
|
||||
],
|
||||
clusterID: [
|
||||
{ required: true, message: this.$t('message.pleaseChoose') }
|
||||
],
|
||||
packageIDs: [
|
||||
{ required: true, message: this.$t('message.pleaseChoose') }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'data'() {
|
||||
this.editInfoForm.packageID = this.data.parentPackageID
|
||||
this.editInfoForm.packageName = this.data.name
|
||||
this.getCodeFileList()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
getClusterList({ 'storageSchedule': 1, pageSize: 1000, pageNum: 1 }).then(e => {
|
||||
this.clusterList = e?.data?.list || []
|
||||
})
|
||||
this.editInfoForm.packageID = this.data.parentPackageID
|
||||
this.editInfoForm.packageName = this.data.name
|
||||
this.getCodeFileList()
|
||||
},
|
||||
methods: {
|
||||
handleClose(tag) {
|
||||
this.editInfoForm.tags.splice(this.editInfoForm.tags.indexOf(tag), 1)
|
||||
},
|
||||
showInput() {
|
||||
this.inputVisible = true
|
||||
this.$nextTick(_ => {
|
||||
this.$refs.saveTagInput.$refs.input.focus()
|
||||
})
|
||||
},
|
||||
pageChange(page) {
|
||||
this.page = page
|
||||
this.getCodeFileList()
|
||||
},
|
||||
intoFold(path, flag) {
|
||||
if (flag) {
|
||||
this.path = this.path.substring(0, this.path.indexOf(path) + path.length)
|
||||
} else {
|
||||
this.path = (this.path === '/' ? '' : this.path) + path
|
||||
}
|
||||
this.getCodeFileList()
|
||||
// this.$router.push({ path: this.$route.path, query })
|
||||
},
|
||||
getCodeFileList() {
|
||||
const params = {
|
||||
'queryParams': {
|
||||
'dataType': 'code',
|
||||
'userID': this.userID,
|
||||
'packageID': Number(this.editInfoForm.packageID),
|
||||
'path': this.path === '/' ? '' : this.path,
|
||||
'CurrentPage': this.page,
|
||||
'pageSize': this.pageSize,
|
||||
'orderBy': 'name'
|
||||
}
|
||||
}
|
||||
getFileList(params).then(e => {
|
||||
this.total = e.data?.totalCount
|
||||
const arr = e.data?.uploadedDatas[0].objects || []
|
||||
arr.forEach(item => {
|
||||
item.disabled = item.objectID === -1
|
||||
})
|
||||
this.allFileList = arr
|
||||
this.storageIDs = e.data?.uploadedDatas[0].uploadedCluster.map(e => e.storageID).filter(Boolean)
|
||||
})
|
||||
},
|
||||
selectCodeFile(val) {
|
||||
this.dialogSelectVisible = false
|
||||
this.itemList = this.itemList.concat(val)
|
||||
this.editInfoForm.filePath = (this.path === '/' ? '' : this.path) + val.path
|
||||
},
|
||||
downloadCode(row) {
|
||||
this.currentFile = row
|
||||
downloadFile({
|
||||
userID: this.userID,
|
||||
objectID: row.objectID
|
||||
}).then(n => {
|
||||
this.codeVisible = true
|
||||
this.code = n + ''
|
||||
this.originCode = n + ''
|
||||
})
|
||||
},
|
||||
closeCodeVisible() {
|
||||
this.codeVisible = false
|
||||
},
|
||||
confirmCode() {
|
||||
if (this.code !== this.originCode) {
|
||||
this.editedFileList.push({
|
||||
...this.currentFile,
|
||||
content: this.code
|
||||
})
|
||||
}
|
||||
this.codeVisible = false
|
||||
},
|
||||
submitCode() {
|
||||
const params = {
|
||||
userID: this.userID,
|
||||
type: 'children',
|
||||
param: {
|
||||
...this.editInfoForm,
|
||||
parentImageID: this.data.parentImageID,
|
||||
packageName: this.data.packageName,
|
||||
bucketID: this.data.bucketID,
|
||||
imageID: this.data.imageID
|
||||
}
|
||||
}
|
||||
addCode(params).then(n => {
|
||||
const form = new FormData()
|
||||
form.append('info', JSON.stringify({
|
||||
'userID': this.userID,
|
||||
'packageID': n.data.newPackage?.packageID,
|
||||
'loadTo': this.storageIDs,
|
||||
'loadToPath': ['/']
|
||||
}))
|
||||
this.editedFileList.forEach(e => {
|
||||
const blob = new Blob([e.content], { type: 'text/plain' })
|
||||
const file = new File([blob], encodeURIComponent(e.path), { type: 'text/plain' })
|
||||
form.append(`files`, file)
|
||||
})
|
||||
uploadData(form).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('修改成功')
|
||||
this.codeVisible = false
|
||||
this.getNewVersion = true
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
submitInfoEdit() {
|
||||
this.$refs.editInfoForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.editInfoForm.filePath === '') {
|
||||
this.$message.warning('请选择入口文件')
|
||||
return
|
||||
}
|
||||
this.submitCode()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,556 @@
|
|||
<template>
|
||||
<div id="createContainer">
|
||||
<el-dialog
|
||||
v-if="createFormVisible"
|
||||
width="70%"
|
||||
:close-on-click-modal="false"
|
||||
:title="(isEdit? '查看' : '绑定')+tabName[dataType]"
|
||||
:visible.sync="createFormVisible"
|
||||
>
|
||||
<el-form
|
||||
ref="editInfoForm"
|
||||
:rules="rules"
|
||||
:model="editInfoForm"
|
||||
label-width="auto"
|
||||
label-position="left"
|
||||
>
|
||||
<el-form-item
|
||||
v-if="dataType !== 'code'"
|
||||
prop="clusterIDs"
|
||||
:label="'选择'+tabName[dataType]+'创建平台'"
|
||||
>
|
||||
<el-checkbox-group v-model="editInfoForm.clusterIDs" size="mini" :disabled="isEdit">
|
||||
<el-col v-for="item in clusterList" :key="item.id" :span="8">
|
||||
<el-checkbox :label="item.id" border>{{ item.name }}</el-checkbox>
|
||||
</el-col>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="name"
|
||||
:label="tabName[dataType]+'名称'"
|
||||
>
|
||||
<el-input v-model="editInfoForm.name" :maxlength="63" :disabled="isEdit" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
prop="description"
|
||||
:label="tabName[dataType]+'描述'"
|
||||
>
|
||||
<el-input v-model="editInfoForm.description" :disabled="isEdit" type="textarea" :rows="5" :maxlength="200" />
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dataType === 'dataset'"
|
||||
prop="category"
|
||||
label="数据集类别"
|
||||
>
|
||||
<el-radio v-for="item in categoryList" :key="item.itemValue" v-model="editInfoForm.category" :label="item.itemValue">{{ item.itemText }}</el-radio>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dataType === 'model'" :label="$t('page.modelType')" prop="modelType">
|
||||
<el-select v-model="editInfoForm.modelType" :disabled="isEdit" style="width: 280px;margin-right: 10px;">
|
||||
<el-option v-for="item in modelTypeList" :key="item" :label="item" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dataType === 'model'" label="模型环境" prop="env">
|
||||
<el-select v-model="editInfoForm.env" style="width: 280px;margin-right: 10px;" :disabled="isEdit">
|
||||
<el-option label="Pytorch" value="pytorch" />
|
||||
<el-option label="Tensorflow" value="tensorflow" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dataType === 'model'" label="模型版本" prop="version">
|
||||
<el-input v-model="editInfoForm.version" :maxlength="63" :disabled="isEdit" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dataType === 'image'" label="架构选择" prop="architecture">
|
||||
<el-select v-model="editInfoForm.architecture" style="width: 280px;margin-right: 10px;" :disabled="isEdit">
|
||||
<el-option label="Pytorch" value="pytorch" />
|
||||
<el-option label="Tensorflow" value="tensorflow" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dataType === 'image'" label="计算类型选择" prop="resourceType ">
|
||||
<el-radio v-for="item in chipList" :key="item.itemValue" v-model="editInfoForm.resourceType" :label="item.itemValue" :disabled="isEdit">{{ item.itemText }}</el-radio>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dataType === 'image'" label="标签" prop="tags">
|
||||
<el-tag
|
||||
v-for="tag in editInfoForm.tags"
|
||||
:key="tag"
|
||||
closable
|
||||
:disabled="isEdit"
|
||||
:disable-transitions="false"
|
||||
@close="handleClose(tag)"
|
||||
>
|
||||
{{ tag }}
|
||||
</el-tag>
|
||||
<el-input
|
||||
v-if="inputVisible&&!isEdit"
|
||||
ref="saveTagInput"
|
||||
v-model="inputValue"
|
||||
class="input-new-tag"
|
||||
size="small"
|
||||
@keyup.enter.native="handleInputConfirm"
|
||||
@blur="handleInputConfirm"
|
||||
/>
|
||||
<el-button v-else class="button-new-tag" size="small" :disabled="isEdit" @click="showInput">+</el-button>
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dataType === 'code'" label="选择镜像" prop="imageID">
|
||||
<el-select v-model="editInfoForm.imageID" style="width: 280px;margin-right: 10px;" :disabled="isEdit">
|
||||
<el-option v-for="item in imageList" :key="item.info.id" :label="item.info.name" :value="item.info.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="dataType !== 'code'"
|
||||
prop="packageIDs"
|
||||
label="绑定文件"
|
||||
>
|
||||
<el-card>
|
||||
<table class="tableInput width100">
|
||||
<tr>
|
||||
<th>{{ $t('page.packageName') }}</th>
|
||||
<th>{{ $t('page.targetCluster') }}</th>
|
||||
<th>{{ $t('page.createTime') }}</th>
|
||||
<th>{{ $t('page.more') }}</th>
|
||||
</tr>
|
||||
<tr v-for="(it, index) in itemList" :key="index">
|
||||
<td>
|
||||
<span v-if="!isEdit">{{ it.packageName }}</span>
|
||||
<a v-else style="text-decoration: underline;" @click="toFileManage(it)">{{ it.packageName }}</a>
|
||||
</td>
|
||||
<td>
|
||||
{{ it.clusters }}
|
||||
</td>
|
||||
<td>
|
||||
{{ it.createTime }}
|
||||
</td>
|
||||
<td>
|
||||
<el-button v-if="!isEdit" @click="deleteItem(it)">删除</el-button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<el-button v-if="!isEdit" @click="addItem">添加</el-button>
|
||||
</el-card>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dataType === 'code'" label="选择package" prop="packageID">
|
||||
<el-select v-model="editInfoForm.packageID" style="width: 280px;margin-right: 10px;">
|
||||
<el-option v-for="item in allPackageList" :key="item.packageID" :label="item.packageName" :value="item.packageID" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="dataType === 'code'" label="选择入口文件" prop="filePath">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="10">
|
||||
<el-input v-model="editInfoForm.filePath" placeholder="请选择文件" :readonly="true" />
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-button :disabled="!editInfoForm.packageID" @click="addItem">选择文件</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
<div v-if="!isEdit" slot="footer" class="dialog-footer">
|
||||
<el-button @click="createFormVisible = false">{{ $t("message.cancel") }}</el-button>
|
||||
<el-button type="primary" @click="submitInfoEdit">{{ $t("message.confirm") }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog v-if="dialogSelectVisible" title="选择文件" :visible.sync="dialogSelectVisible">
|
||||
<List
|
||||
v-if="dataType !== 'code'"
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:pagination="false"
|
||||
:table-list-data="allPackageList"
|
||||
/>
|
||||
|
||||
<p />
|
||||
<!-- <br> -->
|
||||
<div v-if="dataType === 'code'">
|
||||
<div class="folder-list">
|
||||
<div class="fold-item">
|
||||
<el-link type="info" :underline="false" @click="intoFold('/', true)">全部文件</el-link>
|
||||
</div>
|
||||
<div v-for="(item, key ) in path.split('/')" :key="key" class="fold-item">
|
||||
<span v-if="item" class="arrow">></span>
|
||||
<el-link v-if="key !== path.split('/').length-1" type="primary" @click="intoFold(item, true)">{{ item }}</el-link>
|
||||
<el-link v-else type="info" :underline="false">{{ item }}</el-link>
|
||||
</div>
|
||||
</div>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="fileColumns"
|
||||
:pagination="false"
|
||||
:table-list-data="allFileList"
|
||||
/>
|
||||
<br>
|
||||
<div class="add-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
hide-on-single-page
|
||||
:current-page="page"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:pager-count="5"
|
||||
@current-change="pageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div slot="footer" class="dialog-footer">
|
||||
<el-button icon="el-icon-close" circle @click="dialogSelectVisible = false" />
|
||||
<el-button icon="el-icon-check" circle @click="ok" />
|
||||
</div> -->
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getDictByCode } from '@/api/common/setting'
|
||||
import { getFileList, addBinding, getBindingList, addCode } from '@/api/jcs/jcs'
|
||||
import List from '@/components/list.vue'
|
||||
import { getClusterList } from '@/api/container/cluster'
|
||||
// import editBaseInfo from '@/mixin/editBaseInfo'
|
||||
import { getModelType } from '@/api/task/task'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: { List },
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
dataType: {
|
||||
type: String,
|
||||
default: 'dataset'
|
||||
},
|
||||
isEdit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tabName: {
|
||||
'dataset': '数据集',
|
||||
'image': '镜像',
|
||||
'code': '算法',
|
||||
'model': '模型'
|
||||
},
|
||||
editInfoForm: {
|
||||
clusterIDs: [],
|
||||
name: '',
|
||||
category: '',
|
||||
description: '',
|
||||
packageIDs: [],
|
||||
type: this.dataType,
|
||||
resourceType: '',
|
||||
architecture: '',
|
||||
tags: [],
|
||||
imageID: '',
|
||||
filePath: '',
|
||||
packageID: '',
|
||||
bootstrapObjectID: ''
|
||||
},
|
||||
itemList: [],
|
||||
dialogSelectVisible: false,
|
||||
currentList: [],
|
||||
allPackageList: [],
|
||||
allFileList: [],
|
||||
clusterList: [],
|
||||
categoryList: [],
|
||||
modelTypeList: [],
|
||||
chipList: [],
|
||||
imageList: [],
|
||||
inputVisible: false,
|
||||
inputValue: '',
|
||||
packageID: '',
|
||||
page: 1,
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
path: '/',
|
||||
foldList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
]),
|
||||
createFormVisible: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
},
|
||||
columns() {
|
||||
return [
|
||||
{
|
||||
prop: 'packageName',
|
||||
label: this.$t('page.packageName')
|
||||
},
|
||||
{
|
||||
prop: 'clusters',
|
||||
label: this.$t('page.targetCluster')
|
||||
},
|
||||
{
|
||||
prop: 'createTime',
|
||||
label: this.$t('page.createTime'), formatter: (row) => {
|
||||
return <div>{new Date(row.createTime).toLocaleString()}</div>
|
||||
} },
|
||||
{
|
||||
prop: 'operation',
|
||||
label: this.$t('message.operation'), formatter: (row) => {
|
||||
return <div>
|
||||
<el-button onClick={() => this.ok(row)} type='text' size='small'>选择</el-button>
|
||||
</div>
|
||||
} }
|
||||
]
|
||||
},
|
||||
fileColumns() {
|
||||
return [
|
||||
{ prop: 'name', label: '文件名', formatter: (row) => {
|
||||
const img1 = require('@/assets/img/file-1.png')
|
||||
return <div>
|
||||
{row.objectID === -1 ? <a onclick={() => this.intoFold(row.path)} ><img style='height: 1.2rem;margin-right: 0.5rem;vertical-align: text-bottom;' src={img1} /><span>{row.path.split('/')[row.path.split('/').length - 1]}</span></a> : <span>{row.path.indexOf('/') === 0 ? row.path.substring(row.path.indexOf('/') + 1) : row.path}</span> }
|
||||
</div>
|
||||
}
|
||||
},
|
||||
{
|
||||
prop: 'size',
|
||||
label: this.$t('page.size')
|
||||
},
|
||||
{
|
||||
prop: 'createTime',
|
||||
label: this.$t('page.createTime')
|
||||
},
|
||||
{ prop: 'more', label: this.$t('message.operation'), formatter: (row) => {
|
||||
return row.objectID !== -1 ? <el-button onClick={() => this.selectCodeFile(row)}> {this.$t('message.select')} </el-button> : ''
|
||||
} }
|
||||
]
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
name: [
|
||||
{ required: true, message: this.$t('message.pleaseInput') }
|
||||
],
|
||||
category: [
|
||||
{ required: true, message: this.$t('message.pleaseChoose') }
|
||||
],
|
||||
clusterIDs: [
|
||||
{ required: true, message: this.$t('message.pleaseChoose') }
|
||||
],
|
||||
packageIDs: [
|
||||
{ required: true, message: this.$t('message.pleaseChoose') }
|
||||
],
|
||||
packageID: [
|
||||
{ required: true, message: this.$t('message.pleaseChoose') }
|
||||
],
|
||||
imageID: [
|
||||
{ required: true, message: this.$t('message.pleaseChoose') }
|
||||
],
|
||||
filePath: [
|
||||
{ required: true, message: this.$t('message.pleaseChoose') }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
itemList: {
|
||||
handler(val) {
|
||||
this.editInfoForm.packageIDs = val.map(item => item.packageID)
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
'editInfoForm.packageID'(val) {
|
||||
if (!this.isEdit) {
|
||||
this.page = 1
|
||||
this.getCodeFileList()
|
||||
}
|
||||
},
|
||||
'data'(val) {
|
||||
this.editInfoForm = val.info
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.isEdit) {
|
||||
console.log(this.data)
|
||||
this.itemList = this.data.packages
|
||||
}
|
||||
getClusterList({ 'storageSchedule': 1, pageSize: 1000, pageNum: 1 }).then(e => {
|
||||
this.clusterList = e?.data?.list || []
|
||||
})
|
||||
if (this.dataType === 'dataset') {
|
||||
getDictByCode('dataset-category-dict').then(res => {
|
||||
this.categoryList = res.data?.list || []
|
||||
})
|
||||
}
|
||||
if (this.dataType === 'model') {
|
||||
getModelType().then(e => {
|
||||
this.modelTypeList = e.data.types
|
||||
})
|
||||
}
|
||||
if (this.dataType === 'image') {
|
||||
getDictByCode('chip-type-dict').then(res => {
|
||||
this.chipList = res.data?.list || []
|
||||
})
|
||||
}
|
||||
if (this.dataType === 'code') {
|
||||
getBindingList({ dataType: 'image', param: { userID: this.userID, bindingID: -1, type: 'private' }}).then(e => {
|
||||
this.imageList = e?.data?.datas || []
|
||||
})
|
||||
}
|
||||
this.getFile() // 非 code 类型的文件列表
|
||||
},
|
||||
methods: {
|
||||
toFileManage(it) {
|
||||
window.open(window.location.origin + '/fileManagement/fileList?packageID=' + it.packageID + '&packageName= ' + it.packageName + '&path=%2F&type=' + this.dataType, '_blank')
|
||||
},
|
||||
handleClose(tag) {
|
||||
this.editInfoForm.tags.splice(this.editInfoForm.tags.indexOf(tag), 1)
|
||||
},
|
||||
showInput() {
|
||||
this.inputVisible = true
|
||||
this.$nextTick(_ => {
|
||||
this.$refs.saveTagInput.$refs.input.focus()
|
||||
})
|
||||
},
|
||||
handleInputConfirm() {
|
||||
const inputValue = this.inputValue
|
||||
if (inputValue) {
|
||||
this.editInfoForm.tags.push(inputValue)
|
||||
}
|
||||
this.inputVisible = false
|
||||
this.inputValue = ''
|
||||
},
|
||||
pageChange(page) {
|
||||
this.page = page
|
||||
this.getCodeFileList()
|
||||
},
|
||||
intoFold(path, flag) {
|
||||
if (flag) {
|
||||
this.path = this.path.substring(0, this.path.indexOf(path) + path.length)
|
||||
} else {
|
||||
this.path = (this.path === '/' ? '' : this.path) + path
|
||||
}
|
||||
this.getCodeFileList()
|
||||
// this.$router.push({ path: this.$route.path, query })
|
||||
},
|
||||
getCodeFileList() {
|
||||
const params = {
|
||||
'queryParams': {
|
||||
'dataType': 'code',
|
||||
'userID': this.userID,
|
||||
'packageID': Number(this.editInfoForm.packageID),
|
||||
'path': this.path === '/' ? '' : this.path,
|
||||
'CurrentPage': this.page,
|
||||
'pageSize': this.pageSize,
|
||||
'orderBy': 'name'
|
||||
}
|
||||
}
|
||||
getFileList(params).then(e => {
|
||||
this.total = e.data?.totalCount
|
||||
const arr = e.data?.uploadedDatas[0].objects || []
|
||||
arr.forEach(item => {
|
||||
item.disabled = item.objectID === -1
|
||||
})
|
||||
this.allFileList = arr
|
||||
})
|
||||
},
|
||||
getFile() {
|
||||
const params = {
|
||||
'queryParams': {
|
||||
'dataType': this.dataType,
|
||||
'userID': this.userID,
|
||||
// "path": "/path",
|
||||
'packageID': -1,
|
||||
'CurrentPage': this.page,
|
||||
'pageSize': this.pageSize,
|
||||
'orderBy': 'name'
|
||||
}
|
||||
}
|
||||
getFileList(params).then(e => {
|
||||
this.total = e.data?.totalCount
|
||||
this.allPackageList = e.data?.uploadedDatas || []
|
||||
})
|
||||
},
|
||||
checkBeforeSubmit() {
|
||||
},
|
||||
addItem() {
|
||||
this.currentList = []
|
||||
this.dialogSelectVisible = true
|
||||
},
|
||||
// currentChange(val) {
|
||||
// this.currentList = val
|
||||
// },
|
||||
selectCodeFile(val) {
|
||||
this.dialogSelectVisible = false
|
||||
this.editInfoForm.bootstrapObjectID = val.objectID
|
||||
this.editInfoForm.filePath = (this.path === '/' ? '' : this.path) + val.path
|
||||
},
|
||||
deleteItem(item) {
|
||||
this.itemList = this.itemList.filter(it => it !== item)
|
||||
},
|
||||
ok(val) {
|
||||
this.dialogSelectVisible = false
|
||||
this.itemList = [val]
|
||||
},
|
||||
submitInfoEdit() {
|
||||
this.$refs.editInfoForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.dataType === 'code') {
|
||||
const { description, name, packageID, imageID } = this.editInfoForm
|
||||
const image = this.imageList.find(e => e.info.id === imageID).info.imageID
|
||||
const item = this.allPackageList.find(e => e.packageID === packageID)
|
||||
const params = {
|
||||
userID: this.userID,
|
||||
type: 'parent',
|
||||
param: {
|
||||
description,
|
||||
name,
|
||||
packageID,
|
||||
parentImageID: imageID,
|
||||
packageName: item.packageName,
|
||||
bucketID: item.bucketID,
|
||||
imageID: image
|
||||
}
|
||||
}
|
||||
addCode(params).then(res => {
|
||||
if (res.code === 'OK') {
|
||||
this.$message.success(this.$t('message.success'))
|
||||
this.createFormVisible = false
|
||||
this.$emit('get-list')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const params = {
|
||||
userID: this.userID,
|
||||
info: {
|
||||
...this.editInfoForm
|
||||
}
|
||||
}
|
||||
params.info.packageID = params.info.packageIDs[0]
|
||||
addBinding(params).then(res => {
|
||||
if (res.code === 'OK') {
|
||||
this.$message.success(this.$t('message.success'))
|
||||
this.createFormVisible = false
|
||||
this.$emit('get-list')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-if="createFormVisible"
|
||||
width="70%"
|
||||
:close-on-click-modal="false"
|
||||
:title="this.$t('page.applyList')"
|
||||
:visible.sync="createFormVisible"
|
||||
>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="dataList"
|
||||
list-key="data"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="createFormVisible = false">{{ $t("message.close") }}</el-button>
|
||||
</div>
|
||||
<div v-if="!dataList.length">
|
||||
<p>无申请列表</p>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list.vue'
|
||||
import { getApplyList, confirmApply } from '@/api/jcs/jcs'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: { List },
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
dataType: {
|
||||
type: String,
|
||||
default: 'dataset'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataList: [],
|
||||
statusMap: {
|
||||
'pending': '申请中',
|
||||
'approved': '申请通过',
|
||||
'rejected': '拒绝',
|
||||
'revoked': '撤回申请',
|
||||
'expired': '申请过期(失效)',
|
||||
'cancel': '取消申请'
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
]),
|
||||
createFormVisible: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
},
|
||||
columns() {
|
||||
return [{ prop: 'name', label: this.$t('page.applyAccount'), formatter: (row) => row.userName || '-' },
|
||||
// { prop: 'createTime', label: this.$t('page.creationTime'), sortable: true, formatter: (row) => {
|
||||
// return <div>{new Date(row.info.createTime).toLocaleString()}</div>
|
||||
// } },
|
||||
{ prop: 'clusters', label: this.dataType === 'dataset' ? this.$t('page.applyDataset') : this.$t('page.applyModel'), formatter: (row) => row.Name },
|
||||
{ prop: 'description', label: this.$t('page.description'), formatter: (row) => { return row.Content ? JSON.parse(decodeURIComponent(row.Content))?.description || '-' : '-' } },
|
||||
{ prop: 'status', label: this.$t('page.status'), formatter: (row) => row?.status ? this.statusMap[row.status] : '-' },
|
||||
{ prop: 'more', label: this.$t('page.more'), width: 160, formatter: (row) => {
|
||||
return <div>
|
||||
{row.status !== 'approved' && (
|
||||
<el-button onClick={() => this.editItem(row, 'approved')} type='success' icon='el-icon-s-setting' size='small'>同意</el-button>
|
||||
)}
|
||||
{(row.status === 'pending' || row.status === 'approved') && (
|
||||
<el-button onClick={() => this.editItem(row, 'rejected')} type='danger' icon='el-icon-s-setting' size='small'>拒绝</el-button>
|
||||
)}
|
||||
</div>
|
||||
} }]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
getApplyList({ userID: this.userID, dataType: this.dataType }).then(res => {
|
||||
this.dataList = res?.data?.datas || []
|
||||
})
|
||||
},
|
||||
editItem(row, status) {
|
||||
// if (status===)
|
||||
confirmApply({ approval: { ID: row.ID, status: status, reason: '' }}).then(res => {
|
||||
if (res.code === 'OK') {
|
||||
this.$message.success('操作成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Add your styles here */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-if="createFormVisible"
|
||||
width="70%"
|
||||
:close-on-click-modal="false"
|
||||
:title="this.$t('page.forApply')"
|
||||
:visible.sync="createFormVisible"
|
||||
>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="dataList"
|
||||
list-key="data"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="createFormVisible = false">{{ $t("message.close") }}</el-button>
|
||||
</div>
|
||||
<div v-if="!dataList.length">
|
||||
<p>无申请列表</p>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list.vue'
|
||||
import { getBindingList, applyData, cancelApply } from '@/api/jcs/jcs'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { getDictByCode } from '@/api/common/setting'
|
||||
|
||||
export default {
|
||||
components: { List },
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
dataType: {
|
||||
type: String,
|
||||
default: 'dataset'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
dataList: [],
|
||||
statusMap: {
|
||||
'pending': '申请中',
|
||||
'approved': '申请通过',
|
||||
'rejected': '拒绝',
|
||||
'revoked': '撤回申请',
|
||||
'expired': '申请过期(失效)',
|
||||
'cancel': '取消申请'
|
||||
},
|
||||
renderMoreButtons(row) {
|
||||
if (row.status) {
|
||||
switch (row.status) {
|
||||
case 'pending':
|
||||
return (
|
||||
<el-button onClick={() => this.editItem(row, 'revoked')} type='success' size='small'>
|
||||
撤销访问
|
||||
</el-button>
|
||||
)
|
||||
case 'approved':
|
||||
return (
|
||||
<div>
|
||||
<el-button onClick={() => this.editItem(row, 'cancel')} type='danger' size='small'>
|
||||
取消访问权限
|
||||
</el-button>
|
||||
</div>
|
||||
)
|
||||
case 'cancel':
|
||||
return (
|
||||
<div>
|
||||
<el-button onClick={() => this.editItem(row, 'applyData')} type='primary' size='small'>
|
||||
再次申请访问
|
||||
</el-button>
|
||||
</div>
|
||||
)
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<el-button onClick={() => this.editItem(row, 'applyData')} type='primary' size='small'>
|
||||
申请访问
|
||||
</el-button>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
]),
|
||||
createFormVisible: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
},
|
||||
columns() {
|
||||
return [{ prop: 'Name', minWidth: '15%', label: this.$t('page.' + this.dataType + 'Applied'), formatter: (row) => row.Name },
|
||||
{ prop: 'Name', minWidth: '15%', label: this.$t('page.owner'), formatter: (row) => row.userName },
|
||||
{ prop: 'description', minWidth: '15%', label: this.$t('page.description'), formatter: (row) => row?.info?.description || '-' },
|
||||
{ prop: 'type', minWidth: '15%', label: this.$t('page.category'), formatter: (row) => this.getResourceType(row?.info?.category) || '' },
|
||||
{ prop: 'status', minWidth: '15%', label: this.$t('page.status'), formatter: (row) => row.status ? this.statusMap[row.status] : '未申请使用' },
|
||||
{ prop: 'more', minWidth: '25%', label: this.$t('page.more'), formatter: (row) => this.renderMoreButtons(row) }]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (this.dataType === 'dataset') {
|
||||
getDictByCode('dataset-category-dict').then(res => {
|
||||
this.categoryList = res.data?.list || []
|
||||
})
|
||||
}
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getResourceType(category) {
|
||||
return this.categoryList.find(item => item.itemValue === category)?.itemText || '-'
|
||||
},
|
||||
getList() {
|
||||
const filterData = { dataType: this.dataType, param: { userID: this.userID, bindingID: -1, type: 'apply' }}
|
||||
// if (param && (param.status || param.name)) {
|
||||
// filterData.param.status = param?.status || ''
|
||||
// filterData.param.name = param?.name || ''
|
||||
// }
|
||||
if (this.activeName === 'apply') {
|
||||
filterData.param.status = 'appoved'
|
||||
}
|
||||
|
||||
getBindingList(filterData).then(res => {
|
||||
this.dataList = res?.data?.datas || []
|
||||
if (this.dataList.length === 0) {
|
||||
this.$message.info('暂无数据')
|
||||
}
|
||||
})
|
||||
},
|
||||
editItem(row, status) {
|
||||
if (status === 'applyData') {
|
||||
const data = {
|
||||
'apply': {
|
||||
'bindingID': row.ID,
|
||||
'applicantID': this.userID,
|
||||
'ownerID': row.ownerID,
|
||||
'reason': '申请使用',
|
||||
'expirationDate': '2028-02-15T14:30:00Z'
|
||||
}
|
||||
}
|
||||
applyData(data).then(res => {
|
||||
if (res.code === 'OK') {
|
||||
this.$message.success('操作成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
cancelApply({ userID: this.userID, bindingID: row.ID, status: status }).then(res => {
|
||||
if (res.code === 'OK') {
|
||||
this.$message.success('操作成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Add your styles here */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
<template>
|
||||
<div class="podInfo">
|
||||
<el-card class="basicInfo">
|
||||
<Exhibition :data="exhibitionArray" :span="8" />
|
||||
</el-card>
|
||||
<el-card>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="datasetList"
|
||||
list-key="data"
|
||||
tooltip-effect="dark"
|
||||
>
|
||||
<template v-slot:filterBtns>
|
||||
<el-button size="medium" type="primary" @click="forApplyVisible = true">{{ $t('page.forApply') }}</el-button>
|
||||
<el-button size="medium" type="primary" @click="applyListVisible = true">{{ $t('page.applyList') }}</el-button>
|
||||
<el-button size="medium" type="primary" @click="handelAdd">{{ $t('message.create') }}</el-button>
|
||||
</template>
|
||||
</List>
|
||||
</el-card>
|
||||
<bind-dataset v-model="addFormVisible" data-type="dataset" :is-edit="isEdit" :data="updateData" @get-list="getList" />
|
||||
<apply-list v-if="applyListVisible" v-model="applyListVisible" />
|
||||
<for-apply v-if="forApplyVisible" v-model="forApplyVisible" />
|
||||
<el-dialog :close-on-click-modal="false" width="50%" title="访问权限设置" :visible.sync="dialogSettingVisible">
|
||||
<el-radio-group v-model="radioValue">
|
||||
<el-radio label="private">仅本用户可访问</el-radio>
|
||||
<el-radio label="apply">申请后可访问</el-radio>
|
||||
<el-radio label="public">公开所有可访问</el-radio>
|
||||
</el-radio-group>
|
||||
<el-button type="primary" @click="authSetting">确定</el-button>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import Exhibition from '@/components/Exhibition'
|
||||
import bindDataset from './addForm'
|
||||
import { getDictByCode } from '@/api/common/setting'
|
||||
import { getBindingList, deleteBinding, accessAuthSetting } from '@/api/jcs/jcs'
|
||||
import applyList from './applyList'
|
||||
import forApply from './canApplyList'
|
||||
import { getClusterList } from '@/api/container/cluster'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: { Exhibition, List, bindDataset, applyList, forApply },
|
||||
data() {
|
||||
return {
|
||||
dialogSettingVisible: false,
|
||||
datasetList: [],
|
||||
currentID: '',
|
||||
exhibitionArray: [
|
||||
{
|
||||
name: '数据集个数',
|
||||
src: 'dataset-1',
|
||||
value: '0'
|
||||
},
|
||||
{
|
||||
name: '图片类数据集',
|
||||
src: 'dataset-2',
|
||||
value: '0'
|
||||
},
|
||||
{
|
||||
name: '文本类数据集',
|
||||
src: 'dataset-3',
|
||||
value: '0'
|
||||
}
|
||||
],
|
||||
isEdit: false,
|
||||
// num: 0,
|
||||
typeList: [this.$t('page.cloud'), this.$t('page.ai'), this.$t('page.hpc'), this.$t('page.cloud')],
|
||||
activeName: '0',
|
||||
updateData: {},
|
||||
addFormVisible: false,
|
||||
categoryList: [],
|
||||
radioValue: 'private',
|
||||
applyListVisible: false,
|
||||
forApplyVisible: false,
|
||||
clusterList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
]),
|
||||
columns() {
|
||||
return [
|
||||
{ prop: 'name', label: this.$t('page.datasetName'), formatter: (row) => { return <a onclick={() => this.handleDetail(row.ID)} >{row.info.name}</a> } },
|
||||
// { prop: 'createTime', label: this.$t('page.creationTime'), sortable: true, formatter: (row) => {
|
||||
// return <div>{new Date(row.info.createTime).toLocaleString()}</div>
|
||||
// } },
|
||||
{ prop: 'clusters', label: this.$t('page.clusterIn'), formatter: (row) => this.getClusterData(row.info.clusterIDs) },
|
||||
{ prop: 'status', label: this.$t('page.status'), formatter: (row) => row.accessLevel === 'public' ? '公开' : row.accessLevel === 'apply' ? '可申请' : '私有' },
|
||||
{ prop: 'type', label: this.$t('page.datasetCategory'), formatter: (row) => this.getResourceType(row.info.category) || '' },
|
||||
{ prop: 'more', label: this.$t('page.more'), width: 160, formatter: (row) => {
|
||||
return <div>
|
||||
<el-dropdown>
|
||||
<el-button className='el-dropdown-link' size='mini' icon='el-icon-more' circle>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => { this.radioValue = row.accessLevel; this.dialogSettingVisible = true; this.currentID = row.ID }}> <el-dropdown-item> {this.$t('page.authSetting')}</el-dropdown-item> </span>
|
||||
<span onClick={() => { this.deleteItem(row) }}> <el-dropdown-item> {this.$t('page.delete')} </el-dropdown-item> </span>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
} }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getList()
|
||||
getDictByCode('dataset-category-dict').then(res => {
|
||||
this.categoryList = res.data?.list || []
|
||||
})
|
||||
getClusterList({ 'storageSchedule': 1, pageSize: 1000, pageNum: 1 }).then(e => {
|
||||
this.clusterList = e?.data?.list || []
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getClusterData(cluster) {
|
||||
if (this.clusterList.length) {
|
||||
return cluster?.map(e => {
|
||||
return this.clusterList.find(s => s.id === e)?.name || ''
|
||||
}).filter(Boolean).join(',') || '-'
|
||||
} else {
|
||||
return '-'
|
||||
}
|
||||
},
|
||||
getList() {
|
||||
getBindingList({ dataType: 'dataset', param: { userID: this.userID, bindingID: -1, type: 'private' }}).then(e => {
|
||||
this.datasetList = e?.data?.datas || []
|
||||
this.exhibitionArray[0].value = e?.data?.datas?.length || 0
|
||||
this.exhibitionArray[1].value = e?.data?.datas?.filter(item => item.info.category === 'image').length || 0
|
||||
this.exhibitionArray[2].value = e?.data?.datas?.filter(item => item.info.category === 'text').length || 0
|
||||
})
|
||||
},
|
||||
getResourceType(category) {
|
||||
return this.categoryList.find(item => item.itemValue === category)?.itemText || '-'
|
||||
},
|
||||
authSetting() {
|
||||
accessAuthSetting({ ID: this.currentID, level: this.radioValue }).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('设置成功')
|
||||
this.dialogSettingVisible = false
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
},
|
||||
handelAdd() {
|
||||
this.isEdit = false
|
||||
this.addFormVisible = true
|
||||
},
|
||||
handleDetail(bindingID) {
|
||||
this.isEdit = true
|
||||
getBindingList({ dataType: 'dataset', param: { userID: this.userID, bindingID: bindingID, type: 'private' }}).then(e => {
|
||||
this.updateData = e.data.datas[0]
|
||||
this.addFormVisible = true
|
||||
})
|
||||
},
|
||||
deleteItem(row) {
|
||||
this.$confirm('确认删除么?', '提示', {
|
||||
confirmButtonText: this.$t('message.confirm'),
|
||||
cancelButtonText: this.$t('message.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteBinding({ packageIDs: [row.info.packageID], bindingIDs: [row.ID] }).then((e) => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
|
@ -0,0 +1,232 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
v-if="createFormVisible"
|
||||
width="70%"
|
||||
:close-on-click-modal="false"
|
||||
:title="this.$t('message.select') + tabName[dataType]"
|
||||
:visible.sync="createFormVisible"
|
||||
>
|
||||
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
|
||||
<el-tab-pane :label="'我的'+tabName[dataType]" name="private" />
|
||||
<el-tab-pane :label="'已申请'+tabName[dataType]" name="apply" />
|
||||
<el-tab-pane :label="'公开'+tabName[dataType]" name="public" />
|
||||
</el-tabs>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="activeName"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="dataList"
|
||||
:filter-map="filterMap"
|
||||
list-key="data"
|
||||
tooltip-effect="dark"
|
||||
@get-list="getList"
|
||||
/>
|
||||
<!-- <div slot="footer" class="dialog-footer">
|
||||
<el-button @click="createFormVisible = false">{{ $t("message.close") }}</el-button>
|
||||
</div> -->
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list.vue'
|
||||
import { getBindingList, cancelApply, applyData } from '@/api/jcs/jcs'
|
||||
import { getDictByCode } from '@/api/common/setting'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: { List },
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
dataType: {
|
||||
type: String,
|
||||
default: 'dataset'
|
||||
},
|
||||
selectedItem: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tabName: {
|
||||
'dataset': '数据集',
|
||||
'image': '镜像',
|
||||
'code': '算法',
|
||||
'model': '模型'
|
||||
},
|
||||
dataList: [],
|
||||
activeName: 'private',
|
||||
categoryList: [],
|
||||
statusMap: {
|
||||
'pending': '申请中',
|
||||
'approved': '申请通过',
|
||||
'rejected': '拒绝',
|
||||
'revoked': '撤回申请',
|
||||
'expired': '申请过期(失效)',
|
||||
'cancel': '取消申请'
|
||||
},
|
||||
renderMoreButtons(row) {
|
||||
if (row.status) {
|
||||
switch (row.status) {
|
||||
case 'pending':
|
||||
return (
|
||||
<el-button onClick={() => this.editItem(row, 'revoked')} type='success' size='small'>
|
||||
撤销访问
|
||||
</el-button>
|
||||
)
|
||||
case 'approved':
|
||||
return (
|
||||
<div>
|
||||
{/* <el-button onClick={() => this.editItem(row, 'cancel')} type='danger' size='small'>
|
||||
取消访问权限
|
||||
</el-button> */}
|
||||
<el-button onClick={() => this.selectItem(row)} type='success' size='small'>
|
||||
选择
|
||||
</el-button>
|
||||
</div>
|
||||
)
|
||||
case 'cancel':
|
||||
return (
|
||||
<div>
|
||||
<el-button onClick={() => this.editItem(row, 'applyData')} type='primary' size='small'>
|
||||
再次申请访问
|
||||
</el-button>
|
||||
</div>
|
||||
)
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
} else {
|
||||
return (
|
||||
<el-button onClick={() => this.editItem(row, 'applyData')} type='primary' size='small'>
|
||||
申请访问
|
||||
</el-button>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
]),
|
||||
createFormVisible: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
},
|
||||
filterMap() {
|
||||
return this.activeName !== 'apply' ? {
|
||||
name: {
|
||||
label: this.$t('page.name')
|
||||
}
|
||||
} : {
|
||||
name: {
|
||||
label: this.$t('page.name')
|
||||
}
|
||||
// status: {
|
||||
// label: '状态',
|
||||
// type: 'select',
|
||||
// dataSource: Object.keys(this.statusMap).map(key => {
|
||||
// return {
|
||||
// label: this.statusMap[key],
|
||||
// value: key
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
}
|
||||
},
|
||||
columns() {
|
||||
return this.activeName !== 'apply' ? [{ prop: 'name', label: this.$t('page.' + this.dataType + 'Name'), formatter: (row) => row.info?.name },
|
||||
{ prop: 'description', label: this.$t('page.description'), formatter: (row) => row?.info?.description || '-' },
|
||||
{ prop: 'type', label: this.$t('page.category'), formatter: (row) => this.getResourceType(row?.info?.category) || '' },
|
||||
{ prop: 'more', label: this.$t('page.more'), width: 160, formatter: (row) => {
|
||||
return <div>
|
||||
<el-button onClick={() => this.selectItem(row)} type='success' size='small'>选择</el-button>
|
||||
</div>
|
||||
} }] : [{ prop: 'Name', minWidth: '15%', label: this.$t('page.' + this.dataType + 'Applied'), formatter: (row) => row.Name },
|
||||
{ prop: 'Name', minWidth: '15%', label: this.$t('page.owner'), formatter: (row) => row.userName },
|
||||
{ prop: 'description', minWidth: '15%', label: this.$t('page.description'), formatter: (row) => row?.info?.description || '-' },
|
||||
{ prop: 'type', minWidth: '15%', label: this.$t('page.category'), formatter: (row) => this.getResourceType(row?.info?.category) || '' },
|
||||
{ prop: 'status', minWidth: '15%', label: this.$t('page.status'), formatter: (row) => row.status ? this.statusMap[row.status] : '未申请使用' },
|
||||
{ prop: 'more', minWidth: '25%', label: this.$t('page.more'), formatter: (row) => this.renderMoreButtons(row) }]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
getDictByCode('dataset-category-dict').then(res => {
|
||||
this.categoryList = res.data?.list || []
|
||||
})
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
handleClick() {
|
||||
// reset
|
||||
this.getList()
|
||||
},
|
||||
getResourceType(category) {
|
||||
return this.categoryList.find(item => item.itemValue === category)?.itemText || '-'
|
||||
},
|
||||
getList(param) {
|
||||
const filterData = { dataType: this.dataType, param: { userID: this.userID, bindingID: -1, type: this.activeName }}
|
||||
if (param && (param.status || param.name)) {
|
||||
filterData.param.status = param?.status || ''
|
||||
filterData.param.name = param?.name || ''
|
||||
}
|
||||
if (this.activeName === 'apply') {
|
||||
filterData.param.status = 'appoved'
|
||||
}
|
||||
|
||||
getBindingList(filterData).then(res => {
|
||||
this.dataList = res?.data?.datas || []
|
||||
if (this.dataList.length === 0) {
|
||||
this.$message.info('暂无数据')
|
||||
}
|
||||
})
|
||||
},
|
||||
selectItem(row) {
|
||||
console.log('select')
|
||||
this.$emit('select-item', row)
|
||||
},
|
||||
editItem(row, status) {
|
||||
if (status === 'applyData') {
|
||||
const data = {
|
||||
'apply': {
|
||||
'bindingID': row.ID,
|
||||
'applicantID': 1,
|
||||
'ownerID': row.ownerID,
|
||||
'reason': '申请使用',
|
||||
'expirationDate': '2025-02-15T14:30:00Z'
|
||||
}
|
||||
}
|
||||
applyData(data).then(res => {
|
||||
if (res.code === 'OK') {
|
||||
this.$message.success('操作成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
cancelApply({ userID: this.userID, bindingID: row.ID, status: status }).then(res => {
|
||||
if (res.code === 'OK') {
|
||||
this.$message.success('操作成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Add your styles here */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,573 @@
|
|||
<template>
|
||||
<div class="UsabilityMonitor">
|
||||
<el-card class="list-detail">
|
||||
<el-page-header content="文件列表" @back="$router.go(-1)" />
|
||||
<br>
|
||||
<el-card v-if="statusList.length">
|
||||
<p>在线文件上传状态</p>
|
||||
<div v-for="item in statusList" :key="item.id">
|
||||
<el-alert
|
||||
:title="item.name+'正在上传中。。。。'"
|
||||
:type="item.status === 'uploading' ? 'success' : ''"
|
||||
@close="() => {closeStatus(item)}"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-row>
|
||||
<div class="select-option">
|
||||
<el-button v-if="$route.query.type === 'code'" class="opr-btn" size="middle" type="primary" @click="uploadType = 'online';dialogCreateVisible=true">在线上传文件</el-button>
|
||||
<el-button v-if="storageIDs.length" class="opr-btn" size="middle" type="primary" @click="uploadType = 'local';dialogCreateVisible=true">本地上传文件</el-button>
|
||||
<el-button class="opr-btn" size="middle" @click="createFold">创建目录</el-button>
|
||||
</div>
|
||||
<br>
|
||||
<div class="folder-list">
|
||||
<div class="fold-item">
|
||||
<el-link type="info" :underline="false" @click="intoFold('/', true)">全部文件</el-link>
|
||||
</div>
|
||||
<div v-for="(item, key ) in foldList" :key="key" class="fold-item">
|
||||
<span v-if="item" class="arrow">></span>
|
||||
<el-link v-if="key !== foldList.length-1" type="primary" @click="intoFold(item, true)">{{ item }}</el-link>
|
||||
<el-link v-else type="info" :underline="false">{{ item }}</el-link>
|
||||
</div>
|
||||
</div>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="allFileList"
|
||||
:pagination="false"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
<br>
|
||||
<div class="add-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
hide-on-single-page
|
||||
:current-page="page"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:pager-count="5"
|
||||
@current-change="currentChange"
|
||||
/>
|
||||
</div>
|
||||
<el-dialog v-if="dialogCreateVisible" :visible.sync="dialogCreateVisible" :title="(uploadType === 'online' ? '在线' : '本地') +'上传'" width="70%" @close="resetData">
|
||||
<div class="upload-area">
|
||||
<el-form>
|
||||
<el-card v-if="uploadType !== 'online'" border>
|
||||
<el-upload
|
||||
ref="upload"
|
||||
class="upload-demo"
|
||||
:file-list="fileList"
|
||||
:auto-upload="false"
|
||||
multiple
|
||||
action="#"
|
||||
>
|
||||
<el-button slot="trigger" size="small" type="primary">选取文件</el-button>
|
||||
</el-upload>
|
||||
</el-card>
|
||||
<el-form-item v-if="uploadType === 'online'" label="在线文件地址填写" prop="url">
|
||||
<el-input
|
||||
v-model="formData.url"
|
||||
:max-length="200"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div v-if="loading">
|
||||
<img style="height: 25vh;" src="../../../assets/images/loading.gif">
|
||||
<div style="margin-top: -7vh;">上传中</div>
|
||||
</div>
|
||||
</el-form>
|
||||
<!-- <el-divider /> -->
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="resetData">取消</el-button>
|
||||
<el-button type="primary" :disabled="submitLoading" @click="submitUpload">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import clip from '@/utils/clipboard'
|
||||
import { numberToStr } from '@/utils/data-process'
|
||||
// import deletePng from '@/assets/images/exhibition/statusMonitor-2.png'
|
||||
import { getToken } from '@/utils/auth'
|
||||
// import { getAvailableClusterList } from '@/api/fileManagement/index'
|
||||
// import { getDictItems, getDictByCode } from '@/api/common/setting'
|
||||
import { getUploadData, uploadData, getFileList, createFolder, deleteFolder, deleteFile, getStatusList } from '@/api/jcs/jcs'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
List
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
foldList: [],
|
||||
formData: {
|
||||
url: '',
|
||||
bias: [],
|
||||
region: [],
|
||||
chip: [],
|
||||
selectedCluster: []
|
||||
},
|
||||
page: 1,
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
uploadType: '',
|
||||
regionList: [],
|
||||
chipList: [],
|
||||
biasList: [],
|
||||
isScheduled: 'yes',
|
||||
canOnline: false,
|
||||
dialogCreateVisible: false,
|
||||
dialogDetailVisible: false,
|
||||
submitLoading: false,
|
||||
token: getToken(),
|
||||
// clusterPath: {},
|
||||
exhibitionArray: [
|
||||
{
|
||||
name: '文件个数(个)',
|
||||
src: 'usabilityMonitor-1',
|
||||
value: '0'
|
||||
},
|
||||
{
|
||||
name: '文件总大小(GB)',
|
||||
src: 'usabilityMonitor-2',
|
||||
value: '0'
|
||||
}
|
||||
],
|
||||
columns: [
|
||||
// { type: 'selection' },
|
||||
{ prop: 'name', label: '文件名', formatter: (row) => {
|
||||
const img1 = require('@/assets/img/file-1.png')
|
||||
return <div>
|
||||
{row.objectID === -1 ? <a onclick={() => this.intoFold(row.path)} ><img style='height: 1.2rem;margin-right: 0.5rem;vertical-align: text-bottom;' src={img1} /><span>{row.path.split('/')[row.path.split('/').length - 1]}</span></a> : <span>{row.path.indexOf('/') === 0 ? row.path.substring(row.path.indexOf('/') + 1) : row.path}</span> }
|
||||
</div>
|
||||
}
|
||||
},
|
||||
{ prop: 'createTime', label: '创建时间', formatter: (row) => { return <span>{row.objectID === -1 ? '-' : row.createTime}</span> } },
|
||||
{ prop: 'size', label: '大小', formatter: (row) => { return <span>{row.objectID !== -1 ? numberToStr(row.size - 0, 'B') : '-'}</span> } },
|
||||
|
||||
{ prop: '', label: '操作', formatter: (row) => {
|
||||
// const options = { width: 120 }
|
||||
return <div class='opr-group'>
|
||||
<svg-icon icon-class='shanchu' onClick={() => this.deleteItem(row)} />
|
||||
</div>
|
||||
} }
|
||||
],
|
||||
tapTableData0: [],
|
||||
tapTableData1: [],
|
||||
diskfileList: [],
|
||||
fileList: [],
|
||||
clusterList: [],
|
||||
loading: false,
|
||||
allFileList: [],
|
||||
storageIDs: [],
|
||||
clusterIDs: [],
|
||||
statusList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
'$route.query'(newValue, oldValue) {
|
||||
this.foldList = this.$route.query.path.substring(1).split('/') || []
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.$route.query.packageID) {
|
||||
this.foldList = this.$route.query.path.substring(1).split('/') || []
|
||||
this.$router.push({ path: '/fileManagement/packageList' })
|
||||
}
|
||||
this.getList()
|
||||
if (this.$route.query.type === 'code') {
|
||||
this.getStatus()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getStatus() {
|
||||
getStatusList({
|
||||
'userID': this.userID,
|
||||
'operate': 'query',
|
||||
'packageID': this.$route.query.packageID,
|
||||
'dataType': 'code'
|
||||
}).then(e => {
|
||||
this.statusList = e.data
|
||||
})
|
||||
},
|
||||
closeStatus(row) {
|
||||
getStatusList({
|
||||
'userID': this.userID,
|
||||
'operate': 'delete',
|
||||
'id': row.id,
|
||||
'packageID': this.$route.query.packageID,
|
||||
'dataType': 'code'
|
||||
}).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.getStatus()
|
||||
}
|
||||
})
|
||||
},
|
||||
getList() {
|
||||
const params = {
|
||||
'queryParams': {
|
||||
'dataType': this.$route.query.type,
|
||||
'userID': this.userID,
|
||||
// 'clustersIDs': [],
|
||||
'packageID': Number(this.$route.query.packageID),
|
||||
'path': this.$route.query.path === '/' ? '' : this.$route.query.path,
|
||||
'CurrentPage': this.page,
|
||||
'pageSize': this.pageSize,
|
||||
'orderBy': 'name'
|
||||
}
|
||||
}
|
||||
getFileList(params).then(e => {
|
||||
this.total = e.data?.totalCount
|
||||
this.allFileList = e.data?.uploadedDatas[0].objects || []
|
||||
this.storageIDs = e.data?.uploadedDatas[0].uploadedCluster.map(e => e.storageID).filter(Boolean)
|
||||
this.clusterIDs = e.data?.uploadedDatas[0].uploadedCluster.map(e => e.clusterID).filter(Boolean)
|
||||
this.canOnline = this.storageIDs.length === 0 && this.clusterIDs.length !== 0
|
||||
})
|
||||
},
|
||||
currentChange(page) {
|
||||
this.page = page
|
||||
this.getList()
|
||||
},
|
||||
intoFold(path, flag) {
|
||||
const query = JSON.parse(JSON.stringify(this.$route.query))
|
||||
if (flag) {
|
||||
query.path = this.$route.query.path.substring(0, this.$route.query.path.indexOf(path) + path.length)
|
||||
} else {
|
||||
query.path = (query.path === '/' ? '' : query.path) + path
|
||||
}
|
||||
this.$router.push({ path: this.$route.path, query })
|
||||
},
|
||||
createFold() {
|
||||
this.$prompt('请输入文件夹名称', '新建文件夹', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消'
|
||||
}).then(({ value }) => {
|
||||
const pr = {
|
||||
userID: this.userID,
|
||||
packageID: Number(this.$route.query.packageID),
|
||||
path: this.$route.query.path + (this.$route.query.path !== '/' ? '/' : '') + value
|
||||
}
|
||||
createFolder(pr).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('创建成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
handleUploadSuccess() {
|
||||
this.$message.success('文件上传成功')
|
||||
this.dialogCreateVisible = false
|
||||
this.fileList = []
|
||||
this.getList()
|
||||
},
|
||||
handleUploadError() {
|
||||
this.$message.warning('上传失败')
|
||||
},
|
||||
handleCopy(text, event) {
|
||||
clip(text, event)
|
||||
},
|
||||
resetData() {
|
||||
this.formData = {
|
||||
url: '',
|
||||
bias: [],
|
||||
region: [],
|
||||
chip: [],
|
||||
selectedCluster: []
|
||||
}
|
||||
this.dialogCreateVisible = false
|
||||
this.fileList = []
|
||||
this.getList()
|
||||
},
|
||||
deleteItem(item) {
|
||||
this.$confirm('<p>文件/文件夹删除后将不可恢复,是否确认删除?</p>', '温馨提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确认',
|
||||
center: true,
|
||||
cancelButtonText: '取消'
|
||||
}).then(() => {
|
||||
item.objectID === -1 ? deleteFolder({ packageID: Number(this.$route.query.packageID), userID: this.userID, path: (this.$route.query.path !== '/' ? this.$route.query.path : '') + item.path }).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
}
|
||||
}) : deleteFile({ objectIDs: [item.objectID], userID: this.userID }).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
submitUpload() {
|
||||
this.submitLoading = true
|
||||
if (this.uploadType === 'local') {
|
||||
const form = new FormData()
|
||||
form.append('info', JSON.stringify({
|
||||
'userID': this.userID,
|
||||
'packageID': Number(this.$route.query.packageID),
|
||||
'loadTo': this.storageIDs,
|
||||
'loadToPath': Array(this.storageIDs.length).fill('/' + this.$route.query.type + '/' + this.$route.query.packageName + this.$route.query.path + (this.$route.query.path !== '/' ? '/' : ''))
|
||||
}))
|
||||
this.$refs.upload.uploadFiles.forEach((file, index) => {
|
||||
const newFile = new File([file.raw], encodeURIComponent(this.$route.query.path + (this.$route.query.path !== '/' ? '/' : '') + file.raw.name))
|
||||
form.append(`files`, newFile)
|
||||
})
|
||||
this.loading = true
|
||||
uploadData(form).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.submitNotify(e.data.uploadeds.map(e => e.objectID) || [])
|
||||
} else {
|
||||
this.submitLoading = false
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.submitLoading = false
|
||||
this.loading = false
|
||||
})
|
||||
} else {
|
||||
this.submitNotify()
|
||||
}
|
||||
},
|
||||
submitNotify(objectID) {
|
||||
const FormDatas = {
|
||||
'userID': this.userID,
|
||||
'packageID': Number(this.$route.query.packageID),
|
||||
'uploadParams': {
|
||||
'dataType': this.$route.query.type
|
||||
}
|
||||
}
|
||||
if (this.uploadType !== 'local') {
|
||||
FormDatas.uploadParams.uploadInfo = {
|
||||
'type': 'url',
|
||||
'url': this.formData.url,
|
||||
'clusterID': this.clusterIDs,
|
||||
'packageID': Number(this.$route.query.packageID)
|
||||
}
|
||||
const arr = this.formData.url.split('/')
|
||||
FormDatas.uploadParams.uploadInfo.dataName = arr[arr.length - 1].split('.')[0]
|
||||
} else {
|
||||
FormDatas.uploadParams.uploadInfo = {
|
||||
'type': 'local',
|
||||
'localPath': this.$route.query.path + (this.$route.query.path !== '/' ? '/' : '') + this.$refs.upload.uploadFiles[0].name, // localPath arr?
|
||||
'objectIDs': objectID
|
||||
}
|
||||
}
|
||||
getUploadData(FormDatas).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('上传成功!')
|
||||
this.submitLoading = false
|
||||
this.loading = false
|
||||
this.resetData()
|
||||
this.getStatus()
|
||||
} else {
|
||||
this.submitLoading = false
|
||||
this.loading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.submitLoading = false
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
getBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
let fileResult = ''
|
||||
reader.readAsDataURL(file)
|
||||
reader.onload = () => {
|
||||
fileResult = reader.result
|
||||
}
|
||||
reader.onerror = (error) => {
|
||||
reject(error)
|
||||
}
|
||||
reader.onloadend = () => {
|
||||
resolve(fileResult)
|
||||
}
|
||||
})
|
||||
},
|
||||
getCount() {
|
||||
// getFileCount().then(e => {
|
||||
// this.exhibitionArray[0].value = e.data?.totalFiles
|
||||
// this.exhibitionArray[1].value = numberToStr(e.data?.totalSize - 0, 'B')
|
||||
// })
|
||||
},
|
||||
// getList() {
|
||||
// getFileList({ }).then(e => {
|
||||
// this.diskfileList = e.lists
|
||||
// this.total = e.total
|
||||
// })
|
||||
// },
|
||||
deleteFunc(id) {
|
||||
},
|
||||
handleClick() {
|
||||
if (this.activeName === '1') {
|
||||
this.form = { env: 'python' }
|
||||
}
|
||||
},
|
||||
transBase64(code) {
|
||||
return Buffer.from(code).toString('base64')
|
||||
},
|
||||
getResult() {
|
||||
// this.dynamicData();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.folder-list{
|
||||
.fold-item{
|
||||
float: left;
|
||||
.arrow{
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.progress{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
margin: 25px 0;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
background-color: #ccdcff;
|
||||
}
|
||||
.progress::before{
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
background: #3182CE;
|
||||
}
|
||||
.progress::before{
|
||||
animation: progress 10s infinite;
|
||||
}
|
||||
@keyframes progress {
|
||||
to {
|
||||
width: 100%
|
||||
}
|
||||
}
|
||||
.select-option{
|
||||
padding: 20px;
|
||||
color: var(--buttonDivC);
|
||||
background: var(--listBtnColor);
|
||||
}
|
||||
.opr-group{
|
||||
color:#999999;
|
||||
svg{
|
||||
margin-right: 37px;
|
||||
cursor: pointer
|
||||
}
|
||||
.svg-icon{width:20px; height: 20px;}
|
||||
}
|
||||
.file-breadcrumb{
|
||||
padding: 17px 32px;
|
||||
.el-breadcrumb__item:last-child .el-breadcrumb__inner, .el-breadcrumb__item:last-child .el-breadcrumb__inner:hover, .el-breadcrumb__item:last-child .el-breadcrumb__inner a, .el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover{
|
||||
font-size: 16px!important;
|
||||
color: var(--buttonDivC);
|
||||
font-weight: 500!important;
|
||||
}
|
||||
.floatRight{
|
||||
text-align: right;
|
||||
float: right;
|
||||
font-size: 16px!important;
|
||||
color: var(--buttonDivC);
|
||||
font-weight: 500!important;
|
||||
}
|
||||
}
|
||||
.el-popper .qrcode-popover{
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
p{
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
.qrcode{
|
||||
margin: 24px auto;
|
||||
margin-top: 40px;
|
||||
width: 140px;
|
||||
padding: 10px;
|
||||
border: 1px solid #eeeeee;
|
||||
border-radius: 10px;
|
||||
}
|
||||
>span{
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
margin-bottom: 24px;
|
||||
color: #999999;
|
||||
}
|
||||
.el-button{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
.el-divider{
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
.upload-area{
|
||||
text-align: center;
|
||||
p{
|
||||
text-align: left;
|
||||
color: var(--buttonDivC);
|
||||
font-size: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.el-row--flex.is-justify-space-between{
|
||||
margin-top: 20px;
|
||||
}
|
||||
.upload-file{
|
||||
text-align: right;
|
||||
}
|
||||
.el-upload__tip{
|
||||
float: left;
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.el-upload{
|
||||
.el-button{
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.el-upload-list__item-name{
|
||||
text-align: left;
|
||||
color: #ffffff;
|
||||
}
|
||||
.el-radio{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.red{
|
||||
color: #D9001B;
|
||||
}
|
||||
.blue {
|
||||
color: #3182CE;
|
||||
}
|
||||
.tap-name{
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
background: #3182CE;
|
||||
border-radius: 2px;
|
||||
margin-bottom: 24px;
|
||||
padding: 0 27px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.add-pagination{
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
</style>
|
|
@ -1,423 +0,0 @@
|
|||
<template>
|
||||
<div class="UsabilityMonitor">
|
||||
<el-card>
|
||||
<Exhibition :data="exhibitionArray" :span="8" />
|
||||
</el-card>
|
||||
<el-row>
|
||||
<el-card>
|
||||
<el-row>
|
||||
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
|
||||
<el-tab-pane label="数据集" name="0" />
|
||||
<el-tab-pane label="镜像" name="1" />
|
||||
<el-tab-pane label="算法" name="2" />
|
||||
<el-tab-pane label="模型" name="3" />
|
||||
</el-tabs>
|
||||
<div class="select-option">
|
||||
<el-button class="opr-btn" size="middle" type="primary" @click="form={runEnv: 'python3'};dialogCreateVisible=true">上传文件</el-button>
|
||||
<!-- <el-button class="opr-btn" size="middle" @click="downloadList">下载任务列表</el-button> -->
|
||||
</div>
|
||||
<br>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale && activeName"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:get-list-action="getFileList"
|
||||
:default-filter-data="{'label': activeName}"
|
||||
:pagination="true"
|
||||
page-key="pageNum"
|
||||
limit-key="pageSize"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
<!-- <div class="add-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
:hide-on-single-page="false"
|
||||
:current-page="page"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
@current-change="currentChange"
|
||||
/>
|
||||
</div> -->
|
||||
<el-dialog :visible.sync="dialogCreateVisible" title="上传文件选择" width="50%" @close="cancelUpload">
|
||||
<div class="upload-area">
|
||||
<p>选择集群</p>
|
||||
<el-row :gutter="20">
|
||||
<el-checkbox-group v-model="selectedCluster" size="mini">
|
||||
<el-col v-for="item in clusterList" :key="item.id" :span="8">
|
||||
<el-checkbox :label="item.id" border>{{ item.name }}</el-checkbox>
|
||||
<p />
|
||||
<el-input v-model="clusterPath[item.id]" placeholder="存储路径" />
|
||||
</el-col>
|
||||
</el-checkbox-group>
|
||||
</el-row>
|
||||
<p style="margin-top: 30px">本地上传</p>
|
||||
<el-upload
|
||||
ref="upload"
|
||||
class="upload-demo"
|
||||
:file-list="fileList"
|
||||
:auto-upload="false"
|
||||
action="#"
|
||||
:multiple="true"
|
||||
>
|
||||
<el-button slot="trigger" size="small" type="primary">选取文件</el-button>
|
||||
<div slot="tip" class="el-upload__tip">单个文件支持最大上传2G</div>
|
||||
</el-upload>
|
||||
<!-- <el-divider /> -->
|
||||
<el-button type="info" :disabled="submitLoading" @click="submitUpload">确认</el-button>
|
||||
<el-button @click="cancelUpload">取消</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog :visible.sync="dialogDetailVisible" title="存储文件详情" width="80%">
|
||||
<div>
|
||||
<!-- <div class="select-option" /> -->
|
||||
<div class="tap-name">
|
||||
存储文件名称:
|
||||
{{ tapTableData0.length > 0 ? tapTableData0[0].name : '' }}
|
||||
<!-- 条带名:/t1efne231_0 -->
|
||||
</div>
|
||||
<List
|
||||
ref="tapTable0"
|
||||
class="tapTable"
|
||||
:columns="tapTableColumns"
|
||||
:table-list-data="tapTableData0"
|
||||
:pagination="false"
|
||||
/>
|
||||
<!-- <div class="add-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
:hide-on-single-page="false"
|
||||
:current-page="1"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:total="10"
|
||||
/>
|
||||
</div> -->
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import Exhibition from '@/components/Exhibition'
|
||||
import clip from '@/utils/clipboard'
|
||||
import { numberToStr } from '@/utils/data-process'
|
||||
// import deletePng from '@/assets/images/exhibition/statusMonitor-2.png'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { getFileList, getFileCount, getAvailableClusterList, uploadFile, deleteFile } from '@/api/fileManagement/index'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
List,
|
||||
Exhibition
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
getFileList,
|
||||
location: window.location.origin,
|
||||
activeName: '0',
|
||||
dialogCreateVisible: false,
|
||||
dialogDetailVisible: false,
|
||||
submitLoading: false,
|
||||
radio1: '1',
|
||||
token: getToken(),
|
||||
selectedCluster: [],
|
||||
clusterPath: {},
|
||||
exhibitionArray: [
|
||||
{
|
||||
name: '文件个数',
|
||||
src: 'usabilityMonitor-1',
|
||||
value: '0'
|
||||
},
|
||||
{
|
||||
name: '文件总大小',
|
||||
src: 'usabilityMonitor-2',
|
||||
value: '0'
|
||||
}
|
||||
],
|
||||
columns: [
|
||||
{ type: 'selection' },
|
||||
{ prop: 'name', label: '文件名', formatter: (row) => { return <span>{row.name}</span> } },
|
||||
{ prop: 'createdAt', label: '上传时间' },
|
||||
{ prop: 'size', label: '大小', formatter: (row) => { return <span>{numberToStr(row.size - 0, 'B')}</span> } },
|
||||
{ prop: 'cluster', label: '所在集群', formatter: (row) => {
|
||||
const dat = row.clusters.map(e => e.name)
|
||||
return <span>{
|
||||
dat.join(',')
|
||||
}</span>
|
||||
} },
|
||||
{ prop: '', label: '操作', formatter: (row) => {
|
||||
// const options = { width: 120 }
|
||||
return <div class='opr-group'>
|
||||
<svg-icon icon-class='shanchu' onClick={() => this.deleteFile(row.id)} />
|
||||
</div>
|
||||
} }
|
||||
],
|
||||
tapTableColumns: [
|
||||
{ type: 'index', label: '序号' },
|
||||
{ prop: 'clusterName', label: '集群/虚拟机' },
|
||||
{ prop: 'size', label: '占用大小' },
|
||||
{ prop: 'ip', label: 'IP' },
|
||||
{ prop: 'address', label: '地点' },
|
||||
// { prop: 'status', label: '状态', formatter: (row) => { return <span class={row.status === '异常' ? 'red' : 'nlue'}>{row.status}</span> } }
|
||||
{ prop: 'status', label: '状态', formatter: (row) => <span class='nlue'>正常</span> } // 后端wangqi建议先写死
|
||||
],
|
||||
tapTableData0: [],
|
||||
tapTableData1: [],
|
||||
diskfileList: [],
|
||||
fileList: [],
|
||||
clusterList: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.getList()
|
||||
this.getCount()
|
||||
getAvailableClusterList().then(e => {
|
||||
this.clusterList = e.data
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
currentChange(page) {
|
||||
this.page = page
|
||||
this.getList()
|
||||
},
|
||||
handleUploadSuccess() {
|
||||
this.$message.success('文件上传成功')
|
||||
this.dialogCreateVisible = false
|
||||
this.fileList = []
|
||||
this.getList()
|
||||
},
|
||||
handleUploadError() {
|
||||
this.$message.warning('上传失败')
|
||||
},
|
||||
handleCopy(text, event) {
|
||||
clip(text, event)
|
||||
},
|
||||
cancelUpload() {
|
||||
this.dialogCreateVisible = false
|
||||
this.selectedCluster = []
|
||||
this.clusterPath = {}
|
||||
},
|
||||
deleteFile(id) {
|
||||
this.$confirm('<img src=""><p>文件删除后将不可恢复,是否确认删除?</p>', '温馨提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确认',
|
||||
center: true,
|
||||
cancelButtonText: '取消'
|
||||
}).then(() => {
|
||||
deleteFile(id).then(e => {
|
||||
this.$message.success('删除成功')
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
downloadFile(row) {
|
||||
const a = document.createElement('a')
|
||||
a.href = row.url
|
||||
a.download = row.name // 下载文件的名字
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
},
|
||||
addFolder() {},
|
||||
downloadList() {},
|
||||
viewDetail(id) {
|
||||
this.$Api.getFileInfoById(id).then(res => {
|
||||
this.tapTableData0 = [
|
||||
{
|
||||
name: res.data.name,
|
||||
clusterName: res.data.clusterName,
|
||||
size: res.data.size,
|
||||
ip: res.data.ip,
|
||||
address: res.data.city,
|
||||
status: res.data.status === 1 ? '正常' : '异常'
|
||||
}
|
||||
]
|
||||
this.dialogDetailVisible = true
|
||||
})
|
||||
},
|
||||
submitUpload() {
|
||||
const form = new FormData()
|
||||
this.$refs.upload.uploadFiles.forEach((file, index) => {
|
||||
form.append(`file`, file.raw)
|
||||
})
|
||||
const obj = {}
|
||||
this.selectedCluster.forEach(e => {
|
||||
obj[e] = this.clusterPath[e] || ''
|
||||
})
|
||||
form.set('clusters', JSON.stringify(obj))
|
||||
form.set('label', this.activeName)
|
||||
this.submitLoading = true
|
||||
uploadFile(form).then(e => {
|
||||
if (e.code === 200) {
|
||||
this.$message.success('文件上传成功')
|
||||
this.$refs.multipleTable.getList()
|
||||
this.dialogCreateVisible = false
|
||||
this.submitLoading = false
|
||||
} else {
|
||||
this.submitLoading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.submitLoading = false
|
||||
})
|
||||
},
|
||||
getBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
let fileResult = ''
|
||||
reader.readAsDataURL(file)
|
||||
reader.onload = () => {
|
||||
fileResult = reader.result
|
||||
}
|
||||
reader.onerror = (error) => {
|
||||
reject(error)
|
||||
}
|
||||
reader.onloadend = () => {
|
||||
resolve(fileResult)
|
||||
}
|
||||
})
|
||||
},
|
||||
getCount() {
|
||||
getFileCount().then(e => {
|
||||
this.exhibitionArray[0].value = e.data?.totalFiles
|
||||
this.exhibitionArray[1].value = numberToStr(e.data?.totalSize - 0, 'B')
|
||||
})
|
||||
},
|
||||
// getList() {
|
||||
// getFileList({ }).then(e => {
|
||||
// this.diskfileList = e.lists
|
||||
// this.total = e.total
|
||||
// })
|
||||
// },
|
||||
deleteFunc(id) {
|
||||
},
|
||||
handleClick() {
|
||||
if (this.activeName === '1') {
|
||||
this.form = { env: 'python' }
|
||||
}
|
||||
},
|
||||
transBase64(code) {
|
||||
return Buffer.from(code).toString('base64')
|
||||
},
|
||||
getResult() {
|
||||
// this.dynamicData();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.select-option{
|
||||
padding: 20px;
|
||||
color: var(--buttonDivC);
|
||||
background: var(--listBtnColor);
|
||||
}
|
||||
.opr-group{
|
||||
color:#999999;
|
||||
svg{
|
||||
margin-right: 37px;
|
||||
cursor: pointer
|
||||
}
|
||||
.svg-icon{width:20px; height: 20px;}
|
||||
}
|
||||
.file-breadcrumb{
|
||||
padding: 17px 32px;
|
||||
.el-breadcrumb__item:last-child .el-breadcrumb__inner, .el-breadcrumb__item:last-child .el-breadcrumb__inner:hover, .el-breadcrumb__item:last-child .el-breadcrumb__inner a, .el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover{
|
||||
font-size: 16px!important;
|
||||
color: var(--buttonDivC);
|
||||
font-weight: 500!important;
|
||||
}
|
||||
.floatRight{
|
||||
text-align: right;
|
||||
float: right;
|
||||
font-size: 16px!important;
|
||||
color: var(--buttonDivC);
|
||||
font-weight: 500!important;
|
||||
}
|
||||
}
|
||||
.el-popper .qrcode-popover{
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
p{
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
.qrcode{
|
||||
margin: 24px auto;
|
||||
margin-top: 40px;
|
||||
width: 140px;
|
||||
padding: 10px;
|
||||
border: 1px solid #eeeeee;
|
||||
border-radius: 10px;
|
||||
}
|
||||
>span{
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
margin-bottom: 24px;
|
||||
color: #999999;
|
||||
}
|
||||
.el-button{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
.el-divider{
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
.upload-area{
|
||||
text-align: center;
|
||||
p{
|
||||
text-align: left;
|
||||
color: var(--buttonDivC);
|
||||
font-size: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.el-row--flex.is-justify-space-between{
|
||||
margin-top: 20px;
|
||||
}
|
||||
.upload-file{
|
||||
text-align: right;
|
||||
}
|
||||
.el-upload__tip{
|
||||
float: left;
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.el-upload{
|
||||
.el-button{
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.el-upload-list__item-name{
|
||||
text-align: left;
|
||||
}
|
||||
.el-radio{
|
||||
width: 100%;
|
||||
}
|
||||
>.el-button{
|
||||
margin: 100px 18px 10px 18px;
|
||||
}
|
||||
}
|
||||
.red{
|
||||
color: #D9001B;
|
||||
}
|
||||
.blue {
|
||||
color: #3182CE;
|
||||
}
|
||||
.tap-name{
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
background: #3182CE;
|
||||
border-radius: 2px;
|
||||
margin-bottom: 24px;
|
||||
padding: 0 27px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.add-pagination{
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,676 @@
|
|||
<template>
|
||||
<div class="UsabilityMonitor">
|
||||
<el-card>
|
||||
<Exhibition :data="exhibitionArray" :span="8" />
|
||||
</el-card>
|
||||
<el-row>
|
||||
<el-card>
|
||||
<el-row>
|
||||
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
|
||||
<el-tab-pane label="数据集" name="dataset" />
|
||||
<el-tab-pane label="镜像" name="image" />
|
||||
<el-tab-pane label="算法" name="code" />
|
||||
<el-tab-pane label="模型" name="model" />
|
||||
</el-tabs>
|
||||
<div class="select-option">
|
||||
<el-button class="opr-btn" size="middle" @click="createPackage">创建Package</el-button>
|
||||
</div>
|
||||
<!-- <List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale && activeName"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="allFileList"
|
||||
:pagination="false"
|
||||
tooltip-effect="dark"
|
||||
/> -->
|
||||
<el-row :gutter="20">
|
||||
<el-col v-for="(item,index) in allFileList" :key="index" :span="6">
|
||||
<el-card class="functionCard">
|
||||
<p class="title">{{ item.packageName }}</p>
|
||||
<p>{{ item.uploadPriority.type === 'specify' ? '指定集群模式' : '智能调度模式' }}</p>
|
||||
<p v-if="item.uploadPriority.type === 'specify'">亲和集群:{{ getClusterData(item.uploadedCluster) }}</p>
|
||||
<p v-else>优先选择:
|
||||
<span v-for="it in item.uploadPriority.priorities" :key="it.type">
|
||||
<el-tag
|
||||
v-for="tag in it.options"
|
||||
:key="tag"
|
||||
type="info"
|
||||
>{{ tag }}</el-tag>
|
||||
</span>
|
||||
</p>
|
||||
<div class="btn-group">
|
||||
<el-popconfirm
|
||||
confirm-button-text="好的"
|
||||
cancel-button-text="不用了"
|
||||
icon="el-icon-info"
|
||||
icon-color="red"
|
||||
title="确认删除此Package么?"
|
||||
@onConfirm="deleteItem(item.packageID)"
|
||||
>
|
||||
<el-button slot="reference" style="margin-right:10px">删除</el-button>
|
||||
</el-popconfirm>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="toFileList(item)"
|
||||
>打开</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<br>
|
||||
<div class="add-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
hide-on-single-page
|
||||
:current-page="page"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
:page-size="pageSize"
|
||||
:pager-count="5"
|
||||
@current-change="currentChange"
|
||||
/>
|
||||
</div>
|
||||
<el-dialog :visible.sync="dialogCreateVisible" :title="'创建' + tabName[activeName] + 'Package'" width="70%" @close="resetData">
|
||||
<div class="upload-area">
|
||||
<el-form ref="formData" :model="formData" :rules="rules">
|
||||
<el-form-item label="Packge名称" prop="name">
|
||||
<el-input
|
||||
v-model="formData.name"
|
||||
:max-length="200"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-tabs v-model="isScheduled" @tab-click="handleClick">
|
||||
<el-tab-pane label="智能调度模式" name="yes" />
|
||||
<el-tab-pane label="集群指定模式" name="no" />
|
||||
</el-tabs>
|
||||
<div v-if="isScheduled === 'yes'">
|
||||
<p>根据您所选择的标签偏好,系统将为您把文件调度至合适的存储服务</p>
|
||||
</div>
|
||||
<el-card v-if="isScheduled === 'yes'">
|
||||
<el-form-item label="优先选择" prop="bias">
|
||||
<el-checkbox-group v-model="formData.bias">
|
||||
<el-checkbox-button v-for="item in biasList" :key="item.itemValue" :label="item.itemText">{{ item.itemText }}</el-checkbox-button>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="地域选择" prop="region">
|
||||
<el-checkbox-group v-model="formData.region">
|
||||
<el-checkbox-button v-for="item in regionList" :key="item.itemValue" :label="item.itemText">{{ item.itemText }}</el-checkbox-button>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="计算类型选择" prop="chip">
|
||||
<el-checkbox-group v-model="formData.chip">
|
||||
<el-checkbox-button v-for="item in chipList" :key="item.itemValue" :label="item.itemText">{{ item.itemText }}</el-checkbox-button>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
<el-card v-if="isScheduled === 'no'">
|
||||
<el-row :gutter="20">
|
||||
<el-form-item label="集群选择" prop="selectedCluster">
|
||||
<el-card>
|
||||
<el-checkbox-group v-model="formData.selectedCluster" size="mini">
|
||||
<el-col v-for="item in clusterList" :key="item.id" :span="8">
|
||||
<el-checkbox :label="item.id" border>{{ item.name }}</el-checkbox>
|
||||
<!-- <el-input v-if="uploadType === 'online'" v-model="clusterPath[item.id]" placeholder="在线url填写" /> -->
|
||||
</el-col>
|
||||
</el-checkbox-group>
|
||||
</el-card>
|
||||
</el-form-item>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-form>
|
||||
<!-- <el-divider /> -->
|
||||
<div v-if="loading" class="progress" />
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="resetData">取消</el-button>
|
||||
<el-button type="primary" :disabled="submitLoading" @click="submitUpload">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog :visible.sync="dialogDetailVisible" title="存储文件详情" width="80%">
|
||||
<div>
|
||||
<!-- <div class="select-option" /> -->
|
||||
<div class="tap-name">
|
||||
存储文件名称:
|
||||
{{ tapTableData0.length > 0 ? tapTableData0[0].name : '' }}
|
||||
<!-- 条带名:/t1efne231_0 -->
|
||||
</div>
|
||||
<List
|
||||
ref="tapTable0"
|
||||
class="tapTable"
|
||||
:columns="tapTableColumns"
|
||||
:table-list-data="tapTableData0"
|
||||
:pagination="false"
|
||||
/>
|
||||
<!-- <div class="add-pagination">
|
||||
<el-pagination
|
||||
background
|
||||
:hide-on-single-page="false"
|
||||
:current-page="1"
|
||||
layout="total, prev, pager, next, jumper"
|
||||
:total="10"
|
||||
/>
|
||||
</div> -->
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import Exhibition from '@/components/Exhibition'
|
||||
import clip from '@/utils/clipboard'
|
||||
// import { numberToStr } from '@/utils/data-process'
|
||||
// import deletePng from '@/assets/images/exhibition/statusMonitor-2.png'
|
||||
import { getToken } from '@/utils/auth'
|
||||
// import { getAvailableClusterList } from '@/api/fileManagement/index'
|
||||
import { getClusterList } from '@/api/container/cluster'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { getDictItems, getDictByCode } from '@/api/common/setting'
|
||||
import { createPackage, getFileList, deletePackage } from '@/api/jcs/jcs'
|
||||
export default {
|
||||
components: {
|
||||
List,
|
||||
Exhibition
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
location: window.location.origin,
|
||||
activeName: 'dataset',
|
||||
tabName: {
|
||||
'dataset': '数据集',
|
||||
'image': '镜像',
|
||||
'code': '算法',
|
||||
'model': '模型'
|
||||
},
|
||||
currentFold: -1,
|
||||
foldList: [{
|
||||
id: -1,
|
||||
name: '全部文件'
|
||||
}],
|
||||
formData: {
|
||||
name: '',
|
||||
bias: [],
|
||||
region: [],
|
||||
chip: [],
|
||||
selectedCluster: []
|
||||
},
|
||||
page: 1,
|
||||
total: 0,
|
||||
pageSize: 10,
|
||||
uploadType: '',
|
||||
regionList: [],
|
||||
chipList: [],
|
||||
biasList: [],
|
||||
isScheduled: 'yes',
|
||||
dialogCreateVisible: false,
|
||||
dialogDetailVisible: false,
|
||||
submitLoading: false,
|
||||
token: getToken(),
|
||||
// clusterPath: {},
|
||||
exhibitionArray: [
|
||||
{
|
||||
name: '文件个数(个)',
|
||||
src: 'usabilityMonitor-1',
|
||||
value: '0'
|
||||
},
|
||||
{
|
||||
name: '文件总大小(GB)',
|
||||
src: 'usabilityMonitor-2',
|
||||
value: '0'
|
||||
}
|
||||
],
|
||||
tapTableColumns: [
|
||||
{ type: 'index', label: '序号' },
|
||||
{ prop: 'clusterName', label: '集群/虚拟机' },
|
||||
{ prop: 'size', label: '占用大小' },
|
||||
{ prop: 'ip', label: 'IP' },
|
||||
{ prop: 'address', label: '地点' },
|
||||
// { prop: 'status', label: '状态', formatter: (row) => { return <span class={row.status === '异常' ? 'red' : 'nlue'}>{row.status}</span> } }
|
||||
{ prop: 'status', label: '状态', formatter: (row) => <span class='nlue'>正常</span> } // 后端wangqi建议先写死
|
||||
],
|
||||
tapTableData0: [],
|
||||
tapTableData1: [],
|
||||
diskfileList: [],
|
||||
fileList: [],
|
||||
clusterList: [],
|
||||
loading: false,
|
||||
allFileList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
]),
|
||||
rules() {
|
||||
return {
|
||||
name: [
|
||||
{ required: true, message: this.$t('message.pleaseInput') }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeName(newValue, oldValue) {
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.getList()
|
||||
this.getCount()
|
||||
getClusterList({ 'storageSchedule': 1, pageSize: 1000, pageNum: 1 }).then(e => {
|
||||
this.clusterList = e?.data?.list || []
|
||||
})
|
||||
getDictByCode('preference-type-dict').then(res => {
|
||||
this.biasList = res.data?.list || []
|
||||
})
|
||||
getDictItems({ dictId: 1, pageNum: 1, pageSize: 999 }).then(res => {
|
||||
this.regionList = res.data?.list || []
|
||||
})
|
||||
getDictByCode('chip-type-dict').then(res => {
|
||||
this.chipList = res.data?.list || []
|
||||
})
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
toFileList(item) {
|
||||
this.$router.push({ path: '/fileManagement/fileList', query: { packageID: item.packageID, packageName: item.packageName, path: '/', type: this.activeName }})
|
||||
},
|
||||
getList() {
|
||||
const params = {
|
||||
'queryParams': {
|
||||
'dataType': this.activeName,
|
||||
'userID': this.userID,
|
||||
// "path": "/path",
|
||||
'packageID': -1,
|
||||
'CurrentPage': this.page,
|
||||
'pageSize': this.pageSize,
|
||||
'orderBy': 'name'
|
||||
}
|
||||
}
|
||||
getFileList(params).then(e => {
|
||||
this.total = e.data?.totalCount
|
||||
this.allFileList = e.data?.uploadedDatas || []
|
||||
})
|
||||
},
|
||||
getClusterData(cluster) {
|
||||
if (this.clusterList.length) {
|
||||
return cluster.map(e => {
|
||||
return this.clusterList.find(s => s.id === e.clusterID)?.name || ''
|
||||
}).filter(Boolean).join(',') || '-'
|
||||
} else {
|
||||
return '-'
|
||||
}
|
||||
},
|
||||
currentChange(page) {
|
||||
this.page = page
|
||||
this.getList()
|
||||
},
|
||||
intoFold(foldId, foldName, flag) {
|
||||
this.currentFold = foldId
|
||||
if (flag) {
|
||||
this.foldList = this.foldList.slice(0, this.foldList.findIndex(ar => ar.id === foldId))
|
||||
}
|
||||
this.foldList.push({ id: foldId, name: foldName })
|
||||
this.getList()
|
||||
},
|
||||
createPackage() {
|
||||
this.dialogCreateVisible = true
|
||||
},
|
||||
handleUploadSuccess() {
|
||||
this.$message.success('文件上传成功')
|
||||
this.dialogCreateVisible = false
|
||||
this.fileList = []
|
||||
this.getList()
|
||||
},
|
||||
handleUploadError() {
|
||||
this.$message.warning('上传失败')
|
||||
},
|
||||
handleCopy(text, event) {
|
||||
clip(text, event)
|
||||
},
|
||||
resetData() {
|
||||
this.formData = {
|
||||
name: '',
|
||||
bias: [],
|
||||
region: [],
|
||||
chip: [],
|
||||
selectedCluster: []
|
||||
}
|
||||
this.dialogCreateVisible = false
|
||||
this.submitLoading = false
|
||||
this.getList()
|
||||
},
|
||||
deleteItem(id) {
|
||||
this.$confirm('<img src=""><p>Package删除后将不可恢复,是否确认删除?</p>', '温馨提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '确认',
|
||||
center: true,
|
||||
cancelButtonText: '取消'
|
||||
}).then(() => {
|
||||
deletePackage({ userID: this.userID, packageID: id }).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
downloadFile(row) {
|
||||
const a = document.createElement('a')
|
||||
a.href = row.url
|
||||
a.download = row.name // 下载文件的名字
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
},
|
||||
downloadList() {},
|
||||
viewDetail(id) {
|
||||
this.$Api.getFileInfoById(id).then(res => {
|
||||
this.tapTableData0 = [
|
||||
{
|
||||
name: res.data.name,
|
||||
clusterName: res.data.clusterName,
|
||||
size: res.data.size,
|
||||
ip: res.data.ip,
|
||||
address: res.data.city,
|
||||
status: res.data.status === 1 ? '正常' : '异常'
|
||||
}
|
||||
]
|
||||
this.dialogDetailVisible = true
|
||||
})
|
||||
},
|
||||
submitUpload() {
|
||||
this.$refs.formData.validate((valid) => {
|
||||
if (valid) {
|
||||
this.submitLoading = true
|
||||
const FormDatas = {
|
||||
'userID': this.userID,
|
||||
'name': this.formData.name,
|
||||
'dataType': this.activeName
|
||||
}
|
||||
if (this.isScheduled === 'yes') {
|
||||
FormDatas.uploadPriority = {
|
||||
'type': 'preference',
|
||||
'priorities': [
|
||||
{
|
||||
'type': 'region',
|
||||
'options': this.formData.region
|
||||
},
|
||||
{
|
||||
'type': 'chip',
|
||||
'options': this.formData.chip
|
||||
},
|
||||
{
|
||||
'type': 'bias',
|
||||
'options': this.formData.bias
|
||||
}
|
||||
]
|
||||
}
|
||||
} else {
|
||||
FormDatas.uploadPriority = {
|
||||
'type': 'specify',
|
||||
'clusters': this.formData.selectedCluster
|
||||
}
|
||||
}
|
||||
createPackage(FormDatas).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.getList()
|
||||
this.resetData()
|
||||
this.dialogCreateVisible = false
|
||||
} else {
|
||||
this.submitLoading = false
|
||||
}
|
||||
}).catch(() => {
|
||||
this.submitLoading = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
getBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
let fileResult = ''
|
||||
reader.readAsDataURL(file)
|
||||
reader.onload = () => {
|
||||
fileResult = reader.result
|
||||
}
|
||||
reader.onerror = (error) => {
|
||||
reject(error)
|
||||
}
|
||||
reader.onloadend = () => {
|
||||
resolve(fileResult)
|
||||
}
|
||||
})
|
||||
},
|
||||
getCount() {
|
||||
// getFileCount().then(e => {
|
||||
// this.exhibitionArray[0].value = e.data?.totalFiles
|
||||
// this.exhibitionArray[1].value = numberToStr(e.data?.totalSize - 0, 'B')
|
||||
// })
|
||||
},
|
||||
// getList() {
|
||||
// getFileList({ }).then(e => {
|
||||
// this.diskfileList = e.lists
|
||||
// this.total = e.total
|
||||
// })
|
||||
// },
|
||||
deleteFunc(id) {
|
||||
},
|
||||
handleClick() {
|
||||
if (this.activeName === '1') {
|
||||
this.form = { env: 'python' }
|
||||
}
|
||||
},
|
||||
transBase64(code) {
|
||||
return Buffer.from(code).toString('base64')
|
||||
},
|
||||
getResult() {
|
||||
// this.dynamicData();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.folder-list{
|
||||
.fold-item{
|
||||
float: left;
|
||||
.arrow{
|
||||
margin: 0 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.progress{
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
margin: 25px 0;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
background-color: #ccdcff;
|
||||
}
|
||||
.progress::before{
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
background: #3182CE;
|
||||
}
|
||||
.progress::before{
|
||||
animation: progress 10s infinite;
|
||||
}
|
||||
@keyframes progress {
|
||||
to {
|
||||
width: 100%
|
||||
}
|
||||
}
|
||||
.select-option{
|
||||
padding: 20px;
|
||||
color: var(--buttonDivC);
|
||||
background: var(--listBtnColor);
|
||||
}
|
||||
.opr-group{
|
||||
color:#999999;
|
||||
svg{
|
||||
margin-right: 37px;
|
||||
cursor: pointer
|
||||
}
|
||||
.svg-icon{width:20px; height: 20px;}
|
||||
}
|
||||
.file-breadcrumb{
|
||||
padding: 17px 32px;
|
||||
.el-breadcrumb__item:last-child .el-breadcrumb__inner, .el-breadcrumb__item:last-child .el-breadcrumb__inner:hover, .el-breadcrumb__item:last-child .el-breadcrumb__inner a, .el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover{
|
||||
font-size: 16px!important;
|
||||
color: var(--buttonDivC);
|
||||
font-weight: 500!important;
|
||||
}
|
||||
.floatRight{
|
||||
text-align: right;
|
||||
float: right;
|
||||
font-size: 16px!important;
|
||||
color: var(--buttonDivC);
|
||||
font-weight: 500!important;
|
||||
}
|
||||
}
|
||||
.el-popper .qrcode-popover{
|
||||
padding: 12px;
|
||||
text-align: center;
|
||||
p{
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
}
|
||||
.qrcode{
|
||||
margin: 24px auto;
|
||||
margin-top: 40px;
|
||||
width: 140px;
|
||||
padding: 10px;
|
||||
border: 1px solid #eeeeee;
|
||||
border-radius: 10px;
|
||||
}
|
||||
>span{
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
margin-bottom: 24px;
|
||||
color: #999999;
|
||||
}
|
||||
.el-button{
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
.el-divider{
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
.upload-area{
|
||||
text-align: center;
|
||||
p{
|
||||
text-align: left;
|
||||
color: var(--buttonDivC);
|
||||
font-size: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.el-row--flex.is-justify-space-between{
|
||||
margin-top: 20px;
|
||||
}
|
||||
.upload-file{
|
||||
text-align: right;
|
||||
}
|
||||
.el-upload__tip{
|
||||
float: left;
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.el-upload{
|
||||
.el-button{
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
.el-upload-list__item-name{
|
||||
text-align: left;
|
||||
color: #ffffff;
|
||||
}
|
||||
.el-radio{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.red{
|
||||
color: #D9001B;
|
||||
}
|
||||
.blue {
|
||||
color: #3182CE;
|
||||
}
|
||||
.tap-name{
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
background: #3182CE;
|
||||
border-radius: 2px;
|
||||
margin-bottom: 24px;
|
||||
padding: 0 27px;
|
||||
color: #ffffff;
|
||||
}
|
||||
.add-pagination{
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.functionCard{
|
||||
|
||||
margin: 0px auto;
|
||||
margin-top: 20px;
|
||||
.el-card__body{
|
||||
padding:0;
|
||||
padding-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
p{
|
||||
margin: 10px 30px;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
position: relative;
|
||||
text-indent: 1em;
|
||||
}
|
||||
p:before{
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: #2FB4AA;
|
||||
border-radius: 50%;
|
||||
top: 5px;
|
||||
left: 0em;
|
||||
}
|
||||
.title{
|
||||
margin:20px 27px;
|
||||
// margin-bottom: 10px;
|
||||
font-size: 18px;
|
||||
text-indent: 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.title:before{
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.el-button--text{
|
||||
line-height: 1.1rem;
|
||||
}
|
||||
|
||||
.el-button{
|
||||
margin:10px;
|
||||
border:1px solid #468EFC ;
|
||||
border-radius: 0;
|
||||
}
|
||||
.el-button--default{
|
||||
color: #468EFC;
|
||||
}
|
||||
.insideFloatRight {
|
||||
margin: 0;
|
||||
padding:0;
|
||||
float: right;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,144 @@
|
|||
<template>
|
||||
<div class="podInfo">
|
||||
<el-card class="basicInfo">
|
||||
<Exhibition :data="exhibitionArray" :span="8" />
|
||||
</el-card>
|
||||
<el-card>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="dataList"
|
||||
list-key="data"
|
||||
tooltip-effect="dark"
|
||||
>
|
||||
<template v-slot:filterBtns>
|
||||
<!-- <el-button size="medium" type="primary" @click="handelAdd">{{ $t('message.create') }}</el-button> -->
|
||||
</template>
|
||||
</List>
|
||||
</el-card>
|
||||
<bind-dataset v-model="addFormVisible" data-type="image" :is-edit="isEdit" :data="updateData" @get-list="getList" />
|
||||
<el-dialog v-if="dialogCertVisible" :close-on-click-modal="false" width="50%" title="镜像信息" :visible.sync="dialogCertVisible">
|
||||
<FormData
|
||||
v-if="JSON.stringify(imageData) !== '{}'"
|
||||
:columns="1"
|
||||
:data="imageData"
|
||||
:data-map="imageMap"
|
||||
/>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FormData } from '@/components/FormData'
|
||||
import List from '@/components/list'
|
||||
import Exhibition from '@/components/Exhibition'
|
||||
import { getBindingList, deleteBinding, queryImages } from '@/api/jcs/jcs'
|
||||
import bindDataset from '../datasetManagement/addForm'
|
||||
import { getClusterList } from '@/api/container/cluster'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: { Exhibition, List, bindDataset, FormData },
|
||||
data() {
|
||||
return {
|
||||
imageData: {},
|
||||
imageMap: {
|
||||
id: 'id',
|
||||
name: '名称',
|
||||
clusterID: '集群ID',
|
||||
clusterImageID: '镜像ID',
|
||||
cardType: '卡类型'
|
||||
},
|
||||
dialogCertVisible: false,
|
||||
exhibitionArray: [
|
||||
{
|
||||
name: '镜像个数',
|
||||
src: 'image-1',
|
||||
value: '0'
|
||||
}
|
||||
],
|
||||
isEdit: false,
|
||||
dataList: [],
|
||||
updateData: {},
|
||||
addFormVisible: false,
|
||||
clusterList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
]),
|
||||
columns() {
|
||||
return [
|
||||
{ prop: 'name', label: this.$t('page.imageName'), formatter: (row) => row.info.name },
|
||||
{ prop: 'createTime', label: this.$t('page.creationTime'), sortable: true, formatter: (row) => {
|
||||
return <div>{new Date(row.createTime).toLocaleString()}</div>
|
||||
} },
|
||||
{ prop: 'clusters', label: this.$t('page.clusterIn'), formatter: (row) => this.getClusterData(row.info.clusterIDs) },
|
||||
{ prop: 'more', label: this.$t('page.more'), width: 160, formatter: (row) => {
|
||||
return <el-dropdown>
|
||||
<el-button className='el-dropdown-link' size='mini' icon='el-icon-more' circle>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => { this.getDetail(row.ID) }}> <el-dropdown-item> {this.$t('message.detail')}</el-dropdown-item> </span>
|
||||
<span onClick={() => { this.deleteItem(row) }}> <el-dropdown-item> {this.$t('page.delete')} </el-dropdown-item> </span>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
} }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getList()
|
||||
getClusterList({ 'storageSchedule': 1, pageSize: 1000, pageNum: 1 }).then(e => {
|
||||
this.clusterList = e?.data?.list || []
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getDetail(id) {
|
||||
queryImages({ ids: [id] }).then(e => {
|
||||
this.dialogCertVisible = true
|
||||
this.imageData = e.data?.images?.[0] || {}
|
||||
})
|
||||
},
|
||||
getClusterData(cluster) {
|
||||
if (this.clusterList.length) {
|
||||
return cluster?.map(e => {
|
||||
return this.clusterList.find(s => s.id === e)?.name || ''
|
||||
}).filter(Boolean).join(',') || '-'
|
||||
} else {
|
||||
return '-'
|
||||
}
|
||||
},
|
||||
getList() {
|
||||
getBindingList({ dataType: 'image', param: { userID: this.userID, bindingID: -1, type: 'private' }}).then(e => {
|
||||
this.dataList = e?.data?.datas || []
|
||||
this.exhibitionArray[0].value = e?.data?.datas?.length || 0
|
||||
})
|
||||
},
|
||||
handelAdd() {
|
||||
this.addFormVisible = true
|
||||
},
|
||||
deleteItem(row) {
|
||||
this.$confirm('确认删除么?', '提示', {
|
||||
confirmButtonText: this.$t('message.confirm'),
|
||||
cancelButtonText: this.$t('message.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteBinding({ packageIDs: [row.info.packageID], bindingIDs: [row.ID] }).then((e) => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
|
@ -0,0 +1,146 @@
|
|||
<template>
|
||||
<div class="podInfo">
|
||||
<el-card class="basicInfo">
|
||||
<Exhibition :data="exhibitionArray" :span="8" />
|
||||
</el-card>
|
||||
<el-card>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="dataList"
|
||||
list-key="data"
|
||||
tooltip-effect="dark"
|
||||
>
|
||||
<template v-slot:filterBtns>
|
||||
<el-button size="medium" type="primary" @click="applyListVisible = true">{{ $t('page.applyList') }}</el-button>
|
||||
<el-button size="medium" type="primary" @click="handelAdd">{{ $t('message.create') }}</el-button>
|
||||
</template>
|
||||
</List>
|
||||
</el-card>
|
||||
<bind-dataset v-model="addFormVisible" data-type="model" :is-edit="isEdit" :data="updateData" @get-list="getList" />
|
||||
<apply-list v-model="applyListVisible" data-type="model" />
|
||||
<el-dialog :close-on-click-modal="false" width="50%" title="访问权限设置" :visible.sync="dialogSettingVisible">
|
||||
<el-radio-group v-model="radioValue">
|
||||
<el-radio label="private">仅本用户可访问</el-radio>
|
||||
<el-radio label="apply">申请后可访问</el-radio>
|
||||
<el-radio label="public">公开所有可访问</el-radio>
|
||||
</el-radio-group>
|
||||
<el-button type="primary" @click="authSetting">确定</el-button>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import Exhibition from '@/components/Exhibition'
|
||||
import { getBindingList, deleteBinding, accessAuthSetting } from '@/api/jcs/jcs'
|
||||
import bindDataset from '../datasetManagement/addForm'
|
||||
import { getClusterList } from '@/api/container/cluster'
|
||||
import applyList from '../datasetManagement/applyList'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
components: { Exhibition, List, bindDataset, applyList },
|
||||
data() {
|
||||
return {
|
||||
exhibitionArray: [
|
||||
{
|
||||
name: '模型个数',
|
||||
src: 'model-1',
|
||||
value: '0'
|
||||
}
|
||||
],
|
||||
dialogSettingVisible: false,
|
||||
currentID: '',
|
||||
isEdit: false,
|
||||
dataList: [],
|
||||
updateData: {},
|
||||
addFormVisible: false,
|
||||
clusterList: [],
|
||||
radioValue: 'private',
|
||||
applyListVisible: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
]),
|
||||
columns() {
|
||||
return [
|
||||
{ prop: 'name', label: this.$t('page.modelName'), formatter: (row) => row.info.name },
|
||||
{ prop: 'createTime', label: this.$t('page.creationTime'), sortable: true, formatter: (row) => {
|
||||
return <div>{new Date(row.createTime).toLocaleString()}</div>
|
||||
} },
|
||||
{ prop: 'clusters', label: this.$t('page.clusterIn'), formatter: (row) => this.getClusterData(row.info.clusterIDs) },
|
||||
{ prop: 'modelType', label: '模型类型', formatter: (row) => row.info.modelType },
|
||||
{ prop: 'status', label: this.$t('page.status'), formatter: (row) => row.accessLevel === 'public' ? '公开' : row.accessLevel === 'apply' ? '可申请' : '私有' },
|
||||
{ prop: 'more', label: this.$t('page.more'), width: 160, formatter: (row) => {
|
||||
return <el-dropdown>
|
||||
<el-button className='el-dropdown-link' size='mini' icon='el-icon-more' circle>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => { this.radioValue = row.accessLevel; this.dialogSettingVisible = true; this.currentID = row.ID }}> <el-dropdown-item> {this.$t('page.authSetting')}</el-dropdown-item> </span>
|
||||
<span onClick={() => { this.deleteItem(row) }}> <el-dropdown-item> {this.$t('page.delete')} </el-dropdown-item> </span>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
} }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getList()
|
||||
getClusterList({ 'storageSchedule': 1, pageSize: 1000, pageNum: 1 }).then(e => {
|
||||
this.clusterList = e?.data?.list || []
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
authSetting() {
|
||||
accessAuthSetting({ ID: this.currentID, level: this.radioValue }).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('设置成功')
|
||||
this.dialogSettingVisible = false
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
},
|
||||
getClusterData(cluster) {
|
||||
if (this.clusterList.length) {
|
||||
return cluster?.map(e => {
|
||||
return this.clusterList.find(s => s.id === e)?.name || ''
|
||||
}).filter(Boolean).join(',') || '-'
|
||||
} else {
|
||||
return '-'
|
||||
}
|
||||
},
|
||||
getList() {
|
||||
getBindingList({ dataType: 'model', param: { userID: this.userID, bindingID: -1, type: 'private' }}).then(e => {
|
||||
this.dataList = e?.data?.datas || []
|
||||
this.exhibitionArray[0].value = e?.data?.datas?.length || 0
|
||||
})
|
||||
},
|
||||
handelAdd() {
|
||||
this.addFormVisible = true
|
||||
},
|
||||
deleteItem(row) {
|
||||
this.$confirm('确认删除么?', '提示', {
|
||||
confirmButtonText: this.$t('message.confirm'),
|
||||
cancelButtonText: this.$t('message.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteBinding({ packageIDs: [row.info.packageID], bindingIDs: [row.ID] }).then((e) => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('删除成功')
|
||||
this.getList()
|
||||
}
|
||||
})
|
||||
}).catch(() => {
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
|
@ -0,0 +1,335 @@
|
|||
<template>
|
||||
<div class="login-container">
|
||||
<div class="header">
|
||||
<!-- <img src="@/assets/AI4M-logo.png">{{ $t("page.title") }} | 注册 -->
|
||||
</div>
|
||||
<div class="manufacturer">
|
||||
<a class="login-btn" href="/login">登录</a>
|
||||
<el-form
|
||||
ref="registerForm"
|
||||
:model="loginForm"
|
||||
:rules="loginRules"
|
||||
class="register-form"
|
||||
autocomplete="on"
|
||||
label-position="left"
|
||||
label-width="auto"
|
||||
>
|
||||
<div class="title-container"> 注册</div>
|
||||
<el-form-item prop="username" label="名称">
|
||||
<el-input
|
||||
ref="username"
|
||||
v-model="loginForm.username"
|
||||
placeholder="请输入账号"
|
||||
name="username"
|
||||
type="text"
|
||||
autocomplete="new-username"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="nickName" label="昵称">
|
||||
<el-input
|
||||
v-model="loginForm.nickName"
|
||||
placeholder="请输入昵称"
|
||||
name="nickName"
|
||||
type="text"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password" label="密码">
|
||||
<el-input
|
||||
:key="passwordType"
|
||||
ref="password"
|
||||
v-model="loginForm.password"
|
||||
:type="passwordType"
|
||||
placeholder="请输入密码"
|
||||
name="password"
|
||||
autocomplete="new-password"
|
||||
@keyup.native="checkCapslock"
|
||||
@blur="capsTooltip = false"
|
||||
@keyup.enter.native="handleRegister"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="passwordR" label="密码">
|
||||
<el-input
|
||||
:key="passwordType"
|
||||
ref="passwordR"
|
||||
v-model="loginForm.passwordR"
|
||||
:type="passwordType"
|
||||
placeholder="请再次输入密码"
|
||||
name="passwordR"
|
||||
autocomplete="new-password"
|
||||
@keyup.native="checkCapslock"
|
||||
@blur="capsTooltip = false"
|
||||
@keyup.enter.native="handleRegister"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="bcosPublicKey" label="公钥">
|
||||
<el-input
|
||||
v-model="loginForm.bcosPublicKey"
|
||||
name="bcosPublicKey"
|
||||
type="text"
|
||||
placeholder="请输入公钥"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="bcosAccountAddress" label="地址">
|
||||
<el-input
|
||||
v-model="loginForm.bcosAccountAddress"
|
||||
name="bcosAccountAddress"
|
||||
placeholder="请输入链上账户地址"
|
||||
type="text"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-button
|
||||
:loading="loading"
|
||||
style="width:100%;margin-top: 2vh;margin-bottom:30px;"
|
||||
@click.native.prevent="handleRegister"
|
||||
>注册</el-button>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-dialog
|
||||
:visible.sync="successVisible"
|
||||
width="40%"
|
||||
class="successModel"
|
||||
center
|
||||
>
|
||||
<img style="height: 28vh;" src="../../assets/images/register_success.png">
|
||||
<h2>注册成功!</h2>
|
||||
<div v-if="JSON.stringify(info) !=='{}'">注意:请用户在当前页面下载并妥善保存公钥、私钥、账户地址平台不会保存用户相关信息,关闭当前后用户将无法再次获取。</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button v-if="JSON.stringify(info) !=='{}'" @click="downloadCodeAsFile">下载文件</el-button>
|
||||
<el-button type="primary" @click="$router.push({ path: '/login' })">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createAdmin } from '@/api/authority/permissionManagement'
|
||||
import { registerAdmin } from '@/api/jcs/jcs'
|
||||
|
||||
export default {
|
||||
name: 'Register',
|
||||
data() {
|
||||
return {
|
||||
successVisible: false,
|
||||
loginForm: {
|
||||
id: null,
|
||||
username: null,
|
||||
password: null,
|
||||
nickName: null,
|
||||
email: null,
|
||||
note: null,
|
||||
status: 1
|
||||
},
|
||||
loginRules: {
|
||||
username: [
|
||||
{ required: true, trigger: 'blur', message: '请输入用户名' }
|
||||
],
|
||||
nickName: [{ required: true, trigger: 'blur', message: '请输入昵称' }],
|
||||
password: [{ required: true, trigger: 'blur', message: '请输入密码' }],
|
||||
passwordR: [
|
||||
{ required: true, trigger: 'blur', message: '请再次输入密码' }
|
||||
],
|
||||
email: [
|
||||
{
|
||||
validator: this.checkEmail,
|
||||
trigger: 'blur'
|
||||
}
|
||||
]
|
||||
},
|
||||
rememberMe: false,
|
||||
passwordType: 'password',
|
||||
capsTooltip: false,
|
||||
loading: false,
|
||||
showDialog: false,
|
||||
redirect: undefined,
|
||||
otherQuery: {},
|
||||
info: {}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
handler(route) {
|
||||
const { query } = route
|
||||
if (query) {
|
||||
this.redirect = query.redirect
|
||||
// this.otherQuery = this.getOtherQuery(query);
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$refs.username.focus()
|
||||
},
|
||||
destroyed() {
|
||||
// window.removeEventListener('storage', this.afterQRScan)
|
||||
},
|
||||
methods: {
|
||||
downloadCodeAsFile() {
|
||||
const blob = new Blob([JSON.stringify(this.info)], { type: 'text/plain' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = '用户信息.txt'
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
},
|
||||
checkEmail(rule, value, callback) {
|
||||
if (
|
||||
value &&
|
||||
!value.match(
|
||||
/^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$/
|
||||
)
|
||||
) {
|
||||
callback(new Error('请输入正确的邮箱'))
|
||||
}
|
||||
callback()
|
||||
},
|
||||
checkCapslock(e) {
|
||||
const { key } = e
|
||||
this.capsTooltip = key && key.length === 1 && key >= 'A' && key <= 'Z'
|
||||
},
|
||||
handleRegister() {
|
||||
this.$refs.registerForm.validate(valid => {
|
||||
if (valid) {
|
||||
const { password, passwordR } = this.loginForm
|
||||
if (password === passwordR) {
|
||||
createAdmin(this.loginForm).then(res => {
|
||||
if (res) {
|
||||
registerAdmin({ ssoID: res.data.id, userName: res.data.username }).then(res => {})
|
||||
if (res.data?.bcosAccountAddress) {
|
||||
this.info = {
|
||||
bcosAccountAddress: res.data.bcosAccountAddress,
|
||||
bcosPrivateKey: res.data.bcosPrivateKey,
|
||||
bcosPublicKey: res.data.bcosPublicKey
|
||||
}
|
||||
}
|
||||
this.successVisible = true
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$message({
|
||||
message: '两次输入密码不一致!',
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.login-container {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
background-color: var(--loginBgC);
|
||||
background: url('../../assets/images/login_bg.png') white center no-repeat;
|
||||
background-size: cover;
|
||||
}
|
||||
::v-deep {
|
||||
.el-form-item__label{
|
||||
line-height: 3.2rem ;
|
||||
padding: 0 2rem;
|
||||
background-color: rgba(87, 149, 157, 0.5);
|
||||
position: relative;
|
||||
&::before{
|
||||
position: absolute;
|
||||
left: 4.5rem;
|
||||
top: 0.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.header{
|
||||
display: flex;
|
||||
margin: 3rem;
|
||||
font-size: 1.88rem;
|
||||
line-height: 3rem;
|
||||
img{
|
||||
width:auto;
|
||||
height: 3.2rem;
|
||||
margin-right: 2vh;
|
||||
}
|
||||
}
|
||||
.ai4mDark .el-button {
|
||||
padding: 1.2rem 1.25rem;
|
||||
border-radius: 0;
|
||||
}
|
||||
.manufacturer{
|
||||
width: 66vh;
|
||||
height: 82vh;
|
||||
box-sizing: border-box;
|
||||
padding: 7rem 5rem;
|
||||
text-align: left;
|
||||
position: absolute;
|
||||
background: url('../../assets/images/register_input.png') center no-repeat;
|
||||
background-size: contain;
|
||||
right: calc(50vw - 33vh);
|
||||
top: 10vh;
|
||||
.login-btn{
|
||||
position: absolute;
|
||||
font-size: 1.2rem;
|
||||
top: 9.5vh;
|
||||
right: 4vh;
|
||||
z-index: 3;
|
||||
}
|
||||
&::after{
|
||||
content: '';
|
||||
width: 11vh;
|
||||
height: 11vh;
|
||||
display: block;
|
||||
position: absolute;
|
||||
background: url(../../assets/images/login-btn.png) no-repeat;
|
||||
background-size: auto 100%;
|
||||
background-position: center;
|
||||
top: 7vh;
|
||||
right: 3vh;
|
||||
z-index: 2;
|
||||
}
|
||||
::v-deep{
|
||||
.el-input__inner {
|
||||
line-height: 3.2rem !important;
|
||||
height: 3.2rem !important;
|
||||
border-radius: 0;
|
||||
padding: 0 0.9375rem;
|
||||
background: #A0BDEF;
|
||||
font-size: 1.1rem !important;
|
||||
}
|
||||
.el-button {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
.el-input__inner {
|
||||
background: rgba(87, 149, 157, 0.5);
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
.title-container{
|
||||
font-size: 1.5rem;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
margin-bottom: 4.2vh;
|
||||
}
|
||||
::v-deep{
|
||||
.el-button--default {
|
||||
background: rgb(0, 167, 186);
|
||||
border-color: #00A6BAFF;
|
||||
}
|
||||
.el-button:hover, .el-button:focus {
|
||||
color: white;
|
||||
border-color: rgb(0, 186, 186);
|
||||
background-color: rgb(0, 186, 186);
|
||||
}
|
||||
}
|
||||
}
|
||||
.successModel{
|
||||
::v-deep{
|
||||
.el-dialog--center .el-dialog__body{
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -3,23 +3,23 @@
|
|||
<el-card>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="listData"
|
||||
:pagination="true"
|
||||
:pagination-auto="true"
|
||||
row-key="id"
|
||||
:default-sort="{prop: 'sort', order: 'ascending'}"
|
||||
tooltip-effect="dark"
|
||||
>
|
||||
<template v-slot:filterBtns>
|
||||
<el-button size="medium" type="primary" @click="handleAdd"> {{ $t('message.create') }} </el-button>
|
||||
<el-button size="medium" type="primary" @click="handleAdd">创建</el-button>
|
||||
<el-button v-if="showBtn" size="medium" type="info" @click="goBack">返回上级菜单</el-button>
|
||||
</template>
|
||||
</List>
|
||||
</el-card>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
:title="isEdit? $t('permission.editMenu'): $t('permission.addMenu')"
|
||||
:title="isEdit?'编辑菜单':'添加菜单'"
|
||||
:visible.sync="dialogVisible"
|
||||
width="50%"
|
||||
>
|
||||
|
@ -27,81 +27,40 @@
|
|||
ref="menuFrom"
|
||||
:model="menu"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
label-width="150px"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="parentId" :label="$t('permission.fatherNode')">
|
||||
<el-cascader
|
||||
ref="cascader"
|
||||
v-model="menu.parentId"
|
||||
style="width: 100%;"
|
||||
class="cascader-box"
|
||||
:options="selectMenuList"
|
||||
:props="{ value: 'id', label: 'title', checkStrictly: true, expandTrigger: 'hover' }"
|
||||
:show-all-levels="false"
|
||||
clearable
|
||||
@change="handleCascader"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('permission.menuName')" prop="title"> <el-input v-model="menu.title" /> </el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('permission.routerName')" prop="name"> <el-input v-model="menu.name" /> </el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('permission.router')" prop="path"> <el-input v-model="menu.path" /> </el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('permission.redirect')" prop="redirect"> <el-input v-model="menu.redirect" /> </el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item :label="$t('permission.componentPath')" prop="component"> <el-input v-model="menu.component" /> </el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="sort" :label="$t('permission.sort')">
|
||||
<el-input-number v-model="menu.sort" :min="1" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="status" :label="$t('permission.isShow')">
|
||||
<el-radio-group v-model="menu.status">
|
||||
<el-radio :label="true"> {{ $t('permission.yes') }} </el-radio>
|
||||
<el-radio :label="false"> {{ $t('permission.no') }} </el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!-- <el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="icon" label="图标:">
|
||||
<el-radio-group v-model="menu.icon">
|
||||
<el-radio :label="0">是</el-radio>
|
||||
<el-radio :label="1">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="固定:">
|
||||
<el-radio-group v-model="menu.hidden">
|
||||
<el-radio :label="0">是</el-radio>
|
||||
<el-radio :label="1">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row> -->
|
||||
<el-form-item label="菜单名称:" prop="title">
|
||||
<el-input v-model="menu.title" />
|
||||
</el-form-item>
|
||||
<el-form-item label="上级菜单:">
|
||||
<el-select
|
||||
v-model="menu.parentId"
|
||||
placeholder="请选择菜单"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in selectMenuList"
|
||||
:key="item.id"
|
||||
:label="item.title"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="前端名称:" prop="name">
|
||||
<el-input v-model="menu.name" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否显示:">
|
||||
<el-radio-group v-model="menu.hidden">
|
||||
<el-radio :label="0">是</el-radio>
|
||||
<el-radio :label="1">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="排序:">
|
||||
<el-input v-model="menu.sort" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button size="small" @click="dialogVisible = false">{{ $t("message.cancel") }}</el-button>
|
||||
<el-button type="primary" size="small" @click="handleDialogConfirm()">{{ $t("message.confirm") }}</el-button>
|
||||
<el-button size="small" @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" size="small" @click="handleDialogConfirm()">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
@ -109,19 +68,17 @@
|
|||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import { deleteMenu, getUserMenus, createMenu, updateMenu } from '@/api/authority/menu'
|
||||
import { deleteMenu, getMenuList, createMenu, updateMenu, getMenu, updateHidden } from '@/api/authority/permissionManagement'
|
||||
|
||||
// import { newEval } from '@/utils'
|
||||
import moment from 'moment'
|
||||
const defaultMenu = {
|
||||
'parentId': [0],
|
||||
'name': '',
|
||||
'path': '',
|
||||
'redirect': '',
|
||||
'component': '',
|
||||
'sort': null,
|
||||
'title': '',
|
||||
'icon': '',
|
||||
'status': true,
|
||||
'defaultMenu': false
|
||||
title: '',
|
||||
parentId: 0,
|
||||
name: '',
|
||||
icon: '',
|
||||
hidden: 0,
|
||||
sort: 0
|
||||
}
|
||||
export default {
|
||||
components: { List },
|
||||
|
@ -131,64 +88,111 @@ export default {
|
|||
dialogVisible: false,
|
||||
menu: Object.assign({}, defaultMenu),
|
||||
isEdit: false,
|
||||
selectMenuList: []
|
||||
selectMenuList: [],
|
||||
listQuery: {
|
||||
pageNum: 1,
|
||||
pageSize: 999
|
||||
},
|
||||
parentId: 0,
|
||||
columns: [
|
||||
{ prop: 'id', label: '编号', sortable: true },
|
||||
{ prop: 'title', label: '菜单名称', sortable: true },
|
||||
{ prop: 'level', label: '菜单级数', sortable: true, formatter: (row, index) => {
|
||||
if (row.level === 0) {
|
||||
return '一级'
|
||||
} else if (row.level === 1) {
|
||||
return '二级'
|
||||
}
|
||||
} },
|
||||
{ prop: 'name', label: '前端名称', sortable: true },
|
||||
{ prop: 'hidden', label: '是否显示', formatter: (row, index) => {
|
||||
return <el-switch
|
||||
onChange={() => this.handleHiddenChange(index, row)}
|
||||
activeValue={0}
|
||||
inactiveValue={1}
|
||||
value={row.hidden}>
|
||||
</el-switch>
|
||||
} },
|
||||
{ prop: 'sort', label: '排序', sortable: true },
|
||||
{ prop: 'level', label: '设置', formatter: (row, index) => {
|
||||
return <el-button
|
||||
size='mini'
|
||||
type='text'
|
||||
disabled={row.level !== 0}
|
||||
onClick={() => this.handleShowNextLevel(index, row)}>查看下级
|
||||
</el-button>
|
||||
} },
|
||||
{
|
||||
prop: 'more', label: '更多操作', formatter: (row, index) => {
|
||||
return <div>
|
||||
<el-button type='text' onClick={() => this.handleUpdate(index, row)}> 编辑 </el-button>
|
||||
<el-button type='text' onClick={() => this.handleDelete(index, row)}> 删除 </el-button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
],
|
||||
rules: {
|
||||
title: [
|
||||
{ required: true, message: '请输入菜单名称', trigger: 'blur' },
|
||||
{ min: 2, max: 140, message: '长度在 2 到 140 个字符', trigger: 'blur' }
|
||||
],
|
||||
name: [
|
||||
{ required: true, message: '请输入前端名称', trigger: 'blur' },
|
||||
{ min: 2, max: 140, message: '长度在 2 到 140 个字符', trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
columns() {
|
||||
return [
|
||||
{ prop: 'id', label: 'ID' },
|
||||
{ prop: 'parentId', label: this.$t('permission.fatherNode') },
|
||||
{ prop: 'title', label: this.$t('permission.menuName') },
|
||||
{ prop: 'path', label: this.$t('permission.routerName') },
|
||||
// { prop: 'redirect', label: '重定向 ' },
|
||||
{ prop: 'status', label: this.$t('permission.isShow'), formatter: (row, index) => {
|
||||
return row.status === true ? <el-tag type='success'>{this.$t('permission.show')}</el-tag> : <el-tag type='warning'>{this.$t('permission.hide')}</el-tag>
|
||||
} },
|
||||
{ prop: 'sort', label: this.$t('permission.sort'), sortable: true },
|
||||
{ prop: 'name', label: this.$t('permission.routerName') },
|
||||
{
|
||||
prop: 'more', label: this.$t('page.more'), formatter: (row, index) => {
|
||||
return <el-dropdown>
|
||||
<el-button size='mini' className='el-dropdown-link' icon='el-icon-more' circle>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => this.handleUpdate(index, row)}> <el-dropdown-item><i class='el-icon-edit'></i> {this.$t('page.edit')} </el-dropdown-item> </span>
|
||||
<span onClick={() => this.handleDelete(index, row)}> <el-dropdown-item divided><i class='el-icon-delete'></i> { this.$t('message.delete') } </el-dropdown-item> </span>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
parentId: [{ required: true, message: this.$t('message.pleaseChoose'), trigger: 'change' }],
|
||||
path: [{ required: true, message: this.$t('message.pleaseInput'), trigger: 'blur' }],
|
||||
name: [{ required: true, message: this.$t('message.pleaseInput'), trigger: 'blur' }],
|
||||
title: [{ required: true, message: this.$t('message.pleaseInput'), trigger: 'blur' }]
|
||||
}
|
||||
showBtn() {
|
||||
return this.$route.query.parentId
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route(route) {
|
||||
this.resetParentId()
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.resetParentId()
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$router.go(-1)
|
||||
},
|
||||
getList() {
|
||||
getUserMenus().then(e => {
|
||||
this.listData = e.data
|
||||
this.selectMenuList = [].concat(e.data)
|
||||
this.selectMenuList.unshift({ id: '0', title: this.$t('permission.root') })
|
||||
getMenuList(this.parentId, { pageNum: this.listQuery.pageNum, pageSize: this.listQuery.pageSize }).then(e => {
|
||||
this.listData = e.data.list
|
||||
this.selectMenuList = [].concat(e.data.list)
|
||||
this.selectMenuList.unshift({ id: 0, title: '无上级菜单' })
|
||||
}).catch(e => {
|
||||
})
|
||||
},
|
||||
handleCascader(val) {
|
||||
this.menu.parentId = val
|
||||
resetParentId() {
|
||||
this.listQuery.pageNum = 1
|
||||
if (this.$route.query.parentId != null) {
|
||||
this.parentId = this.$route.query.parentId
|
||||
} else {
|
||||
this.parentId = 0
|
||||
}
|
||||
},
|
||||
formatDate(t) {
|
||||
return moment(t).local().format('YYYY-MM-DD hh:mm:ss')
|
||||
},
|
||||
handleShowNextLevel(index, row) {
|
||||
this.$router.push({ path: '/permissionManagement/menuList', query: { parentId: row.id }})
|
||||
},
|
||||
handleHiddenChange(index, row) {
|
||||
updateHidden(row.id, { hidden: !row.hidden ? 0 : 1 }).then(response => {
|
||||
this.$message({
|
||||
message: '修改成功',
|
||||
type: 'success',
|
||||
duration: 1000
|
||||
})
|
||||
this.getList()
|
||||
})
|
||||
},
|
||||
handleAdd() {
|
||||
this.dialogVisible = true
|
||||
|
@ -196,44 +200,66 @@ export default {
|
|||
this.menu = Object.assign({}, defaultMenu)
|
||||
},
|
||||
handleDelete(index, row) {
|
||||
this.$confirm(this.$t('permission.wantDelete'), this.$t('page.info'), {
|
||||
confirmButtonText: this.$t('message.confirm'),
|
||||
cancelButtonText: this.$t('message.cancel'),
|
||||
this.$confirm('是否要删除该菜单', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteMenu({ id: row.id }).then(response => {
|
||||
this.$message({ message: this.$t('page.deleteSuccess'), type: 'success', duration: 1000 })
|
||||
deleteMenu(row.id).then(response => {
|
||||
this.$message({
|
||||
message: '删除成功',
|
||||
type: 'success',
|
||||
duration: 1000
|
||||
})
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleUpdate(index, row) {
|
||||
this.dialogVisible = true
|
||||
this.menuId = row.id
|
||||
this.menu = Object.assign({}, row)
|
||||
this.menu.parentId = [row.parentId]
|
||||
this.isEdit = true
|
||||
getMenu(this.menuId).then(response => {
|
||||
this.menu = response.data
|
||||
this.isEdit = true
|
||||
this.dialogVisible = true
|
||||
})
|
||||
},
|
||||
handleDialogConfirm() {
|
||||
this.$refs.menuFrom.validate((valid) => {
|
||||
if (valid) {
|
||||
this.menu.parentId = this.menu.parentId[this.menu.parentId.length - 1]
|
||||
if (this.isEdit) {
|
||||
updateMenu(this.menu).then(response => {
|
||||
this.$message({ message: this.$t('message.updateSuccess'), type: 'success', duration: 1000 })
|
||||
this.dialogVisible = false
|
||||
this.getList()
|
||||
})
|
||||
} else {
|
||||
createMenu(this.menu).then(response => {
|
||||
this.$refs.menuFrom.resetFields()
|
||||
this.$message({ message: this.$t('message.submitSuccess'), type: 'success', duration: 1000 })
|
||||
this.dialogVisible = false
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
this.$confirm('是否提交数据', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
if (this.isEdit) {
|
||||
updateMenu(this.menuId, this.menu).then(response => {
|
||||
this.$message({
|
||||
message: '修改成功',
|
||||
type: 'success',
|
||||
duration: 1000
|
||||
})
|
||||
this.dialogVisible = false
|
||||
this.getList()
|
||||
})
|
||||
} else {
|
||||
createMenu(this.menu).then(response => {
|
||||
this.$refs.menuFrom.resetFields()
|
||||
this.$message({
|
||||
message: '提交成功',
|
||||
type: 'success',
|
||||
duration: 1000
|
||||
})
|
||||
this.dialogVisible = false
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$message({ message: this.$t('message.verificationFailed'), type: 'success', duration: 1000 })
|
||||
this.$message({
|
||||
message: '验证失败',
|
||||
type: 'error',
|
||||
duration: 1000
|
||||
})
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
@ -241,10 +267,10 @@ export default {
|
|||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
::v-deep{
|
||||
.el-table__expand-icon {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
<style scoped>
|
||||
.btnBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
<template>
|
||||
<div class="">
|
||||
<el-card>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:filter-map="filterMap"
|
||||
:get-list-action="getOplList"
|
||||
:pagination="true"
|
||||
page-key="pageNum"
|
||||
limit-key="pageSize"
|
||||
tooltip-effect="dark"
|
||||
>
|
||||
<!-- <template v-slot:filterBtns>
|
||||
<el-button size="medium" type="primary" @click="handleDelete">删除</el-button>
|
||||
</template> -->
|
||||
</List>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import { getOplList, deleteOpl
|
||||
// deleteOplByIds
|
||||
} from '@/api/authority/opl'
|
||||
export default {
|
||||
components: { List },
|
||||
data() {
|
||||
return {
|
||||
getOplList,
|
||||
isEdit: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filterMap() {
|
||||
return {
|
||||
path: {
|
||||
label: this.$t('page.path')
|
||||
},
|
||||
method: {
|
||||
label: this.$t('page.method'),
|
||||
type: 'select',
|
||||
dataSource: [
|
||||
{ label: 'GET', value: 'GET' },
|
||||
{ label: 'POST', value: 'POST' },
|
||||
{ label: 'PUT', value: 'PUT' },
|
||||
{ label: 'DELETE', value: 'DELETE' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
columns() {
|
||||
return [
|
||||
// { type: 'selection' },
|
||||
{ prop: 'id', label: 'ID' },
|
||||
{ prop: 'userName', label: this.$t('page.user') },
|
||||
{ prop: 'ip', label: 'IP' },
|
||||
{ prop: 'path', label: this.$t('page.path') },
|
||||
{ prop: 'status', label: this.$t('page.code') },
|
||||
{ prop: 'method', label: this.$t('page.request') },
|
||||
{ prop: 'latency', label: this.$t('page.responseTime'), formatter: res => res.latency + 'ms' },
|
||||
{ prop: 'createTime', label: this.$t('page.creationTime'), formatter: row => {
|
||||
return <div>{new Date(row.createTime).toLocaleString()}</div>
|
||||
} },
|
||||
{
|
||||
prop: 'more', label: this.$t('page.more'), formatter: (row, index) => {
|
||||
return <div>
|
||||
<el-button type='text' onClick={() => this.handleDelete(row)}> {this.$t('page.delete')} </el-button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
handleDelete(row) {
|
||||
this.$confirm(this.$t('page.isDeleteLog'), this.$t('page.info'), {
|
||||
confirmButtonText: this.$t('message.confirm'),
|
||||
cancelButtonText: this.$t('message.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteOpl({ id: row.id }).then(response => {
|
||||
this.$message({ message: this.$t('page.deleteSuccess'), type: 'success', duration: 1000 })
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
</style>
|
|
@ -0,0 +1,151 @@
|
|||
<template>
|
||||
<div class="">
|
||||
<List
|
||||
ref="multipleTable"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="listData"
|
||||
tooltip-effect="dark"
|
||||
>
|
||||
<template v-slot:filterBtns>
|
||||
<el-button size="medium" type="primary" @click="handleAdd">添加</el-button>
|
||||
</template>
|
||||
</List>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
title="添加分类"
|
||||
:visible.sync="dialogVisible"
|
||||
append-to-body
|
||||
width="40%"
|
||||
>
|
||||
<el-form
|
||||
ref="resourceCategoryForm"
|
||||
:model="resourceCategory"
|
||||
label-width="150px"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item label="名称:">
|
||||
<el-input v-model="resourceCategory.name" style="width: 250px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="排序:">
|
||||
<el-input v-model="resourceCategory.sort" style="width: 250px" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button size="small" @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" size="small" @click="handleDialogConfirm()">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import { listAllCate, createResourceCategory, updateResourceCategory, deleteResourceCategory } from '@/api/authority/permissionManagement'
|
||||
|
||||
// import { newEval } from '@/utils'
|
||||
import moment from 'moment'
|
||||
const defaultResourceCategory = {
|
||||
name: null,
|
||||
sort: 0
|
||||
}
|
||||
export default {
|
||||
components: { List },
|
||||
data() {
|
||||
return {
|
||||
listData: [],
|
||||
dialogVisible: false,
|
||||
resourceCategory: Object.assign({}, defaultResourceCategory),
|
||||
isEdit: false,
|
||||
categoryOptions: [],
|
||||
defaultCategoryId: null,
|
||||
columns: [
|
||||
{ prop: 'id', label: '编号', sortable: true },
|
||||
{ prop: 'name', label: '名称', sortable: true },
|
||||
{ prop: 'createTime', label: '添加时间', sortable: true, formatter: (row) => { return <span>{this.formatDate(row.createTime)}</span> } },
|
||||
{ prop: 'sort', label: '排序', sortable: true },
|
||||
{
|
||||
prop: 'more', label: '更多操作', formatter: (row, index) => {
|
||||
return <div>
|
||||
<el-button type='text' onClick={() => this.handleUpdate(index, row)}> 编辑 </el-button>
|
||||
<el-button type='text' onClick={() => this.handleDelete(index, row)}> 删除 </el-button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
listAllCate().then(e => {
|
||||
this.listData = e.data
|
||||
})
|
||||
},
|
||||
formatDate(t) {
|
||||
return moment(t).local().format('YYYY-MM-DD hh:mm:ss')
|
||||
},
|
||||
handleAdd() {
|
||||
this.dialogVisible = true
|
||||
this.isEdit = false
|
||||
this.resourceCategory = Object.assign({}, defaultResourceCategory)
|
||||
},
|
||||
handleUpdate(index, row) {
|
||||
this.dialogVisible = true
|
||||
this.isEdit = true
|
||||
this.resourceCategory = Object.assign({}, row)
|
||||
},
|
||||
handleDelete(index, row) {
|
||||
this.$confirm('是否要删除该分类?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteResourceCategory(row.id).then(response => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '删除成功!'
|
||||
})
|
||||
this.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleDialogConfirm() {
|
||||
this.$confirm('是否要确认?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
if (this.isEdit) {
|
||||
updateResourceCategory(this.resourceCategory.id, this.resourceCategory).then(response => {
|
||||
this.$message({
|
||||
message: '修改成功!',
|
||||
type: 'success'
|
||||
})
|
||||
this.dialogVisible = false
|
||||
this.getList()
|
||||
})
|
||||
} else {
|
||||
createResourceCategory(this.resourceCategory).then(response => {
|
||||
this.$message({
|
||||
message: '添加成功!',
|
||||
type: 'success'
|
||||
})
|
||||
this.dialogVisible = false
|
||||
this.getList()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.btnBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
|
@ -3,150 +3,119 @@
|
|||
<el-card>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:get-list-action="getResourceList"
|
||||
:filter-map="filterMap"
|
||||
:pagination="true"
|
||||
page-key="pageNum"
|
||||
limit-key="pageSize"
|
||||
tooltip-effect="dark"
|
||||
>
|
||||
<template v-slot:filterBtns>
|
||||
<el-button size="medium" type="primary" @click="handleAdd"> {{ $t('page.add') }} </el-button>
|
||||
<el-button size="medium" type="primary" @click="resourceCategoryVisible=true">资源分类</el-button>
|
||||
<el-button size="medium" type="primary" @click="handleAdd">添加</el-button>
|
||||
</template>
|
||||
</List>
|
||||
</el-card>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
:title="isEdit? $t('page.editResource') : $t('page.addResource')"
|
||||
:title="isEdit?'编辑资源':'添加资源'"
|
||||
:visible.sync="dialogVisible"
|
||||
width="40%"
|
||||
>
|
||||
<p>
|
||||
<el-alert
|
||||
:title="$t('page.apiInfo')"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
/>
|
||||
</p>
|
||||
<el-form
|
||||
ref="resourceForm"
|
||||
:model="resource"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
label-width="150px"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item :label="$t('page.apiPath')" prop="path">
|
||||
<el-input v-model="resource.path" />
|
||||
<el-form-item label="资源名称:">
|
||||
<el-input v-model="resource.name" style="width: 250px" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.request')" prop="method">
|
||||
<el-select v-model="resource.method" style="width: 100%;">
|
||||
<el-form-item label="资源路径:">
|
||||
<el-input v-model="resource.url" style="width: 250px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="资源分类:">
|
||||
<el-select v-model="resource.categoryId" placeholder="全部" clearable style="width: 250px">
|
||||
<el-option
|
||||
v-for="it in filterMap.method.dataSource"
|
||||
:key="it.label"
|
||||
:label="it.label"
|
||||
:value="it.label"
|
||||
v-for="item in categoryOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.apiGroup')" prop="apiGroup">
|
||||
<el-input v-model="resource.apiGroup" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.apiDesc')" prop="description">
|
||||
<el-input v-model="resource.description" type="textarea" :rows="5" />
|
||||
<el-form-item label="描述:">
|
||||
<el-input
|
||||
v-model="resource.description"
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
style="width: 250px"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button size="small" @click="dialogVisible = false">{{ $t("message.cancel") }}</el-button>
|
||||
<el-button type="primary" size="small" @click="handleDialogConfirm()">{{ $t("message.confirm") }}</el-button>
|
||||
<el-button size="small" @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" size="small" @click="handleDialogConfirm()">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
title="资源列表"
|
||||
:visible.sync="resourceCategoryVisible"
|
||||
width="80%"
|
||||
>
|
||||
<resource-category-list />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import { getResourceList, addApi, editApi, deleteApi
|
||||
// deleteApisByIds
|
||||
} from '@/api/authority/api'
|
||||
import { getResourceList, createResource, updateResource, deleteResource, listAllCate } from '@/api/authority/permissionManagement'
|
||||
|
||||
// import { newEval } from '@/utils'
|
||||
import moment from 'moment'
|
||||
import ResourceCategoryList from './resourceCategoryList.vue'
|
||||
const defaultResource = {
|
||||
'name': null,
|
||||
'path': null,
|
||||
'description': '',
|
||||
'apiGroup': null,
|
||||
'method': null
|
||||
id: null,
|
||||
name: null,
|
||||
url: null,
|
||||
categoryId: null,
|
||||
description: ''
|
||||
}
|
||||
export default {
|
||||
components: { List },
|
||||
components: { List, ResourceCategoryList },
|
||||
data() {
|
||||
return {
|
||||
getResourceList,
|
||||
listData: [],
|
||||
dialogVisible: false,
|
||||
resourceCategoryVisible: false,
|
||||
resource: Object.assign({}, defaultResource),
|
||||
isEdit: false,
|
||||
categoryOptions: [],
|
||||
defaultCategoryId: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filterMap() {
|
||||
return {
|
||||
path: {
|
||||
label: this.$t('page.path')
|
||||
},
|
||||
apiGroup: {
|
||||
label: this.$t('page.apiGroup')
|
||||
},
|
||||
method: {
|
||||
label: this.$t('page.method'),
|
||||
type: 'select',
|
||||
dataSource: [
|
||||
{ label: 'GET', value: 'GET' },
|
||||
{ label: 'POST', value: 'POST' },
|
||||
{ label: 'PUT', value: 'PUT' },
|
||||
{ label: 'DELETE', value: 'DELETE' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
columns() {
|
||||
return [
|
||||
{ prop: 'id', label: 'ID', width: 100 },
|
||||
{ prop: 'path', label: this.$t('page.path') },
|
||||
{ prop: 'description', label: this.$t('page.description') },
|
||||
{ prop: 'apiGroup', label: this.$t('page.apiGroup') },
|
||||
{ prop: 'method', label: this.$t('page.request') },
|
||||
defaultCategoryId: null,
|
||||
columns: [
|
||||
{ prop: 'id', label: '编号', sortable: true },
|
||||
{ prop: 'name', label: '资源名称', sortable: true },
|
||||
{ prop: 'url', label: '资源路径', sortable: true },
|
||||
{ prop: 'description', label: '描述', sortable: true },
|
||||
{ prop: 'createTime', label: '添加时间', sortable: true, formatter: (row) => { return <span>{this.formatDate(row.createTime)}</span> } },
|
||||
{
|
||||
prop: 'more', label: this.$t('page.more'), width: 150, formatter: (row, index) => {
|
||||
return <el-dropdown>
|
||||
<el-button size='mini' className='el-dropdown-link' icon='el-icon-more' circle>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => this.handleUpdate(index, row)}> <el-dropdown-item><i class='el-icon-edit'></i> {this.$t('page.edit')} </el-dropdown-item> </span>
|
||||
<span onClick={() => this.handleDelete(index, row)}> <el-dropdown-item divided><i class='el-icon-delete'></i> { this.$t('message.delete') } </el-dropdown-item> </span>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
prop: 'more', label: '更多操作', formatter: (row, index) => {
|
||||
return <div>
|
||||
<el-button type='text' onClick={() => this.handleUpdate(index, row)}> 编辑 </el-button>
|
||||
<el-button type='text' onClick={() => this.handleDelete(index, row)}> 删除 </el-button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
name: [{ required: true, message: this.$t('message.pleaseInput') }],
|
||||
description: [{ required: true, message: this.$t('message.pleaseInput') }],
|
||||
apiGroup: [{ required: true, message: this.$t('message.pleaseInput') }],
|
||||
path: [{ required: true, message: this.$t('message.pleaseInput') }],
|
||||
method: [{ required: true, message: this.$t('message.pleaseChoose') }]
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.getList()
|
||||
this.getCateList()
|
||||
},
|
||||
methods: {
|
||||
getList() {
|
||||
|
@ -163,15 +132,19 @@ export default {
|
|||
this.dialogVisible = true
|
||||
this.isEdit = false
|
||||
this.resource = Object.assign({}, defaultResource)
|
||||
this.resource.categoryId = this.defaultCategoryId
|
||||
},
|
||||
handleDelete(index, row) {
|
||||
this.$confirm(this.$t('message.isDeleteResource'), this.$t('page.info'), {
|
||||
confirmButtonText: this.$t('message.confirm'),
|
||||
cancelButtonText: this.$t('message.cancel'),
|
||||
this.$confirm('是否要删除该资源?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteApi({ id: row.id + '' }).then(response => {
|
||||
this.$message({ message: this.$t('page.deleteSuccess'), type: 'success', duration: 1000 })
|
||||
deleteResource(row.id).then(response => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '删除成功!'
|
||||
})
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
})
|
||||
|
@ -182,25 +155,41 @@ export default {
|
|||
this.resource = Object.assign({}, row)
|
||||
},
|
||||
handleDialogConfirm() {
|
||||
this.$refs.resourceForm.validate((valid) => {
|
||||
if (valid) {
|
||||
this.resource.name = this.resource.description
|
||||
if (this.isEdit) {
|
||||
this.resource.ID = this.resource.id
|
||||
editApi(this.resource).then(response => {
|
||||
this.$message({ message: this.$t('message.updateSuccess'), type: 'success', duration: 1000 })
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
this.$confirm('是否要确认?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
if (this.isEdit) {
|
||||
updateResource(this.resource.id, this.resource).then(response => {
|
||||
this.$message({
|
||||
message: '修改成功!',
|
||||
type: 'success'
|
||||
})
|
||||
} else {
|
||||
addApi(this.resource).then(response => {
|
||||
this.$message({ message: this.$t('message.addSuccess'), type: 'success', duration: 1000 })
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
} else {
|
||||
createResource(this.resource).then(response => {
|
||||
this.$message({
|
||||
message: '添加成功!',
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
getCateList() {
|
||||
listAllCate().then(response => {
|
||||
const cateList = response.data
|
||||
for (let i = 0; i < cateList.length; i++) {
|
||||
const cate = cateList[i]
|
||||
this.categoryOptions.push({ label: cate.name, value: cate.id })
|
||||
}
|
||||
this.defaultCategoryId = cateList[0].id
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,35 +3,35 @@
|
|||
<el-card>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:get-list-action="getRoleList"
|
||||
list-key="data"
|
||||
:pagination="true"
|
||||
page-key="pageNum"
|
||||
limit-key="pageSize"
|
||||
tooltip-effect="dark"
|
||||
>
|
||||
<template v-slot:filterBtns>
|
||||
<el-button size="medium" type="primary" @click="handleRoleAdd">{{ $t('message.create') }}</el-button>
|
||||
<el-button size="medium" type="primary" @click="handleAdd">创建</el-button>
|
||||
</template>
|
||||
</List>
|
||||
</el-card>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
:title="isEdit?$t('permission.editRole'):$t('permission.addRole')"
|
||||
:title="isEdit?'编辑角色':'添加角色'"
|
||||
:visible.sync="dialogVisible"
|
||||
width="40%"
|
||||
>
|
||||
<el-form
|
||||
ref="roleForm"
|
||||
:model="role"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
label-width="150px"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item prop="name" :label="$t('permission.roleName')">
|
||||
<el-form-item label="角色名称:">
|
||||
<el-input v-model="role.name" style="width: 250px" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="description" :label="$t('page.description')">
|
||||
<el-form-item label="描述:">
|
||||
<el-input
|
||||
v-model="role.description"
|
||||
type="textarea"
|
||||
|
@ -39,28 +39,27 @@
|
|||
style="width: 250px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="status" :label="$t('permission.isUse')">
|
||||
<el-form-item label="是否启用:">
|
||||
<el-radio-group v-model="role.status">
|
||||
<el-radio :label="true"> {{ $t('permission.yes') }} </el-radio>
|
||||
<el-radio :label="false"> {{ $t('permission.no') }} </el-radio>
|
||||
<el-radio :label="1">是</el-radio>
|
||||
<el-radio :label="0">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button size="small" @click="dialogVisible = false">{{ $t("message.cancel") }}</el-button>
|
||||
<el-button type="primary" size="small" @click="handleDialogConfirm()">{{ $t("message.confirm") }}</el-button>
|
||||
<el-button size="small" @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" size="small" @click="handleDialogConfirm()">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
:title="$t('permission.assignMenu')"
|
||||
title="分配菜单"
|
||||
:visible.sync="menuSelectDialog"
|
||||
width="50%"
|
||||
>
|
||||
<el-tree
|
||||
ref="menuTree"
|
||||
ref="tree"
|
||||
:data="menuTreeList"
|
||||
:default-checked-keys="menuIds"
|
||||
show-checkbox
|
||||
default-expand-all
|
||||
node-key="id"
|
||||
|
@ -68,27 +67,37 @@
|
|||
:props="defaultProps"
|
||||
/>
|
||||
<div style="margin-top: 20px" align="center">
|
||||
<el-button type="primary" @click="handleMenuSave()"> {{ $t('message.save') }} </el-button>
|
||||
<el-button type="primary" @click="handleSave()">保存</el-button>
|
||||
<el-button @click="handleClear()">清空</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
:title="$t('permission.assignResource')"
|
||||
title="分配资源"
|
||||
:visible.sync="resourceSelectDialog"
|
||||
width="50%"
|
||||
>
|
||||
<el-tree
|
||||
ref="apiTree"
|
||||
:data="apiTreeList"
|
||||
:default-checked-keys="apiIds"
|
||||
show-checkbox
|
||||
default-expand-all
|
||||
node-key="key"
|
||||
highlight-current
|
||||
:props="apiDefaultProps"
|
||||
/>
|
||||
<div v-for="(cate,index) in allResourceCate" :key="'cate'+cate.id" :class="index===0?'top-line':null">
|
||||
<el-row class="table-layout choose-line">
|
||||
<el-checkbox
|
||||
v-model="cate.checked"
|
||||
:indeterminate="isIndeterminate(cate.id)"
|
||||
@change="handleCheckAllChange(cate)"
|
||||
>
|
||||
{{ cate.name }}
|
||||
</el-checkbox>
|
||||
</el-row>
|
||||
<el-row class="table-layout">
|
||||
<el-col v-for="resource in getResourceByCate(cate.id)" :key="resource.id" :span="8" style="padding: 4px 0">
|
||||
<el-checkbox v-model="resource.checked" @change="handleCheckChange(resource)">
|
||||
{{ resource.name }}
|
||||
</el-checkbox>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div style="margin-top: 20px" align="center">
|
||||
<el-button type="primary" @click="handleResourceSave()"> {{ $t('message.save') }} </el-button>
|
||||
<el-button type="primary" @click="handleResourceSave()">保存</el-button>
|
||||
<el-button @click="handleResourceClear()">清空</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
@ -96,16 +105,16 @@
|
|||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import { createRole, updateRole, deleteRole, allocMenu, getRoleList, allocApis } from '@/api/authority/role'
|
||||
import { getMenuTree } from '@/api/authority/menu'
|
||||
import { getElTreeApis } from '@/api/authority/api'
|
||||
import { getRoleList, createRole, updateRole, updateRoleStatus, deleteRole, fetchTreeList, listMenuByRole, allocMenu, fetchAllResourceList, listAllCate, allocResource, listResourceByRole } from '@/api/authority/permissionManagement'
|
||||
|
||||
// import { newEval } from '@/utils'
|
||||
import moment from 'moment'
|
||||
const defaultRole = {
|
||||
'id': undefined,
|
||||
'name': undefined,
|
||||
'description': undefined,
|
||||
'status': true
|
||||
id: null,
|
||||
name: null,
|
||||
description: null,
|
||||
adminCount: 0,
|
||||
status: 1
|
||||
}
|
||||
export default {
|
||||
components: { List },
|
||||
|
@ -118,149 +127,316 @@ export default {
|
|||
resourceSelectDialog: false,
|
||||
role: Object.assign({}, defaultRole),
|
||||
isEdit: false,
|
||||
labelWidth: Math.round(document.body.offsetHeight / 1048 * 100) + 'px',
|
||||
apiTreeList: [],
|
||||
apiIds: [],
|
||||
columns: [
|
||||
{ prop: 'id', label: '编号', sortable: true },
|
||||
{ prop: 'name', label: '角色名称', sortable: true },
|
||||
{ prop: 'description', label: '描述', sortable: true },
|
||||
{ prop: 'adminCount', label: '用户数', sortable: true },
|
||||
{ prop: 'createTime', label: '添加时间', sortable: true, formatter: (row) => { return <span>{this.formatDate(row.createTime)}</span> } },
|
||||
{ prop: 'status', label: '是否启用', formatter: (row) => {
|
||||
return <el-switch
|
||||
onChange={() => this.handleStatusChange(row)}
|
||||
activeValue={1}
|
||||
inactiveValue={0}
|
||||
value={row.status}>
|
||||
</el-switch>
|
||||
} },
|
||||
{
|
||||
prop: 'more', label: '更多操作', formatter: (row, index) => {
|
||||
return <div>
|
||||
<el-button type='text' onClick={() => this.handleSelectMenu(index, row)}> 分配菜单 </el-button>
|
||||
<el-button type='text' onClick={() => this.handleSelectResource(index, row)}> 分配资源 </el-button>
|
||||
<el-button type='text' onClick={() => this.handleUpdate(index, row)}> 编辑 </el-button>
|
||||
<el-button type='text' onClick={() => this.handleDelete(index, row)}> 删除 </el-button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
],
|
||||
menuTreeList: [],
|
||||
menuIds: [],
|
||||
defaultProps: {
|
||||
children: 'children',
|
||||
label: 'title'
|
||||
},
|
||||
apiDefaultProps: {
|
||||
children: 'children',
|
||||
label: (data) => {
|
||||
return data.apiGroup
|
||||
}
|
||||
},
|
||||
roleId: null,
|
||||
allResource: null,
|
||||
allResourceCate: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
columns() {
|
||||
return [
|
||||
{ prop: 'id', label: 'ID', sortable: true },
|
||||
{ prop: 'name', label: this.$t('permission.roleName'), sortable: true },
|
||||
{ prop: 'description', label: this.$t('page.description'), sortable: true },
|
||||
{ prop: 'status', label: this.$t('permission.isUse'), formatter: (row, index) => {
|
||||
return row.status === true ? <el-tag type='success'>{this.$t('permission.enable')}</el-tag> : <el-tag type='warning'>{this.$t('permission.deactivate')}</el-tag>
|
||||
} },
|
||||
{
|
||||
prop: 'more', label: this.$t('page.more'), formatter: (row, index) => {
|
||||
return <el-dropdown>
|
||||
<el-button size='mini' className='el-dropdown-link' icon='el-icon-more' circle>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => this.handleSelectMenu(index, row)}> <el-dropdown-item><i class='el-icon-edit'></i> {this.$t('permission.assignMenu')} </el-dropdown-item> </span>
|
||||
<span onClick={() => this.handleSelectResource(index, row)}> <el-dropdown-item><i class='el-icon-edit'></i> {this.$t('permission.assignResource')} </el-dropdown-item> </span>
|
||||
<span onClick={() => this.handleRoleUpdate(index, row)}> <el-dropdown-item><i class='el-icon-edit'></i> {this.$t('page.edit')} </el-dropdown-item> </span>
|
||||
<span onClick={() => this.handleRoleDelete(index, row)}> <el-dropdown-item divided><i class='el-icon-delete'></i> { this.$t('message.delete') } </el-dropdown-item> </span>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
name: [{ required: true, message: this.$t('check.input') }],
|
||||
description: [{ required: true, message: this.$t('check.input') }],
|
||||
status: [{ required: true, message: this.$t('check.select') }]
|
||||
}
|
||||
}
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
handleRoleAdd() {
|
||||
formatDate(t) {
|
||||
return moment(t).local().format('YYYY-MM-DD hh:mm:ss')
|
||||
},
|
||||
handleAdd() {
|
||||
this.dialogVisible = true
|
||||
this.isEdit = false
|
||||
this.role = Object.assign({}, defaultRole)
|
||||
},
|
||||
handleRoleDelete(index, row) {
|
||||
this.$confirm(this.$t('permission.wantDeleteRole'), this.$t('page.info'), {
|
||||
confirmButtonText: this.$t('message.confirm'),
|
||||
cancelButtonText: this.$t('message.cancel'),
|
||||
handleStatusChange(row) {
|
||||
console.log(row.status)
|
||||
this.$confirm('是否要修改该状态?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteRole({ id: row.id + '' }).then(response => {
|
||||
this.$message({ type: 'success', message: this.$t('page.deleteSuccess') })
|
||||
updateRoleStatus(row.id, { status: !row.status ? 1 : 0 }).then(response => {
|
||||
this.$refs.multipleTable.getList()
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '修改成功!'
|
||||
})
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '取消修改'
|
||||
})
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
},
|
||||
handleDelete(index, row) {
|
||||
this.$confirm('是否要删除该角色?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const ids = []
|
||||
ids.push(row.id)
|
||||
const params = new URLSearchParams()
|
||||
params.append('ids', ids)
|
||||
deleteRole({ ids: row.id }).then(response => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '删除成功!'
|
||||
})
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleRoleUpdate(row) {
|
||||
handleUpdate(index, row) {
|
||||
this.dialogVisible = true
|
||||
this.isEdit = true
|
||||
this.role = Object.assign({}, row)
|
||||
},
|
||||
handleDialogConfirm() {
|
||||
this.$refs.roleForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.isEdit) {
|
||||
updateRole(this.role).then(response => {
|
||||
this.$message({ type: 'success', message: this.$t('message.updateSuccess') })
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
this.$confirm('是否要确认?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
if (this.isEdit) {
|
||||
updateRole(this.role.id, this.role).then(response => {
|
||||
this.$message({
|
||||
message: '修改成功!',
|
||||
type: 'success'
|
||||
})
|
||||
} else {
|
||||
createRole(this.role).then(response => {
|
||||
this.$message({ type: 'success', message: this.$t('message.addSuccess') })
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
} else {
|
||||
createRole(this.role).then(response => {
|
||||
this.$message({
|
||||
message: '添加成功!',
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSelectMenu(index, row) {
|
||||
this.roleId = row.id
|
||||
getMenuTree({ id: row.id }).then(response => {
|
||||
this.menuTreeList = response.data.list
|
||||
this.menuIds = response.data.menuIds
|
||||
this.treeList()
|
||||
this.getRoleMenu(row.id)
|
||||
},
|
||||
treeList() {
|
||||
fetchTreeList().then(response => {
|
||||
this.menuTreeList = response.data
|
||||
this.menuSelectDialog = true
|
||||
})
|
||||
},
|
||||
handleMenuSave() {
|
||||
const checkedNodes = this.$refs.menuTree.getCheckedKeys()
|
||||
const halfCheckedNodes = this.$refs.menuTree.getHalfCheckedKeys()
|
||||
let menuIds = [...checkedNodes, ...halfCheckedNodes]
|
||||
menuIds = menuIds.map(item => item + '')
|
||||
allocMenu({ roleId: this.roleId + '', menuIds })
|
||||
.then((res) => {
|
||||
this.$message({ message: this.$t('message.allocationSucce'), type: 'success', duration: 1000 })
|
||||
getRoleMenu(roleId) {
|
||||
listMenuByRole(roleId).then(response => {
|
||||
const menuList = response.data
|
||||
const checkedMenuIds = []
|
||||
if (menuList != null && menuList.length > 0) {
|
||||
for (let i = 0; i < menuList.length; i++) {
|
||||
const menu = menuList[i]
|
||||
if (menu.parentId !== 0) {
|
||||
checkedMenuIds.push(menu.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$refs.tree.setCheckedKeys(checkedMenuIds)
|
||||
})
|
||||
},
|
||||
handleSave() {
|
||||
const checkedNodes = this.$refs.tree.getCheckedNodes()
|
||||
const checkedMenuIds = new Set()
|
||||
if (checkedNodes != null && checkedNodes.length > 0) {
|
||||
for (let i = 0; i < checkedNodes.length; i++) {
|
||||
const checkedNode = checkedNodes[i]
|
||||
checkedMenuIds.add(checkedNode.id)
|
||||
if (checkedNode.parentId !== 0) {
|
||||
checkedMenuIds.add(checkedNode.parentId)
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$confirm('是否分配菜单?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const params = {
|
||||
roleId: this.roleId,
|
||||
menuIds: Array.from(checkedMenuIds).join(',')
|
||||
}
|
||||
allocMenu(params).then(response => {
|
||||
this.menuSelectDialog = false
|
||||
this.$message({
|
||||
message: '分配成功',
|
||||
type: 'success',
|
||||
duration: 1000
|
||||
})
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
.catch(() => {})
|
||||
})
|
||||
},
|
||||
handleClear() {
|
||||
this.$refs.tree.setCheckedKeys([])
|
||||
},
|
||||
handleSelectResource(index, row) {
|
||||
this.roleId = row.id
|
||||
getElTreeApis({ id: row.id }).then(response => {
|
||||
this.apiTreeList = response.data.list
|
||||
this.apiIds = response.data.checkedKey
|
||||
this.resourceSelectDialog = true
|
||||
this.getAllResourceCateList()
|
||||
},
|
||||
getAllResourceList() {
|
||||
fetchAllResourceList().then(response => {
|
||||
this.allResource = response.data
|
||||
for (let i = 0; i < this.allResource.length; i++) {
|
||||
this.allResource[i].checked = false
|
||||
}
|
||||
this.getResourceByRole(this.roleId)
|
||||
})
|
||||
},
|
||||
handleResourceSave() {
|
||||
const casbinInfos = []
|
||||
const checkedNodes = this.$refs.apiTree.getCheckedNodes()
|
||||
for (const item of checkedNodes) {
|
||||
if (item.path && item.method) {
|
||||
const casbinInfo = {
|
||||
path: item.path,
|
||||
method: item.method
|
||||
}
|
||||
casbinInfos.push(casbinInfo)
|
||||
getAllResourceCateList() {
|
||||
listAllCate().then(response => {
|
||||
this.resourceSelectDialog = true
|
||||
this.allResourceCate = response.data
|
||||
for (let i = 0; i < this.allResourceCate.length; i++) {
|
||||
this.allResourceCate[i].checked = false
|
||||
}
|
||||
this.getAllResourceList()
|
||||
})
|
||||
},
|
||||
getResourceByCate(categoryId) {
|
||||
const cateResource = []
|
||||
if (this.allResource == null) return null
|
||||
for (let i = 0; i < this.allResource.length; i++) {
|
||||
const resource = this.allResource[i]
|
||||
if (resource.categoryId === categoryId) {
|
||||
cateResource.push(resource)
|
||||
}
|
||||
}
|
||||
allocApis({ roleId: this.roleId, casbinInfos: casbinInfos })
|
||||
.then((res) => {
|
||||
this.$message({ message: this.$t('message.allocationSucce'), type: 'success', duration: 1000 })
|
||||
this.resourceSelectDialog = false
|
||||
this.$refs.multipleTable.getList()
|
||||
return cateResource
|
||||
},
|
||||
getResourceByRole(roleId) {
|
||||
listResourceByRole(roleId).then(response => {
|
||||
const allocResource = response.data
|
||||
this.allResource.forEach(item => {
|
||||
item.checked = this.getResourceChecked(item.id, allocResource)
|
||||
})
|
||||
.catch(() => {})
|
||||
this.allResourceCate.forEach(item => {
|
||||
item.checked = this.isAllChecked(item.id)
|
||||
})
|
||||
this.$forceUpdate()
|
||||
})
|
||||
},
|
||||
getResourceChecked(resourceId, allocResource) {
|
||||
if (allocResource == null || allocResource.length === 0) return false
|
||||
for (let i = 0; i < allocResource.length; i++) {
|
||||
if (allocResource[i].id === resourceId) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
isIndeterminate(categoryId) {
|
||||
const cateResources = this.getResourceByCate(categoryId)
|
||||
if (cateResources == null) return false
|
||||
let checkedCount = 0
|
||||
for (let i = 0; i < cateResources.length; i++) {
|
||||
if (cateResources[i].checked === true) {
|
||||
checkedCount++
|
||||
}
|
||||
}
|
||||
return !(checkedCount === 0 || checkedCount === cateResources.length)
|
||||
},
|
||||
isAllChecked(categoryId) {
|
||||
const cateResources = this.getResourceByCate(categoryId)
|
||||
if (cateResources == null) return false
|
||||
let checkedCount = 0
|
||||
for (let i = 0; i < cateResources.length; i++) {
|
||||
if (cateResources[i].checked === true) {
|
||||
checkedCount++
|
||||
}
|
||||
}
|
||||
if (checkedCount === 0) {
|
||||
return false
|
||||
}
|
||||
return checkedCount === cateResources.length
|
||||
},
|
||||
handleResourceSave() {
|
||||
this.$confirm('是否分配资源?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const checkedResourceIds = new Set()
|
||||
if (this.allResource != null && this.allResource.length > 0) {
|
||||
this.allResource.forEach(item => {
|
||||
if (item.checked) {
|
||||
checkedResourceIds.add(item.id)
|
||||
}
|
||||
})
|
||||
}
|
||||
const params = new URLSearchParams()
|
||||
params.append('roleId', this.roleId)
|
||||
params.append('resourceIds', Array.from(checkedResourceIds))
|
||||
allocResource(params).then(response => {
|
||||
this.$message({
|
||||
message: '分配成功',
|
||||
type: 'success',
|
||||
duration: 1000
|
||||
})
|
||||
this.$router.back()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleResourceClear() {
|
||||
this.allResourceCate.forEach(item => {
|
||||
item.checked = false
|
||||
})
|
||||
this.allResource.forEach(item => {
|
||||
item.checked = false
|
||||
})
|
||||
this.$forceUpdate()
|
||||
},
|
||||
handleCheckAllChange(cate) {
|
||||
const cateResources = this.getResourceByCate(cate.id)
|
||||
for (let i = 0; i < cateResources.length; i++) {
|
||||
cateResources[i].checked = cate.checked
|
||||
}
|
||||
this.$forceUpdate()
|
||||
},
|
||||
handleCheckChange(resource) {
|
||||
this.allResourceCate.forEach(item => {
|
||||
if (item.id === resource.categoryId) {
|
||||
item.checked = this.isAllChecked(resource.categoryId)
|
||||
}
|
||||
})
|
||||
this.$forceUpdate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
<el-card>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:get-list-action="getUserList"
|
||||
|
@ -13,83 +12,71 @@
|
|||
tooltip-effect="dark"
|
||||
>
|
||||
<template v-slot:filterBtns>
|
||||
<el-button size="medium" type="primary" @click="handleAdd">{{ $t('message.create') }}</el-button>
|
||||
<el-button size="medium" type="primary" @click="handleAdd">创建</el-button>
|
||||
</template>
|
||||
</List>
|
||||
</el-card>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
:title="isEdit ? $t('permission.editUser') : $t('permission.addUser')"
|
||||
:title="isEdit?'编辑用户':'添加用户'"
|
||||
:visible.sync="dialogVisible"
|
||||
width="40%"
|
||||
>
|
||||
<el-form
|
||||
ref="adminForm"
|
||||
:model="admin"
|
||||
:rules="rules"
|
||||
label-width="auto"
|
||||
label-width="150px"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item prop="username" :label="$t('page.userName')">
|
||||
<el-input v-model="admin.username" />
|
||||
<el-form-item label="帐号:">
|
||||
<el-input v-model="admin.username" style="width: 250px" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="nickname" :label="$t('permission.nickName')">
|
||||
<el-input v-model="admin.nickname" />
|
||||
<el-form-item label="姓名:">
|
||||
<el-input v-model="admin.nickName" style="width: 250px" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!isEdit" prop="password" :label="$t('page.password')">
|
||||
<el-input v-model="admin.password" type="password" show-password />
|
||||
<el-form-item label="邮箱:">
|
||||
<el-input v-model="admin.email" style="width: 250px" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="phone" :label="$t('permission.phone')">
|
||||
<el-input v-model="admin.phone" type="tel" />
|
||||
<el-form-item label="密码:">
|
||||
<el-input v-model="admin.password" type="password" style="width: 250px" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="email" :label="$t('permission.email')">
|
||||
<el-input v-model="admin.email" type="email" />
|
||||
<el-form-item label="备注:">
|
||||
<el-input
|
||||
v-model="admin.note"
|
||||
type="textarea"
|
||||
:rows="5"
|
||||
style="width: 250px"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="roleId" :label="$t('permission.role')">
|
||||
<el-select v-model="admin.roleId" :placeholder="$t('message.pleaseChoose')" size="small">
|
||||
<el-option
|
||||
v-for="item in allRoleList"
|
||||
:key="item.id"
|
||||
::label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('permission.isUse')">
|
||||
<el-form-item label="是否启用:">
|
||||
<el-radio-group v-model="admin.status">
|
||||
<el-radio :label="true">{{ $t('permission.enable') }}</el-radio>
|
||||
<el-radio :label="false">{{ $t('permission.deactivate') }}</el-radio>
|
||||
<el-radio :label="1">是</el-radio>
|
||||
<el-radio :label="0">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button size="small" @click="dialogVisible = false">{{ $t("message.cancel") }}</el-button>
|
||||
<el-button type="primary" size="small" @click="handleDialogConfirm()">{{ $t("message.confirm") }}</el-button>
|
||||
<el-button size="small" @click="dialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" size="small" @click="handleDialogConfirm()">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
:close-on-click-modal="false"
|
||||
:title="$t('permission.editPass')"
|
||||
:visible.sync="passDialogVisible"
|
||||
width="40%"
|
||||
title="分配角色"
|
||||
:visible.sync="allocDialogVisible"
|
||||
width="30%"
|
||||
>
|
||||
<el-form
|
||||
ref="passForm"
|
||||
:model="changePass"
|
||||
:rules="passRules"
|
||||
label-width="auto"
|
||||
size="small"
|
||||
>
|
||||
<el-form-item prop="newPassword" :label="$t('permission.newPass')">
|
||||
<el-input v-model="changePass.newPassword" type="password" show-password />
|
||||
</el-form-item>
|
||||
<el-form-item prop="rePassword" :label="$t('permission.confirmPass')">
|
||||
<el-input v-model="changePass.rePassword" type="password" show-password />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-select v-model="allocRoleIds" multiple placeholder="请选择" size="small" style="width: 80%">
|
||||
<el-option
|
||||
v-for="item in allRoleList"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button size="small" @click="passDialogVisible = false">{{ $t("message.cancel") }}</el-button>
|
||||
<el-button type="primary" size="small" @click="handlePassConfirm()">{{ $t("message.confirm") }}</el-button>
|
||||
<el-button size="small" @click="allocDialogVisible = false">取 消</el-button>
|
||||
<el-button type="primary" size="small" @click="handleAllocDialogConfirm()">确 定</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
@ -97,135 +84,65 @@
|
|||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import { editUser, addUser, getUserList, deleteUser, switchStatus, modifyPass } from '@/api/authority/user'
|
||||
import { getRoleList } from '@/api/authority/role'
|
||||
import { getUserList, createAdmin, updateAdmin, updateUserStatus, deleteAdmin, getRoleByAdmin, allocRole, fetchAllRoleList } from '@/api/authority/permissionManagement'
|
||||
|
||||
// import { newEval } from '@/utils'
|
||||
import moment from 'moment'
|
||||
const defaultAdmin = {
|
||||
id: null,
|
||||
username: null,
|
||||
password: null,
|
||||
nickName: null,
|
||||
email: null,
|
||||
status: true
|
||||
note: null,
|
||||
status: 1
|
||||
}
|
||||
export default {
|
||||
components: { List },
|
||||
data() {
|
||||
return {
|
||||
getUserList,
|
||||
// userList: [],
|
||||
admin: Object.assign({}, defaultAdmin),
|
||||
changePass: { newPassword: undefined },
|
||||
dialogVisible: false,
|
||||
passDialogVisible: false,
|
||||
isEdit: false,
|
||||
allocDialogVisible: false,
|
||||
allocRoleIds: [],
|
||||
allRoleList: [],
|
||||
allocAdminId: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
columns() {
|
||||
return [
|
||||
{ prop: 'id', label: 'ID', sortable: true, width: 100 },
|
||||
{ prop: 'username', label: this.$t('page.userName') },
|
||||
{ prop: 'nickname', label: this.$t('permission.nickName') },
|
||||
{ prop: 'phone', label: this.$t('permission.phone') },
|
||||
{ prop: 'email', label: this.$t('permission.email') },
|
||||
{ prop: 'roleName', label: this.$t('permission.role') },
|
||||
{ prop: 'status', label: this.$t('permission.isUse'), formatter: (row) => {
|
||||
allocAdminId: null,
|
||||
columns: [
|
||||
// { prop: 'id', label: '编号', sortable: true },
|
||||
{ prop: 'username', label: '帐号', sortable: true },
|
||||
{ prop: 'nickName', label: '姓名', sortable: true },
|
||||
{ prop: 'email', label: '邮箱', sortable: true },
|
||||
{ prop: 'createTime', label: '添加时间', sortable: true, formatter: (row) => { return <span>{this.formatDate(row.createTime)}</span> } },
|
||||
{ prop: 'loginTime', label: '最后登录', sortable: true, formatter: (row) => { return <span>{this.formatDate(row.loginTime)}</span> } },
|
||||
{ prop: 'status', label: '是否启用', formatter: (row) => {
|
||||
return <el-switch
|
||||
onChange={() => this.handleStatusChange(row)}
|
||||
activeValue={true}
|
||||
inactiveValue={false}
|
||||
activeValue={1}
|
||||
inactiveValue={0}
|
||||
value={row.status}>
|
||||
</el-switch>
|
||||
} },
|
||||
{
|
||||
prop: 'more', label: this.$t('page.more'), formatter: (row, index) => {
|
||||
return <el-dropdown>
|
||||
<el-button size='mini' className='el-dropdown-link' icon='el-icon-more' circle>
|
||||
</el-button>
|
||||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => this.handleUpdate(index, row)}> <el-dropdown-item><i class='el-icon-edit'></i> {this.$t('page.edit')} </el-dropdown-item> </span>
|
||||
<span onClick={() => this.handleSelectRole(index, row)}> <el-dropdown-item><i class='el-icon-edit'></i> {this.$t('permission.editPass')} </el-dropdown-item> </span>
|
||||
<span onClick={() => this.handleDelete(index, row)}> <el-dropdown-item divided><i class='el-icon-delete'></i> { this.$t('message.delete') } </el-dropdown-item> </span>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
prop: 'more', label: '更多操作', formatter: (row, index) => {
|
||||
return <div>
|
||||
<el-button type='text' onClick={() => this.handleSelectRole(index, row)}> 分配角色 </el-button>
|
||||
<el-button type='text' onClick={() => this.handleUpdate(index, row)}> 编辑 </el-button>
|
||||
<el-button type='text' onClick={() => this.handleDelete(index, row)}> 删除 </el-button>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
rules() {
|
||||
return {
|
||||
username: [{ required: true, message: this.$t('message.pleaseInput'), trigger: 'blur' }],
|
||||
nickname: [{ required: true, message: this.$t('message.pleaseInput'), trigger: 'blur' }],
|
||||
phone: [{ required: true, message: this.$t('message.pleaseInput'), trigger: 'blur' }, { pattern: /^1[3456789]\d{9}$/, message: '手机号码格式不正确', trigger: 'blur' }],
|
||||
email: [{ required: true, message: this.$t('message.pleaseInput'), trigger: 'blur' }, { pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/, message: '邮箱格式不正确', trigger: 'blur' }],
|
||||
password: [{ required: true, message: this.$t('message.pleaseInput'), trigger: 'blur' }],
|
||||
roleId: [{ required: true, message: this.$t('message.pleaseChoose') }]
|
||||
}
|
||||
},
|
||||
passRules() {
|
||||
return {
|
||||
newPassword: [
|
||||
{ required: true, trigger: 'blur', message: this.$t('permission.create') },
|
||||
{ min: 6, max: 20, message: this.$t('permission.lengthRequire'), trigger: 'blur' }
|
||||
],
|
||||
rePassword: [
|
||||
{ required: true, message: this.$t('permission.notEmputy') },
|
||||
{ required: true, validator: this.equalToPassword, trigger: 'blur' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getAllRoleList()
|
||||
},
|
||||
methods: {
|
||||
equalToPassword(rule, value, callback) {
|
||||
if (this.changePass.newPassword !== value) {
|
||||
callback(new Error(this.$t('permission.differentPass')))
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
},
|
||||
handleDialogConfirm() {
|
||||
this.$refs.adminForm.validate((valid) => {
|
||||
if (valid) {
|
||||
if (this.isEdit) {
|
||||
editUser({
|
||||
'id': this.admin.id,
|
||||
'username': this.admin.username,
|
||||
'password': this.admin.password,
|
||||
'nickname': this.admin.nickname,
|
||||
'phone': this.admin.phone,
|
||||
'email': this.admin.email,
|
||||
'status': this.admin.status,
|
||||
'roleId': this.admin.roleId
|
||||
}).then(response => {
|
||||
this.$message({ message: this.$t('message.updateSuccess'), type: 'success' })
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
} else {
|
||||
addUser(this.admin).then(response => {
|
||||
this.$message({ message: this.$t('message.addSuccess'), type: 'success' })
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
handlePassConfirm() {
|
||||
this.$refs.passForm.validate((valid) => {
|
||||
if (valid) {
|
||||
modifyPass(this.changePass).then(response => {
|
||||
this.$message({ message: this.$t('message.updateSuccess'), type: 'success' })
|
||||
this.passDialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
}
|
||||
})
|
||||
formatDate(t) {
|
||||
return moment(t).local().format('YYYY-MM-DD hh:mm:ss')
|
||||
},
|
||||
handleAdd() {
|
||||
this.dialogVisible = true
|
||||
|
@ -233,46 +150,119 @@ export default {
|
|||
this.admin = Object.assign({}, defaultAdmin)
|
||||
},
|
||||
handleStatusChange(row) {
|
||||
this.$confirm(this.$t('permission.modifyStatus'), this.$t('page.info'), {
|
||||
confirmButtonText: this.$t('message.confirm'),
|
||||
cancelButtonText: this.$t('message.cancel'),
|
||||
this.$confirm('是否要修改该状态?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
switchStatus({ id: row.id, status: !row.status }).then(response => {
|
||||
updateUserStatus(row.id, { status: !row.status ? 1 : 0 }).then(response => {
|
||||
this.$refs.multipleTable.getList()
|
||||
this.$message({ message: this.$t('message.updateSuccess'), type: 'success' })
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '修改成功!'
|
||||
})
|
||||
})
|
||||
}).catch(() => {
|
||||
this.$message({ type: 'info', message: this.$t('permission.cancelModify') })
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '取消修改'
|
||||
})
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
},
|
||||
handleDelete(id) {
|
||||
this.$confirm(this.$t('permission.isDelUser'), this.$t('page.info'), {
|
||||
confirmButtonText: this.$t('message.confirm'),
|
||||
cancelButtonText: this.$t('message.cancel'),
|
||||
handleDelete(index, row) {
|
||||
this.$confirm('是否要删除该用户?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
deleteUser({ id }).then(response => {
|
||||
this.$message({ type: 'success', message: this.$t('page.deleteSuccess') })
|
||||
deleteAdmin(row.id).then(response => {
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '删除成功!'
|
||||
})
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
})
|
||||
},
|
||||
handleUpdate(row) {
|
||||
handleUpdate(index, row) {
|
||||
this.dialogVisible = true
|
||||
this.isEdit = true
|
||||
this.admin = Object.assign({}, row)
|
||||
},
|
||||
handleDialogConfirm() {
|
||||
this.$confirm('是否要确认?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
if (this.isEdit) {
|
||||
updateAdmin(this.admin.id, this.admin).then(response => {
|
||||
this.$message({
|
||||
message: '修改成功!',
|
||||
type: 'success'
|
||||
})
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
} else {
|
||||
createAdmin(this.admin).then(response => {
|
||||
this.$message({
|
||||
message: '添加成功!',
|
||||
type: 'success'
|
||||
})
|
||||
this.dialogVisible = false
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleAllocDialogConfirm() {
|
||||
this.$confirm('是否要确认?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const params = new FormData()
|
||||
params.append('adminId', this.allocAdminId)
|
||||
params.append('roleIds', this.allocRoleIds)
|
||||
allocRole(params).then(response => {
|
||||
this.$message({
|
||||
message: '分配成功!',
|
||||
type: 'success'
|
||||
})
|
||||
this.allocDialogVisible = false
|
||||
})
|
||||
})
|
||||
},
|
||||
handleSelectRole(index, row) {
|
||||
this.changePass.id = row.id
|
||||
this.passDialogVisible = true
|
||||
this.allocAdminId = row.id
|
||||
this.allocDialogVisible = true
|
||||
this.getRoleListByAdmin(row.id)
|
||||
},
|
||||
getAllRoleList() {
|
||||
getRoleList().then(response => {
|
||||
fetchAllRoleList().then(response => {
|
||||
this.allRoleList = response.data
|
||||
})
|
||||
},
|
||||
getRoleListByAdmin(adminId) {
|
||||
getRoleByAdmin(adminId).then(response => {
|
||||
const allocRoleList = response.data
|
||||
this.allocRoleIds = []
|
||||
if (allocRoleList != null && allocRoleList.length > 0) {
|
||||
for (let i = 0; i < allocRoleList.length; i++) {
|
||||
this.allocRoleIds.push(allocRoleList[i].id)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.btnBox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -163,6 +163,7 @@ export default {
|
|||
this.renderer = null
|
||||
this.camera = null
|
||||
this.aniId = null
|
||||
this.raycaster = null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -776,7 +777,9 @@ export default {
|
|||
this.renderer.setSize(this.width, this.height)
|
||||
// this.renderer.setClearColor(0x03060f, 1) // 设置背景颜色
|
||||
const earth = document.getElementById('earth')
|
||||
earth.appendChild(this.renderer.domElement)
|
||||
if (earth) {
|
||||
earth.appendChild(this.renderer.domElement)
|
||||
}
|
||||
this.animate()
|
||||
})
|
||||
},
|
||||
|
@ -942,7 +945,7 @@ export default {
|
|||
if (this.camera && this.scene && this.scene.getObjectByName('cs')) {
|
||||
this.raycaster.setFromCamera(this.mouse, this.camera)
|
||||
const arr = this.scene.getObjectByName('cs').children.concat(this.scene.getObjectByName('dsxs').children)
|
||||
var intersects = this.raycaster.intersectObjects(arr, true)
|
||||
var intersects = (this.raycaster && arr) ? this.raycaster.intersectObjects(arr, true) : []
|
||||
if (this.activeTab !== 'dsxs') {
|
||||
if (intersects.length) {
|
||||
this.scene.getObjectByName('csText').visible = false
|
||||
|
@ -978,7 +981,7 @@ export default {
|
|||
if (this.camera && this.scene && this.raycaster) {
|
||||
this.raycaster.setFromCamera(this.mouse, this.camera)
|
||||
const arr = this.scene.getObjectByName('cs')?.children
|
||||
var intersects = this.raycaster.intersectObjects(arr, true)
|
||||
var intersects = this.raycaster ? this.raycaster.intersectObjects(arr, true) : []
|
||||
if (intersects && intersects.length) {
|
||||
const hubCode = intersects[0].object.userData.hubCode
|
||||
if (hubCode === 9 || hubCode === 5) {
|
||||
|
|
|
@ -116,7 +116,7 @@ export default {
|
|||
this.orbitControls.update()
|
||||
this.zoomAnimate()
|
||||
this.originPosition = this.camera.position
|
||||
console.log(this.originPosition)
|
||||
// console.log(this.originPosition)
|
||||
const tweenL1 = new TWEEN.Tween(
|
||||
this.camera.position).to({ x: -400, y: 900, z: 1700 }, 1800)
|
||||
.easing(TWEEN.Easing.Sinusoidal.InOut)
|
||||
|
@ -332,7 +332,7 @@ export default {
|
|||
return material
|
||||
},
|
||||
flyAnimation(delta = 0.015) {
|
||||
console.log(this.flyArr)
|
||||
// console.log(this.flyArr)
|
||||
TWEEN.update()
|
||||
if (delta > 0.2) return
|
||||
this.flyArr.forEach(elem => {
|
||||
|
|
|
@ -0,0 +1,234 @@
|
|||
<template>
|
||||
<div class="appCenter">
|
||||
<el-card>
|
||||
<h2>应用中心</h2>
|
||||
<div class="list-btns">
|
||||
<el-form :inline="true" class="demo-form-inline">
|
||||
<el-form-item label="应用类型">
|
||||
<el-select
|
||||
v-model="filterData.instance_type"
|
||||
size="medium"
|
||||
>
|
||||
<el-option label="全部" :value="0" />
|
||||
<el-option label="应用实例" :value="1" />
|
||||
<el-option label="模型实例" :value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
label="应用名称"
|
||||
>
|
||||
<el-input
|
||||
v-model="filterData.instance_name"
|
||||
size="medium"
|
||||
@enter="onSearchClick"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button
|
||||
size="medium"
|
||||
type="info"
|
||||
@click="onSearchClick"
|
||||
>
|
||||
{{ $t('message.search') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
size="medium"
|
||||
@click="resetSearch"
|
||||
>
|
||||
{{ $t('message.reset') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<el-row :gutter="20">
|
||||
<el-col v-for="(item,index) in appCenter" :key="index" :span="6">
|
||||
<el-card class="instanceCard">
|
||||
<img :src="item.logoPath" alt="">
|
||||
<p class="title">{{ item.instanceName }}</p>
|
||||
<el-tag>{{ item.instanceType === 1 ? '应用实例' : '模型实例' }}</el-tag>
|
||||
<el-tag>{{ item.instanceClassChinese }}</el-tag>
|
||||
<br>
|
||||
<p>描述: </p>
|
||||
<div class="desc">{{ item.description }}</div>
|
||||
<p class="version">版本: {{ item.version }}</p>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="goDetail(item)"
|
||||
>立即启用</el-button>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-pagination
|
||||
background
|
||||
:hide-on-single-page="true"
|
||||
:current-page="page"
|
||||
:page-size="10"
|
||||
layout="prev, pager, next"
|
||||
:total="total"
|
||||
@current-change="currentChange"
|
||||
/>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getHpcInstanceList } from '@/api/task/task'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
filterData: {
|
||||
instance_type: 0,
|
||||
instance_name: ''
|
||||
},
|
||||
appCenter: [
|
||||
],
|
||||
fileList: [],
|
||||
page: 1,
|
||||
size: 12,
|
||||
total: 0
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
currentChange(e) {
|
||||
this.page = e
|
||||
this.getList()
|
||||
},
|
||||
getList() {
|
||||
getHpcInstanceList({ ...this.filterData, pageSize: this.size, pageNum: this.page }).then(e => {
|
||||
this.appCenter = e.data.list
|
||||
this.total = e.total
|
||||
})
|
||||
},
|
||||
onSearchClick() {
|
||||
this.getList()
|
||||
},
|
||||
resetSearch() {
|
||||
this.filterData = {
|
||||
instance_type: 0,
|
||||
instance_name: ''
|
||||
}
|
||||
this.getList()
|
||||
},
|
||||
handleClick() {
|
||||
if (this.activeName === '1') {
|
||||
this.form = { env: 'python' }
|
||||
}
|
||||
},
|
||||
goDetail(val) {
|
||||
// this.form = val;
|
||||
// this.activeName = '2';
|
||||
// this.$router.push({ path: '/taskManagement/createInstance' })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.appCenter{
|
||||
// margin: 30px 20px;
|
||||
// .opr-btn{
|
||||
// font-size: 16px;
|
||||
// padding: 10px 36px;
|
||||
// margin-bottom: 30px;
|
||||
// }
|
||||
.el-button--primary{
|
||||
background-color: #468EFC;
|
||||
}
|
||||
}
|
||||
.instanceCard{
|
||||
img{
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
display: block;
|
||||
float: left;
|
||||
background: #ddd;
|
||||
margin: 0 2rem;
|
||||
margin-right: 0rem;
|
||||
}
|
||||
margin: 30px auto;
|
||||
margin-top: 0;
|
||||
.el-tag{
|
||||
margin-left:1rem;
|
||||
float: left;
|
||||
}
|
||||
.desc{
|
||||
margin: 0.05rem 2rem;
|
||||
padding: 0.5rem;
|
||||
border: 1px solid #b1b0b0;
|
||||
text-indent: 1rem;
|
||||
text-align: left;
|
||||
height: 12vh;
|
||||
/* white-space: nowrap; */
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
.el-card__body{
|
||||
padding:0;
|
||||
padding-bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
p{
|
||||
margin: 10px 30px;
|
||||
clear: both;
|
||||
// margin-top: 1rem;
|
||||
font-size: 0.875rem;
|
||||
text-align: left;
|
||||
position: relative;
|
||||
text-indent: 1em;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
p:before{
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 0.5rem;
|
||||
height: 0.5rem;
|
||||
background: #2FB4AA;
|
||||
border-radius: 50%;
|
||||
top: 1.25rem;
|
||||
left: 0em;
|
||||
}
|
||||
.title{
|
||||
margin:20px 0;
|
||||
// margin-bottom: 10px;
|
||||
font-size: 18px;
|
||||
text-indent: 1rem;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
clear: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
.title:before{
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
.version{
|
||||
height: 3vh;
|
||||
padding-top: 0rem
|
||||
}
|
||||
.version:before{
|
||||
top: 0.25rem;
|
||||
|
||||
}
|
||||
.el-button--text{
|
||||
line-height: 1.1rem;
|
||||
}
|
||||
.el-button{
|
||||
margin:10px;
|
||||
border:1px solid #468EFC ;
|
||||
border-radius: 0;
|
||||
}
|
||||
.el-button--default{
|
||||
color: #468EFC;
|
||||
}
|
||||
.insideFloatRight {
|
||||
margin: 0;
|
||||
padding:0;
|
||||
float: right;
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
|
@ -20,6 +20,7 @@
|
|||
tooltip-effect="dark"
|
||||
>
|
||||
<template v-slot:filterBtns>
|
||||
<el-button size="medium" type="primary" @click="openAppCenter">超算应用中心</el-button>
|
||||
<el-button size="medium" type="primary" @click="createItem">{{ $t('message.create') }}</el-button>
|
||||
</template>
|
||||
</List>
|
||||
|
@ -88,6 +89,9 @@ export default {
|
|||
// }
|
||||
},
|
||||
methods: {
|
||||
openAppCenter() {
|
||||
this.$router.push({ path: `appCenter` })
|
||||
},
|
||||
setColumn() {
|
||||
return [
|
||||
{ prop: 'name', label: this.$t('page.taskName'), sortable: true, formatter: (row) => { return <a onClick={() => this.viewDetail(row)}>{row.name}</a> } },
|
||||
|
|
|
@ -0,0 +1,739 @@
|
|||
<template>
|
||||
<div>
|
||||
<h3> {{ $t('page.createTrainingTask') }} </h3>
|
||||
<!-- <el-alert
|
||||
v-if="!adapterId"
|
||||
:title="$t('page.selectDiver')"
|
||||
type="warning"
|
||||
show-icon
|
||||
/> -->
|
||||
<br>
|
||||
<el-form
|
||||
ref="formData"
|
||||
class="form-wrap"
|
||||
label-position="left"
|
||||
:model="formData"
|
||||
:rules="formDataRules"
|
||||
>
|
||||
<el-form-item :label="$t('page.taskName')" prop="name">
|
||||
<el-input
|
||||
v-model="formData.name"
|
||||
:placeholder="$t('page.inputWarn')"
|
||||
:max-length="30"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.taskDes')" prop="description">
|
||||
<el-input
|
||||
v-model="formData.description"
|
||||
:max-length="100"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.resourceType')" prop="resource">
|
||||
<el-radio-group v-model="formData.resource" @input="chooseType">
|
||||
<el-radio-button v-for="(item,index) in resourceRanges" :key="item.type+index" :label="item.type" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="资源范围选择">
|
||||
<el-card v-show="formData.resource">
|
||||
<table class="rangeSelectArea">
|
||||
<tr>
|
||||
<td>CPU使用范围</td>
|
||||
<td><el-slider
|
||||
v-model="formData.cpu"
|
||||
:min="0"
|
||||
:max="singeRange.cpu.max"
|
||||
range
|
||||
/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>内存使用范围</td>
|
||||
<td><el-slider
|
||||
v-model="formData.memory"
|
||||
:min="0"
|
||||
:max="singeRange.memory.max"
|
||||
range
|
||||
show-stops
|
||||
/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>算力卡张数范围</td>
|
||||
<td>
|
||||
<el-input-number v-model="formData.gpu.min" :min="0" :max="singeRange.gpuNumber" />张
|
||||
-
|
||||
<el-input-number v-model="formData.gpu.max" :min="formData.cardStart" :max="singeRange.gpuNumber" />张
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>存储使用范围</td>
|
||||
<td>
|
||||
<el-input-number v-model="formData.storage.min" :min="0" :max="singeRange.storage.max" />G
|
||||
-
|
||||
<el-input-number v-model="formData.storage.max" :min="formData.storage.min" :max="singeRange.storage.max" />G
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</el-card>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.imageName')" prop="image">
|
||||
<el-select v-model="formData.image">
|
||||
<el-option v-for="item in imageList" :key="item.ID" :label="item.info.name" :value="item.ID" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.modelName')" prop="model">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="10">
|
||||
<el-input v-model="formData.modelName" placeholder="请选择模型" :readonly="true" />
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-button @click="() => { dataType = 'model'; clickSelect()}">选择模型</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.algorithmName')" prop="code">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="10">
|
||||
<el-select v-model="formData.code" placeholder="请选择名称" @change="selectCode">
|
||||
<el-option v-for="item in codeList" :key="item.parentPackageID" :label="item.name" :value="item.parentPackageID" />
|
||||
</el-select>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.datasetName')" prop="dataset">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="10">
|
||||
<el-input v-model="formData.datasetName" placeholder="请选择数据集" :readonly="true" />
|
||||
</el-col>
|
||||
<el-col :span="10">
|
||||
<el-button @click="dataType = 'dataset'; clickSelect()">选择数据集</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.resourceRecom')">
|
||||
<el-button type="primary" style="margin-bottom: 1vh;" @click="getResource">刷新</el-button>
|
||||
<table class="tableInput width100">
|
||||
<tr>
|
||||
<th>{{ $t('page.centerName') }}</th>
|
||||
<!-- <th>ID</th> -->
|
||||
<th>选择</th>
|
||||
<th>CPU核数</th>
|
||||
<th>GPU张数</th>
|
||||
<th>卡类型</th>
|
||||
<th>内存1</th>
|
||||
<th>内存2</th>
|
||||
<th>存储空间</th>
|
||||
<th>积分</th>
|
||||
<th>{{ $t('page.more') }}</th>
|
||||
</tr>
|
||||
<tr v-for="(it, index) in algorithmList" :key="index">
|
||||
<td>
|
||||
{{ clusterList.find(s => s.id === it.clusterID).name }}
|
||||
</td>
|
||||
<td>
|
||||
<el-checkbox v-model="it.checked" />
|
||||
</td>
|
||||
<td>
|
||||
{{ it.cpu }}
|
||||
</td>
|
||||
<td>
|
||||
{{ it.gpu }}
|
||||
</td>
|
||||
<td>
|
||||
{{ it.type }}
|
||||
</td>
|
||||
<td>
|
||||
{{ it.ram }}
|
||||
</td>
|
||||
<td>
|
||||
{{ it.vram }}
|
||||
</td>
|
||||
<td>
|
||||
{{ it.storage }}
|
||||
</td>
|
||||
<td>
|
||||
{{ it.jifen }}
|
||||
</td>
|
||||
<td>
|
||||
<el-button @click="viewAlgo(index)">自定义参数编辑</el-button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="计算结果选择" prop="reasonTarget">
|
||||
<el-checkbox-group v-model="formData.reasonTarget">
|
||||
<el-checkbox label="1">回源</el-checkbox>
|
||||
<el-checkbox label="2">直接创建为模型</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="调度策略" prop="scheduleStrategy">
|
||||
<el-radio v-model="formData.scheduleStrategy" label="1">动态集群权重填写</el-radio>
|
||||
<el-radio v-model="formData.scheduleStrategy" label="2" disabled>静态集群权重填写</el-radio>
|
||||
<el-card v-if="formData.scheduleStrategy === '1'">
|
||||
<el-radio v-model="formData.strategy" label="dataLocality">数据优先</el-radio>
|
||||
<el-radio v-model="formData.strategy" label="leastLoadFirst">最小负载</el-radio>
|
||||
</el-card>
|
||||
<el-card v-if="formData.scheduleStrategy === '2'">
|
||||
<el-form-item :label="$t('page.copiesNum')" prop="replicas">
|
||||
<el-input-number v-model="formData.replicas" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.staticWeight')" prop="strategy">
|
||||
<table class="tableInput">
|
||||
<tr v-for="env in formData.staticWeightMap" :key="env.key">
|
||||
<td>{{ env.key }}</td>
|
||||
<td>
|
||||
<el-input-number
|
||||
v-model="env.value"
|
||||
size="small"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</el-form-item>
|
||||
</el-card>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-dialog v-if="dialogFormVisible" :close-on-click-modal="false" title="自定义参数设置" :visible.sync="dialogFormVisible">
|
||||
<el-form ref="editInfoForm" :model="editInfoForm">
|
||||
<el-form-item label="子算法编辑">
|
||||
<el-radio-group v-model="editInfoForm.codeType">
|
||||
<el-radio-button label="1">直接沿用算法</el-radio-button>
|
||||
<el-radio-button label="2">选择子算法</el-radio-button>
|
||||
<el-radio-button label="3">新建子算法</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-card v-if="editInfoForm.codeType === '2'">
|
||||
<List
|
||||
ref="sonList"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="sonColumns"
|
||||
:table-list-data="sonDataList"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
<span v-if="!sonDataList.length">没有子算法</span>
|
||||
</el-card>
|
||||
<el-card v-if="editInfoForm.codeType === '3'">
|
||||
<div class="folder-list">
|
||||
<div class="fold-item">
|
||||
<el-link type="info" :underline="false" @click="intoFold('/', true)">全部文件</el-link>
|
||||
</div>
|
||||
<div v-for="(item, key ) in path.split('/')" :key="key" class="fold-item">
|
||||
<span v-if="item" class="arrow">></span>
|
||||
<el-link v-if="key !== path.split('/').length-1" type="primary" @click="intoFold(item, true)">{{ item }}</el-link>
|
||||
<el-link v-else type="info" :underline="false">{{ item }}</el-link>
|
||||
</div>
|
||||
</div>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale || editInfoForm.filePath"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="allFileList"
|
||||
:pagination="false"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.programVariables')">
|
||||
<el-card>
|
||||
<el-button
|
||||
v-if="editInfoForm.params.length === 0"
|
||||
type="primary"
|
||||
icon="el-icon-circle-plus"
|
||||
@click="appendParams"
|
||||
/>
|
||||
<template v-else>
|
||||
<div v-for="(env, index) in editInfoForm.params" :key="env.id" class="network-wrap">
|
||||
<div class="list-item">
|
||||
<el-input v-model="env.key" placeholder="key" />
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<span>=</span>
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<el-input v-model="env.value" placeholder="value" />
|
||||
</div>
|
||||
<div class="list-item">
|
||||
<el-button
|
||||
v-if="index === 0"
|
||||
icon="el-icon-circle-plus"
|
||||
style="margin-right:8px"
|
||||
@click="appendParams"
|
||||
/>
|
||||
<el-button v-else icon="el-icon-delete-solid" @click="removeParams(index)" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-card>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.commandLine')" prop="command">
|
||||
<el-input
|
||||
v-model="editInfoForm.command"
|
||||
type="textarea"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogFormVisible = false">{{ $t("message.cancel") }}</el-button>
|
||||
<el-button type="primary" @click="submitInfoEdit">{{ $t("message.submit") }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<el-dialog v-if="codeVisible" :close-on-click-modal="false" title="自定义参数设置" :visible.sync="codeVisible">
|
||||
<codemirror v-model="code" class="code-mirror" :options="cmOption" />
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="closeCodeVisible">{{ $t("message.cancel") }}</el-button>
|
||||
<el-button type="primary" @click="submitCode">{{ $t("message.submit") }}</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<select-item v-if="dialogSelectDatasetVisible" v-model="dialogSelectDatasetVisible" :data-type="dataType" @select-item="selectItem" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// import { getInstanceListByModelType, getSubInstanceList } from '@/api/task/task'
|
||||
import generate from 'nanoid/generate'
|
||||
import List from '@/components/list'
|
||||
import { numberToStr } from '@/utils/data-process'
|
||||
import { getResourceRange, getResourceListByfilter, getFileList, getBindingList, downloadFile, updatecode, uploadData, queryCodeList } from '@/api/jcs/jcs'
|
||||
import selectItem from '@/views/fileManagement/datasetManagement/selectItem.vue'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { getClusterList } from '@/api/container/cluster'
|
||||
|
||||
export default {
|
||||
components: { selectItem, List },
|
||||
props: {
|
||||
adapterId: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
codeVisible: false,
|
||||
code: ``,
|
||||
cmOption: {
|
||||
theme: 'darcula',
|
||||
autoCloseBrackets: true,
|
||||
tabSize: 4,
|
||||
styleActiveLine: true,
|
||||
lineNumbers: true,
|
||||
line: true,
|
||||
mode: 'text/x-yaml'
|
||||
},
|
||||
path: '',
|
||||
currentFile: {},
|
||||
allFileList: [],
|
||||
formData: {
|
||||
'name': 'trainingtask-' + generate('abcdefghijklmnopqrstuvwxyz', 12),
|
||||
'description': '',
|
||||
'resource': '',
|
||||
'strategy': '',
|
||||
'datasetName': '',
|
||||
'scheduleStrategy': '',
|
||||
'envs': [],
|
||||
'gpu': {
|
||||
'min': 0,
|
||||
'max': 0
|
||||
},
|
||||
'storage': {
|
||||
'min': 0,
|
||||
'max': 0
|
||||
},
|
||||
'reasonTarget': [],
|
||||
'packageID': '',
|
||||
'codeType': '1'
|
||||
},
|
||||
editInfoForm: {
|
||||
params: []
|
||||
},
|
||||
fileList: [],
|
||||
instanceList: [],
|
||||
resourceRanges: [],
|
||||
singeRange: {
|
||||
'gpuNumber': 0,
|
||||
'cpu': {
|
||||
'max': 0
|
||||
},
|
||||
'memory': {
|
||||
'max': 0
|
||||
},
|
||||
'storage': {
|
||||
'max': 0
|
||||
}
|
||||
},
|
||||
dialogFormVisible: false,
|
||||
algorithmList: [],
|
||||
storageIDs: [],
|
||||
codeList: [],
|
||||
codeVersionList: [],
|
||||
algorithmIndex: null,
|
||||
imageList: [],
|
||||
modelList: [],
|
||||
getNewVersion: false,
|
||||
dialogSelectDatasetVisible: false,
|
||||
clusterList: [],
|
||||
sonDataList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'userID'
|
||||
]),
|
||||
formDataRules() {
|
||||
return {
|
||||
name: [
|
||||
{ required: true, message: this.$t('check.input') + this.$t('message.name') }
|
||||
// {
|
||||
// pattern: /^[a-z]([-a-z0-9]*[a-z0-9])?$/,
|
||||
// message: this.$t('check.inputInvalid')
|
||||
// }
|
||||
// { validator: this.nameValidator }
|
||||
],
|
||||
description: [
|
||||
{ required: true, message: this.$t('check.input') + this.$t('page.taskDes') }
|
||||
],
|
||||
image: [{ required: true, message: this.$t('check.requireSelect'), trigger: 'change' }],
|
||||
model: [{ required: true, message: this.$t('check.requireSelect'), trigger: 'change' }],
|
||||
code: [{ required: true, message: this.$t('check.requireSelect'), trigger: 'change' }],
|
||||
dataset: [{ required: true, message: this.$t('check.requireSelect'), trigger: 'change' }],
|
||||
resource: [{ required: true, message: this.$t('check.requireSelect'), trigger: 'change' }]
|
||||
}
|
||||
},
|
||||
sonColumns() {
|
||||
return [
|
||||
{ prop: 'name', label: this.$t('page.algorithmName'), formatter: (row) => row.name },
|
||||
{ prop: 'description', label: this.$t('page.description'), formatter: (row) => row.description },
|
||||
{ prop: 'createTime', label: this.$t('page.creationTime'), sortable: true, formatter: (row) => {
|
||||
return <div>{new Date(row.createTime).toLocaleString()}</div>
|
||||
} },
|
||||
{ prop: 'more', label: this.$t('page.more'), width: 160, formatter: (row) => {
|
||||
return <el-button onClick={() => { this.selectSonCode(row) }}> {this.$t('message.select')} </el-button>
|
||||
} }
|
||||
]
|
||||
},
|
||||
columns() {
|
||||
return [
|
||||
{ prop: 'name', label: '文件名', minWidth: '30%', formatter: (row) => {
|
||||
const img1 = require('@/assets/img/file-1.png')
|
||||
return <div>
|
||||
{((this.path === '/' ? '' : this.path) + row.path) === this.editInfoForm.filePath ? <i class='el-icon-s-flag' /> : ''}
|
||||
{row.objectID === -1 ? <a onclick={() => this.intoFold(row.path)} ><img style='height: 1.2rem;margin-right: 0.5rem;vertical-align: text-bottom;' src={img1} /><span>{row.path.split('/')[row.path.split('/').length - 1]}</span></a> : <span>{row.path.indexOf('/') === 0 ? row.path.substring(row.path.indexOf('/') + 1) : row.path}</span> }
|
||||
</div>
|
||||
}
|
||||
},
|
||||
{ prop: 'createTime', label: '创建时间', minWidth: '30%', formatter: (row) => { return <span>{row.objectID === -1 ? '-' : row.createTime}</span> } },
|
||||
{ prop: 'size', label: '大小', minWidth: '20%', formatter: (row) => { return <span>{row.objectID !== -1 ? numberToStr(row.size - 0, 'B') : '-'}</span> } },
|
||||
{ prop: '', label: '操作', minWidth: '20%', formatter: (row) => {
|
||||
return row.objectID !== -1 && <div>
|
||||
<el-button disabled={((this.path === '/' ? '' : this.path) + row.path) === this.editInfoForm.filePath} onClick={() => this.selectCodeFile(row)}> {((this.path === '/' ? '' : this.path) + row.path) === this.editInfoForm.filePath ? '已选择' : (this.$t('message.select') + '入口文件')} </el-button>
|
||||
<el-button type='text' onClick={() => this.downloadCode(row)}> 编辑 </el-button>
|
||||
</div>
|
||||
} }
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
mounted() {
|
||||
getResourceRange({ userID: this.userID }).then(res => {
|
||||
const arr = res.data.resourceRanges || []
|
||||
if (arr.length !== 0) {
|
||||
this.resourceRanges = arr.filter(e => {
|
||||
return !(e.gpuNumber === 0 || e.cpu.max === 0 || e.memory.max === 0 || e.storage.max === 0)
|
||||
})
|
||||
}
|
||||
})
|
||||
getClusterList({ 'storageSchedule': 1, pageSize: 1000, pageNum: 1 }).then(e => {
|
||||
this.clusterList = e?.data?.list || []
|
||||
})
|
||||
this.getAllList()
|
||||
},
|
||||
methods: {
|
||||
selectCodeFile(val) {
|
||||
// this.itemList = this.itemList.concat(val)
|
||||
this.editInfoForm.filePath = (this.path === '/' ? '' : this.path) + val.path
|
||||
},
|
||||
selectSonCode(row) {
|
||||
|
||||
},
|
||||
intoFold(path, flag) {
|
||||
if (flag) {
|
||||
this.path = this.path.substring(0, this.path.indexOf(path) + path.length)
|
||||
} else {
|
||||
this.path = (this.path === '/' ? '' : this.path) + path
|
||||
}
|
||||
this.getCodeFileList()
|
||||
},
|
||||
downloadCode(row) {
|
||||
this.currentFile = row
|
||||
downloadFile({
|
||||
userID: this.userID,
|
||||
objectID: row.objectID
|
||||
}).then(n => {
|
||||
this.codeVisible = true
|
||||
this.code = n + ''
|
||||
})
|
||||
},
|
||||
closeCodeVisible() {
|
||||
if (this.getNewVersion) {
|
||||
this.selectCode(this.form.code)
|
||||
}
|
||||
this.codeVisible = false
|
||||
this.getNewVersion = false
|
||||
},
|
||||
submitCode() {
|
||||
updatecode({
|
||||
'userID': this.userID,
|
||||
'bucketID': this.currentFile.bucketID,
|
||||
'packageID': this.currentFile.packageID,
|
||||
'packageName': this.currentFile.packageName
|
||||
}).then(n => {
|
||||
const form = new FormData()
|
||||
form.append('info', JSON.stringify({
|
||||
'userID': this.userID,
|
||||
'packageID': n.data.newPackage?.packageID,
|
||||
'loadTo': this.storageIDs,
|
||||
'loadToPath': ['/']
|
||||
}))
|
||||
const blob = new Blob([this.code], { type: 'text/plain' })
|
||||
const file = new File([blob], encodeURIComponent(this.currentFile.path), { type: 'text/plain' })
|
||||
form.append(`files`, file)
|
||||
uploadData(form).then(e => {
|
||||
if (e.code === 'OK') {
|
||||
this.$message.success('修改成功')
|
||||
this.codeVisible = false
|
||||
this.getNewVersion = true
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
selectCode(val) {
|
||||
getBindingList({ dataType: 'code', param: { userID: this.userID, bindingID: val, type: 'private' }}).then(res => {
|
||||
const arr = res?.data?.datas?.[0]?.packages?.[0]?.versions || []
|
||||
// 默认选择第一个版本
|
||||
this.formData.packageID = arr[0]?.packageID
|
||||
this.codeVersionList = arr
|
||||
})
|
||||
},
|
||||
selectItem(data) {
|
||||
if (this.dataType === 'dataset') {
|
||||
this.formData.dataset = data.ID
|
||||
this.formData.datasetName = data.info?.name
|
||||
} else if (this.dataType === 'model') {
|
||||
this.formData.model = data.ID
|
||||
this.formData.modelName = data.info?.name
|
||||
}
|
||||
this.dialogSelectDatasetVisible = false
|
||||
},
|
||||
clickSelect() {
|
||||
this.dialogSelectDatasetVisible = true
|
||||
},
|
||||
getAllList() {
|
||||
queryCodeList({ dataType: 'code', userID: this.userID, parentPackageID: -1 }).then(e => {
|
||||
this.codeList = e?.data?.packages || []
|
||||
})
|
||||
getBindingList({ dataType: 'image', param: { userID: this.userID, bindingID: -1, type: 'private' }}).then(res => {
|
||||
this.imageList = res?.data?.datas || []
|
||||
})
|
||||
},
|
||||
getResource() {
|
||||
this.$refs.formData.validate((valid) => {
|
||||
if (valid) {
|
||||
getResourceListByfilter({
|
||||
'queryResource': {
|
||||
cpu: { min: this.formData.cpu[0], max: this.formData.cpu[1] },
|
||||
memory: { min: this.formData.memory[0], max: this.formData.memory[1] },
|
||||
gpu: this.formData.gpu,
|
||||
storage: this.formData.storage,
|
||||
type: this.formData.resource
|
||||
}
|
||||
}).then(res => {
|
||||
const algorithmList = []
|
||||
res.data?.resource?.forEach(n => {
|
||||
const arr = n.resources.filter(r => r.resource.type === this.formData.resource)
|
||||
arr?.forEach(i => {
|
||||
algorithmList.push({
|
||||
clusterID: n.clusterID,
|
||||
type: i.resource.type,
|
||||
cpu: i.baseResources?.find(r => r.type === 'CPU')?.available.value,
|
||||
ram: i.baseResources?.find(r => r.name === 'RAM')?.available.value,
|
||||
vram: i.baseResources?.find(r => r.name === 'VRAM')?.available.value,
|
||||
storage: i.baseResources?.find(r => r.type === 'STORAGE')?.available.value,
|
||||
runtime: { command: '', envs: {}, params: {}}
|
||||
})
|
||||
})
|
||||
})
|
||||
this.algorithmList = algorithmList
|
||||
})
|
||||
} else {
|
||||
this.$message({
|
||||
message: '请先输入上述内容',
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
chooseType(val) {
|
||||
const range = this.resourceRanges.find(e => e.type === val)
|
||||
this.singeRange = range
|
||||
},
|
||||
submitUpload() {
|
||||
// 阻止默认上传行为
|
||||
return false
|
||||
},
|
||||
submitInfoEdit() {
|
||||
// if ( === '') {
|
||||
// this.$message.error('未修改文件')
|
||||
// return
|
||||
// }
|
||||
const obj = {}
|
||||
this.editInfoForm.params.forEach((item) => {
|
||||
obj[item.key] = item.value
|
||||
})
|
||||
|
||||
this.dialogFormVisible = false
|
||||
this.algorithmList[this.algorithmIndex].runtime = {
|
||||
command: this.editInfoForm.command,
|
||||
envs: obj,
|
||||
params: obj
|
||||
}
|
||||
},
|
||||
appendParams() {
|
||||
this.editInfoForm.params.push(
|
||||
{
|
||||
key: '',
|
||||
value: ''
|
||||
}
|
||||
)
|
||||
},
|
||||
removeParams(i) {
|
||||
this.editInfoForm.params.splice(i, 1)
|
||||
},
|
||||
getCodeFileList() {
|
||||
const params = {
|
||||
'queryParams': {
|
||||
'dataType': 'code',
|
||||
'userID': this.userID,
|
||||
'packageID': Number(this.formData.code),
|
||||
'path': '',
|
||||
'CurrentPage': 1,
|
||||
'pageSize': 9999,
|
||||
'orderBy': 'name'
|
||||
}
|
||||
}
|
||||
getFileList(params).then(e => {
|
||||
if (e.data?.uploadedDatas?.[0].objects) {
|
||||
this.allFileList = e.data?.uploadedDatas?.[0].objects.map(n => ({
|
||||
...n,
|
||||
bucketID: e.data?.uploadedDatas?.[0].bucketID,
|
||||
packageName: e.data?.uploadedDatas?.[0].packageName
|
||||
}))
|
||||
this.storageIDs = e.data?.uploadedDatas[0].uploadedCluster.map(e => e.storageID).filter(Boolean)
|
||||
}
|
||||
this.dialogFormVisible = true
|
||||
})
|
||||
},
|
||||
viewAlgo(index) {
|
||||
this.algorithmIndex = index
|
||||
if (this.formData?.code) {
|
||||
this.getCodeFileList()
|
||||
queryCodeList({ dataType: 'code', userID: this.userID, parentPackageID: this.formData.code }).then(e => {
|
||||
this.sonDataList = e?.data?.packages || []
|
||||
})
|
||||
this.getCodeFileList()
|
||||
// this.getNewVersion = false
|
||||
} else {
|
||||
this.$message({ message: '请选择算法', type: 'warning' })
|
||||
}
|
||||
},
|
||||
checkForm() {
|
||||
let returnVal
|
||||
this.$refs.formData.validate((valid) => {
|
||||
if (valid) {
|
||||
const clusters = []
|
||||
this.algorithmList.forEach(n => {
|
||||
if (n.checked) {
|
||||
clusters.push({
|
||||
clusterID: n.clusterID,
|
||||
runtime: { command: n.runtime.command, envs: n.runtime.envs, params: n.runtime.params },
|
||||
resources: [
|
||||
{ type: 'CPU', number: n.cpu },
|
||||
{ type: 'GPU', number: n.gpu },
|
||||
{ type: 'RAM', number: n.ram },
|
||||
{ type: 'VRAM', number: n.vram }
|
||||
]
|
||||
})
|
||||
}
|
||||
})
|
||||
const form = {
|
||||
'userID': this.userID,
|
||||
'jobSetInfo': {
|
||||
'jobs': [
|
||||
{
|
||||
'localJobID': '1',
|
||||
'name': this.formData.name,
|
||||
'description': this.formData.description,
|
||||
'type': 'PCM',
|
||||
'files': {
|
||||
'dataset': {
|
||||
'type': 'Binding',
|
||||
'bindingID': this.formData.dataset
|
||||
},
|
||||
'model': {
|
||||
'type': 'Binding',
|
||||
'bindingID': this.formData.model
|
||||
},
|
||||
'code': {
|
||||
'type': 'Binding',
|
||||
'bindingID': this.formData.code
|
||||
},
|
||||
'image': {
|
||||
'type': 'Binding',
|
||||
'bindingID': this.formData.image
|
||||
}
|
||||
},
|
||||
'jobResources': {
|
||||
'scheduleStrategy': this.formData.strategy,
|
||||
// dataLocality, leastLoadFirst
|
||||
'clusters': clusters
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
returnVal = form
|
||||
} else {
|
||||
returnVal = false
|
||||
}
|
||||
})
|
||||
return returnVal
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.form-wrap .el-form-item__label-wrap .el-form-item__label{
|
||||
text-indent: -1rem!important;
|
||||
}
|
||||
.rangeSelectArea{
|
||||
padding-right: 1rem;
|
||||
width: 100%;
|
||||
td:nth-child(odd) {
|
||||
width: 8rem;
|
||||
}
|
||||
tr{
|
||||
height: 4rem;
|
||||
}
|
||||
// .el-slider{
|
||||
// // width: 50%;
|
||||
// }
|
||||
}
|
||||
.network-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0.625rem;
|
||||
// margin: 0 0.625rem;
|
||||
.list-item+.list-item {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -27,7 +27,7 @@
|
|||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item :label="$t('page.dispatchAdapter')" prop="adapterId">
|
||||
<el-form-item v-if="taskType!=='trainingTask'" :label="$t('page.dispatchAdapter')" prop="adapterId">
|
||||
<el-select v-model="formData.adapterId" :disabled="isEdit" class="selectPro" :placeholder="$t('message.pleaseChoose')">
|
||||
<el-option
|
||||
v-for="item in adapterList[taskType]"
|
||||
|
@ -45,9 +45,10 @@
|
|||
<application-form v-show="cpType === 'cloud'&&taskType === 'application'" ref="application" />
|
||||
<hpc-create v-if="cpType === 'hpc'&&taskType === 'hpcBase'" ref="hpcBase" />
|
||||
<vasp-create v-if="cpType === 'hpc'&&taskType === 'hpcVasp'" ref="hpcVasp" />
|
||||
<ai-create v-if="cpType === 'ai'&&taskType!=='deductive'" ref="aiBase" :type="taskType" :adapter-id="formData.adapterId" />
|
||||
<ai-create v-if="cpType === 'ai'&&taskType!=='deductive'&&taskType!=='trainingTask'" ref="aiBase" :type="taskType" :adapter-id="formData.adapterId" />
|
||||
<vm-form v-if="taskType === 'virtualmachine'" ref="virtualmachine" />
|
||||
<deductive-form v-if="taskType === 'deductive'" ref="deductive" :adapter-id="formData.adapterId" />
|
||||
<training-task v-if="taskType === 'trainingTask'" ref="trainingTask" :adapter-id="formData.adapterId" />
|
||||
</div>
|
||||
<!-- <div v-if="taskType === 'virtualmachine' && selectCluster">
|
||||
</div> -->
|
||||
|
@ -204,11 +205,11 @@
|
|||
<el-row type="flex" justify="end">
|
||||
<el-col :span="2.5">
|
||||
<el-button size="medium" @click="goBack">{{ $t("message.cancel") }}</el-button>
|
||||
<el-button v-if="!selectCluster&&!strategySetting&&taskType!=='aiCard'&&taskType!=='deductive'&&taskType!=='hpcVasp'" size="medium" type="primary" @click="next">{{ $t('message.next') }}</el-button>
|
||||
<el-button v-if="!selectCluster&&!strategySetting&&taskType!=='aiCard'&&taskType!=='deductive'&&taskType!=='hpcVasp'&&taskType !== 'trainingTask'" size="medium" type="primary" @click="next">{{ $t('message.next') }}</el-button>
|
||||
<el-button v-if="selectCluster" size="medium" type="primary" @click="selectCluster=false">{{ $t('message.before') }}</el-button>
|
||||
<el-button v-if="selectCluster&&!strategySetting&&taskType!=='aiCard'&&taskType!=='deductive'" size="medium" type="primary" @click="setStrategy">{{ $t('message.next') }}</el-button>
|
||||
<el-button v-if="selectCluster&&!strategySetting&&taskType!=='aiCard'&&taskType!=='deductive'&&taskType !== 'trainingTask'" size="medium" type="primary" @click="setStrategy">{{ $t('message.next') }}</el-button>
|
||||
<el-button v-if="strategySetting" size="medium" type="primary" @click="strategySetting=false;selectCluster=true">{{ $t('message.before') }}</el-button>
|
||||
<el-button v-if="strategySetting || taskType==='aiCard' || taskType==='deductive' || taskType==='hpcVasp'" v-loading="submitLoading" size="medium" type="primary" @click="saveForm">{{ $t('message.create') }}</el-button>
|
||||
<el-button v-if="strategySetting || taskType==='aiCard' || taskType==='deductive' || taskType==='hpcVasp' || taskType === 'trainingTask'" v-loading="submitLoading" size="medium" type="primary" @click="saveForm">{{ $t('message.create') }}</el-button>
|
||||
<!-- <el-button size="medium" type="primary" @click="saveForm">{{ $t("message.easyCreate") }}</el-button> -->
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
@ -223,14 +224,15 @@ import hpcCreate from './components/hpcCreate.vue'
|
|||
import vaspCreate from './components/hpcVasp.vue'
|
||||
import { getClusterList } from '@/api/container/cluster'
|
||||
import aiCreate from './components/aiCreate.vue'
|
||||
import trainingTask from './components/trainingTask.vue'
|
||||
import { getAdapterList } from '@/api/pcm/adapter'
|
||||
import vmForm from './components/virtualmachineForm.vue'
|
||||
import deductiveForm from './components/deductiveForm.vue'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
import { createTrainingTask } from '@/api/jcs/jcs'
|
||||
// import jobForm from './components/jobForm.vue'
|
||||
export default {
|
||||
components: { applicationForm, List, hpcCreate, aiCreate, vmForm, deductiveForm, vaspCreate },
|
||||
components: { applicationForm, List, hpcCreate, aiCreate, vmForm, deductiveForm, vaspCreate, trainingTask },
|
||||
data() {
|
||||
return {
|
||||
getClusterList,
|
||||
|
@ -263,7 +265,8 @@ export default {
|
|||
'ai': {
|
||||
'aiBase': 'createAibase',
|
||||
'aiCard': 'createAiCard',
|
||||
'deductive': 'createDeductiveTask'
|
||||
'deductive': 'createDeductiveTask',
|
||||
'trainingTask': 'createTrainingTask'
|
||||
}
|
||||
},
|
||||
adapterList: {
|
||||
|
@ -392,6 +395,10 @@ export default {
|
|||
list[i] = e.data.list.filter(r => r.type === '1')
|
||||
break
|
||||
}
|
||||
case 'trainingTask': {
|
||||
list[i] = e.data.list.filter(r => r.type === '1')
|
||||
break
|
||||
}
|
||||
default: {
|
||||
list[i] = e.data.list.filter(r => r.resourceType === '01')
|
||||
break
|
||||
|
@ -457,14 +464,14 @@ export default {
|
|||
this.strategySetting = true
|
||||
},
|
||||
saveForm() {
|
||||
if (!this.formData.adapterId) {
|
||||
if (!this.formData.adapterId && this.taskType !== 'trainingTask') {
|
||||
this.$message.warning(this.$t('page.selectDiver'))
|
||||
return false
|
||||
}
|
||||
const type = this.taskType === 'aiCard' ? 'aiBase' : this.taskType
|
||||
let formHook = this.$refs[type].checkForm()
|
||||
if (!formHook) return false
|
||||
if (this.taskType !== 'deductive') {
|
||||
if (this.taskType !== 'deductive' && this.taskType !== 'trainingTask') {
|
||||
if (this.taskType !== 'aiCard') {
|
||||
formHook = { ...formHook, ...this.formData }
|
||||
}
|
||||
|
@ -482,7 +489,7 @@ export default {
|
|||
formHook.adapterIds = [formHook.adapterId]
|
||||
delete formHook.adapterId
|
||||
}
|
||||
|
||||
console.log(formHook)
|
||||
this.submitLoading = true
|
||||
switch (type) {
|
||||
case 'application': {
|
||||
|
@ -573,6 +580,18 @@ export default {
|
|||
|
||||
break
|
||||
}
|
||||
case 'trainingTask': {
|
||||
// formHook.clusterIds = formHook.aiClusterIds
|
||||
delete formHook.aiClusterIds
|
||||
console.log(formHook)
|
||||
createTrainingTask(formHook).then(() => {
|
||||
this.$message.success(this.$t('page.createdSuccess'))
|
||||
this.$router.push({ path: '/taskManagement/taskList' })
|
||||
}).catch(e => {
|
||||
this.submitLoading = false
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'virtualmachine': {
|
||||
formHook.clusterIds = formHook.aiClusterIds
|
||||
delete formHook.aiClusterIds
|
||||
|
|
|
@ -121,6 +121,8 @@ export default {
|
|||
</el-button>
|
||||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => this.viewDetail(row)}> <el-dropdown-item> {txt} </el-dropdown-item> </span>
|
||||
<span onClick={() => this.viewResult(row)}> <el-dropdown-item> 计算结果 </el-dropdown-item> </span>
|
||||
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
|
@ -130,6 +132,9 @@ export default {
|
|||
viewDetail(row) {
|
||||
this.$router.push({ path: `detail`, query: { id: row.id }})
|
||||
},
|
||||
viewResult(row) {
|
||||
this.$router.push({ path: `result`, query: { id: row.id }})
|
||||
},
|
||||
createItem() {
|
||||
this.$router.push({ path: `create` })
|
||||
}
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
<template>
|
||||
<div class="list-detail">
|
||||
<el-card>
|
||||
<el-page-header :content="$t('page.result')" @back="goBack" />
|
||||
<p />
|
||||
任务结果查看
|
||||
<el-tabs v-model="activeName" type="card">
|
||||
<el-tab-pane :label="$t('page.taskProperties')">
|
||||
<FormData :data="formData" :columns="1" :data-map="dataMap" />
|
||||
<p> {{ $t('page.inCluster') }} :{{ formData.clusterInfos ? formData.clusterInfos.map(e=> e.name).join(',') : '-' }}</p>
|
||||
<p>子任务列表:</p>
|
||||
<List
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="columns"
|
||||
:table-list-data="formData.subTaskInfos"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
<!-- <p>资源详情:</p>
|
||||
<div class="resourceList">
|
||||
<div class="cpu"><p>CPU</p><p>100%</p></div>
|
||||
<div class="mem"><p>MEM</p><p>100%</p></div>
|
||||
<div class="disk"><p>DISK</p><p>100%</p></div>
|
||||
</div> -->
|
||||
</el-tab-pane>
|
||||
<!-- <el-tab-pane label="任务拓扑">
|
||||
<FormData :data="formData" :data-map="dataMap" />
|
||||
|
||||
</el-tab-pane> -->
|
||||
<el-tab-pane v-if="formData.clusterInfos && formData.taskTypeDict !== '11' && formData.taskTypeDict !== '12'" :label="$t('page.taskLog')">
|
||||
<el-select v-if="!formData.subTaskInfos[0].workDir" v-model="cluster" style="width:70%" @change="selectCluster(cluster)">
|
||||
<el-option
|
||||
v-for="item in formData.clusterInfos"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
<p />
|
||||
<el-input v-model="log" type="textarea" rows="20" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-if="formData.taskTypeDict === '11' || formData.taskTypeDict === '12'" :label="$t('page.taskResult')">
|
||||
<el-form>
|
||||
<!-- <el-form-item :label="$t('page.taskCmdInput')">
|
||||
<el-input v-model="taskInput" type="textarea" rows="10" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('page.taskSimulateNum')">
|
||||
<el-input v-model="taskSimulateNum" style="width: 20%;" />
|
||||
</el-form-item>
|
||||
<el-button type="primary">{{ $t('message.submit') }}</el-button>
|
||||
<el-divider />
|
||||
<el-form-item :label="$t('page.taskResult')">
|
||||
<el-input v-model="taskOutput" type="textarea" rows="10" />
|
||||
</el-form-item> -->
|
||||
|
||||
<!-- <el-button type="primary" @click="submitUpload">{{ $t('message.submit') }}</el-button> -->
|
||||
<!-- <el-divider /> -->
|
||||
<el-form-item v-if="formData.taskTypeDict === '11'" :label="$t('page.taskResult')">
|
||||
<List
|
||||
|
||||
ref="multipleTable"
|
||||
:key="$i18n.locale"
|
||||
class="multipleTable"
|
||||
:columns="taskColumns"
|
||||
:table-list-data="taskResult"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
|
||||
</el-form-item>
|
||||
<el-form-item v-if="formData.taskTypeDict === '12'" :label="$t('page.selectCluster')">
|
||||
<el-select v-if="formData.subTaskInfos" v-model="inferId" style="width:30%">
|
||||
<el-option
|
||||
v-for="item in formData.subTaskInfos"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<br>
|
||||
<bootChart v-if="formData.taskTypeDict === '12'" :id="inferId" />
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import List from '@/components/list'
|
||||
import { FormData } from '@/components/FormData'
|
||||
import { getTaskDetail, getTaskLog, getDeductiveDetail, downloadVaspContent } from '@/api/task/task'
|
||||
import { mapGetters } from 'vuex'
|
||||
import bootChart from './components/boot'
|
||||
|
||||
export default {
|
||||
components: { FormData, List, bootChart },
|
||||
data() {
|
||||
return {
|
||||
dataMap: {
|
||||
name: this.$t('page.taskName'),
|
||||
description: this.$t('page.taskDes'),
|
||||
startTime: this.$t('page.startTime2'),
|
||||
endTime: this.$t('page.endTime'),
|
||||
strategy: this.$t('page.policy'),
|
||||
synergyStatus: this.$t('page.synergyStatus')
|
||||
},
|
||||
taskInput: '',
|
||||
taskSimulateNum: '',
|
||||
taskOutput: '',
|
||||
cluster: '',
|
||||
formData: {
|
||||
'clusterInfos': [],
|
||||
'name': '',
|
||||
'description': '',
|
||||
'startTime': '',
|
||||
'endTime': '',
|
||||
'strategy': '0',
|
||||
'synergyStatus': '0'
|
||||
},
|
||||
activeName: '',
|
||||
log: '',
|
||||
taskResult: [],
|
||||
inferId: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'dict'
|
||||
]),
|
||||
columns() {
|
||||
return [
|
||||
{ prop: 'name', label: this.$t('page.subtaskName') },
|
||||
{ prop: 'clusterName', label: this.$t('page.clusterIn') },
|
||||
{ prop: 'status', label: this.$t('page.taskStatus') },
|
||||
{ prop: 'remark', label: this.$t('page.description') }
|
||||
]
|
||||
},
|
||||
taskColumns() {
|
||||
return [
|
||||
{ prop: 'imageName', label: this.$t('page.picName') },
|
||||
{ prop: 'clusterName', label: this.$t('page.clusterIn') },
|
||||
{ prop: 'card', label: this.$t('page.card') },
|
||||
{ prop: 'result', label: this.$t('page.result') }
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getFormData()
|
||||
},
|
||||
methods: {
|
||||
goBack() {
|
||||
this.$router.push('taskList')
|
||||
},
|
||||
getFormData() {
|
||||
getTaskDetail({ id: this.$route.query.id }).then(res => {
|
||||
if (res.data) {
|
||||
this.formData = res.data
|
||||
this.formData.strategy = this.dict.schedule_Strategy.filter(e => { return res.data.strategy.toString() === e.itemValue })[0][this.$i18n.locale === 'en' ? 'itemText' : 'description']
|
||||
this.formData.synergyStatus = !res.data.synergyStatus ? this.$t('page.notSynergistic') : this.$t('page.synergistic')
|
||||
// this.formData.clusterInfos ? this.selectCluster(this.formData.clusterInfos[0]) : ''
|
||||
// this.cluster = this.formData.clusterInfos ? this.formData.clusterInfos[0] : []
|
||||
if (this.formData.taskTypeDict === '11') {
|
||||
getDeductiveDetail(this.$route.query.id).then(e => {
|
||||
this.taskResult = e.data
|
||||
})
|
||||
}
|
||||
if (this.formData.taskTypeDict === '12') {
|
||||
this.inferId = this.formData.subTaskInfos[0].id
|
||||
}
|
||||
if (res.data.subTaskInfos[0].workDir) {
|
||||
downloadVaspContent({ workDir: res.data.subTaskInfos[0].workDir, fileName: 'demo.out', clusterId: this.formData.clusterInfos[0].id }).then(e => {
|
||||
this.log = e
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
selectCluster(id) {
|
||||
this.getLog(this.formData.clusterInfos[0].adapterId, id)
|
||||
},
|
||||
getLog(adapterId, clusterId) {
|
||||
getTaskLog(adapterId, clusterId, this.$route.query.id, 0).then(e => {
|
||||
this.log = e.log
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.resourceList{
|
||||
width: 99%;
|
||||
margin: 20px auto;
|
||||
.cpu, .disk, .mem{
|
||||
width: 33%;
|
||||
height: 15vh;
|
||||
float: left;
|
||||
margin: 20px 0;
|
||||
background: url(../../../assets/images/CPU.png) no-repeat center;
|
||||
background-size: auto 100%;
|
||||
p{
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
text-shadow: 0px 5px 10px rgba(108,190,254,0.25);
|
||||
background: linear-gradient(0deg, #A3D2FF 0%, #00C0FA 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
margin-top: 2.5vh;
|
||||
margin-bottom: 5vh;
|
||||
}
|
||||
}
|
||||
.disk{
|
||||
background: url(../../../assets/images/DISK.png) no-repeat center;
|
||||
background-size: auto 100%;
|
||||
}
|
||||
.mem{
|
||||
background: url(../../../assets/images/MEM.png) no-repeat center;
|
||||
background-size: auto 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -54,6 +54,18 @@ module.exports = {
|
|||
// changeOrigin: true,
|
||||
// secure: false
|
||||
// },
|
||||
'/jcs': {
|
||||
ws: false,
|
||||
target: 'https://ai4m.jointcloud.net/',
|
||||
changeOrigin: true,
|
||||
secure: false
|
||||
},
|
||||
'/jsm': {
|
||||
ws: false,
|
||||
target: 'https://ai4m.jointcloud.net/',
|
||||
changeOrigin: true,
|
||||
secure: false
|
||||
},
|
||||
'^/pcm': {
|
||||
ws: false,
|
||||
// target: 'https://jcos.jointcloud.net:443/',
|
||||
|
@ -63,12 +75,25 @@ module.exports = {
|
|||
changeOrigin: true,
|
||||
secure: false
|
||||
},
|
||||
'^/jcc-': {
|
||||
ws: false,
|
||||
// target: 'https://10.101.15.6/apis', /* 测试环境 */
|
||||
target: 'https://dev.jointcloud.net/apis',
|
||||
changeOrigin: true,
|
||||
secure: false
|
||||
},
|
||||
'^/ai4m': {
|
||||
ws: false,
|
||||
target: 'https://ai4m.jointcloud.net:443/',
|
||||
changeOrigin: true,
|
||||
secure: false
|
||||
},
|
||||
'^/blockChain': {
|
||||
ws: false,
|
||||
target: 'https://ai4m.jointcloud.net:443/',
|
||||
changeOrigin: true,
|
||||
secure: false
|
||||
},
|
||||
'^/auth': {
|
||||
ws: false,
|
||||
target: 'https://comnet.jointcloud.net/',
|
||||
|
|