Compare commits

..

1 Commits

Author SHA1 Message Date
jagger e98a8ac104 arm64 2024-10-17 09:54:48 +08:00
109 changed files with 1740 additions and 12479 deletions

View File

@ -11,7 +11,7 @@ on:
env:
REGISTRY: registry.cn-hangzhou.aliyuncs.com # 修改为你的阿里云镜像仓库地址
IMAGE_NAME: jcce/jcce-rip # 修改为你的阿里云镜像仓库名称
IMAGE_TAG: latest
IMAGE_TAG: offline-latest
jobs:
build:
@ -38,26 +38,17 @@ jobs:
username: ${{ secrets.ALIYUN_USERNAME }}
password: ${{ secrets.ALIYUN_PASSWORD }}
- name: Get commit ID and build time
id: get_tags
run: |
echo "::set-output name=build_time::$(date +'%Y%m%d%H%M%S')"
- name: Build and push multi-arch image
run: |
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} \
-t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.get_tags.outputs.build_time }} \
--push .
docker buildx build --platform linux/amd64,linux/arm64 -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} --push .
- name: Set up Kubernetes CLI
uses: azure/setup-kubectl@v1
- name: Configure kubeconfig
- name: Set up SSH key
run: |
mkdir -p ~/.kube
echo "${{ secrets.KUBECONFIG }}" > ~/.kube/config
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
- name: Restart Deployment
run: kubectl rollout restart deployment ${{ secrets.SSH_DEPLOYMENT }}
- name: SSH to remote server and restart deployment
if: github.event_name != 'pull_request'
run: ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} "kubectl rollout restart deployment ${{ secrets.SSH_DEPLOYMENT }} -n ${{ secrets.SSH_NAMESPACE }}"

View File

@ -41,8 +41,7 @@
"passwordMsg": "The password can not be less than 6 digits",
"check": "Check",
"submit": "Submit",
"instance": "Instance",
"select": "Select"
"instance": "Instance"
},
"menu": {
"taskManagement": "Task",
@ -93,7 +92,6 @@
"resourceList": "API Management",
"oplList": "Operation Logs",
"login": "Login",
"register": "Register",
"monitorSelect": "Monitor",
"monitorSelectBk": "Resource Center",
"monitorSelectNew": "PCM Overview",
@ -105,14 +103,7 @@
"appObserve": "App Monitoring",
"logMana": "Log Mgmt",
"monitorSelectPcm": "JCCE",
"fileManagement": "File Management",
"blockchain": "存证查验",
"blockchainLog": "数据可信核验",
"blockchainBrowser": "区块链浏览器",
"datasetManagement": "数据集管理",
"algorithmManagement": "算法管理",
"imageManagement": "镜像管理",
"modelManagement": "模型管理"
"fileManagement": "File Management"
},
"check": {
"input": "Please Input",
@ -247,7 +238,6 @@
"password": "Password",
"createVirtualmachine": "Create Virtual Machine",
"createHpcbase": "Create Supercomputing Base Template",
"createVasp": "Create Vasp Task",
"createAibase": "Create Intelligent Computing Task",
"createAiCard": "Create Specific Computing Power Card Task",
"dict": "Dictionary",
@ -560,7 +550,6 @@
"result": "Result",
"pictureUpload": "Picture Upload",
"createDeductiveTask": "Create Deductive Task",
"createTrainingTask": "中国算力网——智算训练任务创建",
"image": "Image",
"initFile": "Init File",
"codeUpload": "Code Upload",
@ -579,32 +568,6 @@
"application": "Application",
"deployment": "Deployment",
"instanceCenter": "Instance Center",
"instanceType": "Instance Type",
"createVaspTask": "Create Vasp Task",
"partition": "Partition",
"cmdScript": "Script",
"fileUpload": "File Upload",
"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"
"instanceType": "Instance Type"
}
}

View File

@ -41,8 +41,7 @@
"passwordMsg": "密码不能少于6位",
"check": "验证",
"submit": "提交",
"instance": "实例",
"select": "选择"
"instance": "实例"
},
"menu": {
"taskManagement": "任务管理",
@ -93,7 +92,6 @@
"resourceList": "接口管理",
"oplList": "操作日志",
"login": "登录",
"register": "注册",
"monitorSelect": "综合运控",
"monitorSelectBk": "资源中心",
"monitorSelectNew": "PCM总览",
@ -105,16 +103,7 @@
"appObserve": "应用观测",
"logMana": "日志管理",
"monitorSelectPcm": "云际算力网基础平台",
"fileManagement": "文件管理",
"blockchain": "存证查验",
"blockchainLog": "数据可信核验",
"blockchainBrowser": "区块链浏览器",
"datasetManagement": "数据集管理",
"algorithmManagement": "算法管理",
"imageManagement": "镜像管理",
"modelManagement": "模型管理",
"personalCenter": "个人中心",
"pointManagement": "积分管理"
"fileManagement": "文件管理"
},
"check": {
"input": "请输入",
@ -249,9 +238,8 @@
"password": "密码",
"createVirtualmachine": "创建虚拟机",
"createHpcbase": "创建超算基础模板",
"createVasp": "中国算力网-创建Vasp任务",
"createAibase": "创建智算训练任务",
"createAiCard": "中国算力网-创建指定算力卡训练任务",
"createAiCard": "创建指定算力卡训练任务",
"dict": "字典",
"dictName": "字典名称",
"dictCode": "code",
@ -562,7 +550,6 @@
"result": "结果",
"pictureUpload": "图片上传",
"createDeductiveTask": "创建智算推理任务",
"createTrainingTask": "中国算力网——智算训练任务创建",
"image": "镜像",
"initFile": "启动文件",
"codeUpload": "代码上传",
@ -581,32 +568,6 @@
"application": "应用",
"deployment": "部署",
"instanceCenter": "实例中心",
"instanceType": "实例类型",
"createVaspTask": "创建Vasp任务",
"partition": "分区",
"cmdScript": "脚本",
"fileUpload": "文件上传",
"uploadSuccess": "上传成功",
"cpCluster": "算力集群",
"computingResource": "计算资源",
"internet": "访问Internet",
"visualization": "可视化",
"codeBranch": "代码分支",
"runParams": "运行参数",
"imageName": "镜像名称",
"packageName": "Package名称",
"targetCluster": "目标集群",
"datasetCategory": "数据集类别",
"resourceRecom": "资源推荐",
"authSetting": "访问权限设置",
"applyList": "申请列表",
"applyAccount": "申请用户",
"applyDataset": "申请使用数据集名称",
"applyModel": "申请使用模型名称",
"category": "类别",
"datasetApplied": "申请使用数据集名称",
"modelApplied": "申请使用模型名称",
"forApply": "可申请数据集",
"sonAlgorithmName": "子算法名称"
"instanceType": "实例类型"
}
}

View File

@ -1,282 +0,0 @@
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'
})
}

View File

@ -1,89 +0,0 @@
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'
})
}

View File

@ -1,35 +0,0 @@
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
})
}

View File

@ -1,272 +0,0 @@
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
})
}

View File

@ -19,8 +19,3 @@ export const getHomeOverview = () => {
export const getSituation = () => {
return request({ url: '/pcm/v1/monitoring/schedule/situation', method: 'get' })
}
export const getCpList = () => {
return request({ url: '/ai4m/v1/screen/resources', method: 'get' })
}

View File

@ -37,9 +37,7 @@ 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 })
}
@ -49,12 +47,6 @@ export const addApp = (data) => {
export const addHpcTask = (data) => {
return request({ url: '/pcm/v1/hpc/commitHpcTask', method: 'post', data })
}
export const uploadVaspContent = (data) => {
return request({ url: '/ai4m/v1/sftp/upload', method: 'post', data })
}
export const downloadVaspContent = (params) => {
return request({ url: '/ai4m/v1/sftp/download', method: 'get', params })
}
export const addVirtualMachine = (data) => {
return request({ url: '/pcm/v1/core/commitVmTask', method: 'post', data })
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -26,16 +26,6 @@
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'"
>
@ -107,7 +97,6 @@
:key="index"
:prop="item.prop"
:label="item.label"
:min-width="item.minWidth"
:width="item.width"
:formatter="item.formatter"
:sortable="item.sortable"
@ -313,12 +302,6 @@ 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

File diff suppressed because one or more lines are too long

View File

@ -59,12 +59,6 @@
<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>
@ -162,10 +156,6 @@ 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' })
@ -182,10 +172,6 @@ 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' })
@ -195,7 +181,7 @@ export default {
},
async logout() {
await this.$store.dispatch('user/logout')
this.$router.push(`/login`)
this.$router.push(`/login?redirect=${this.$route.fullPath}`)
}
}
}

View File

@ -1,17 +0,0 @@
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 || [] })
}
}

View File

@ -8,7 +8,7 @@ import getPageTitle from '@/utils/get-page-title'
NProgress.configure({ showSpinner: false }) // NProgress Configuration
const whiteList = ['/login', '/register', '/auth-redirect'] // no redirect whitelist
const whiteList = ['/login', '/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 { roles, menuNames, id } = await store.dispatch('user/getInfo')
const { roleName } = await store.dispatch('user/getInfo')
store.dispatch('user/getUserID', id)
// // get user menus
// const menus = await store.dispatch('user/getMenus')
// 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', { menuNames, roles })
const accessRoutes = await store.dispatch('permission/generateRoutes', { menus, roleName })
// dynamically add accessible routes
router.addRoutes(accessRoutes)
@ -71,6 +71,7 @@ router.beforeEach(async(to, from, next) => {
}
} else {
/* has no token*/
if (whiteList.indexOf(to.path) !== -1) {
// in the free login whitelist, go directly
next()

View File

@ -7,8 +7,7 @@ import Layout from '@/layout'
// import emptyLayout from '@/layout/emptyLayout'
import podRouter from './modules/pod'
import virtualMachineRouter from './modules/virtualMachine'
import blockchainManagementRouter from './modules/blockchain'
import personalCenter from './modules/personalCenter'
import blockChainRouter from './modules/blockChain'
import functionsRouter from './modules/functions'
import permissionRouter from './modules/permissionManagement'
import monitorRouter from './modules/warnManagement'
@ -69,13 +68,6 @@ 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'),
@ -107,17 +99,6 @@ export const constantRoutes = [
component: () => import('@/views/monitorSelectPcm/index'),
meta: { title: 'monitorSelectPcm' },
hidden: true
},
{
path: '/resourceList',
component: () => import('@/views/cluster/resourceList'),
hidden: true
},
{
path: '/monitorSelectDev',
component: () => import('@/views/monitorSelectDev/index'),
meta: { title: 'monitorSelectDev' },
hidden: true
}
// {
// path: '/resourceList',
@ -163,7 +144,7 @@ export const asyncRoutes = [
},
podRouter,
virtualMachineRouter,
blockchainManagementRouter,
blockChainRouter,
functionsRouter,
permissionRouter,
monitorRouter,
@ -174,8 +155,7 @@ export const asyncRoutes = [
taskManagementRouter,
strategyManagementRouter,
adapterMangementRouter,
fileManagementRouter,
personalCenter
fileManagementRouter
]
const createRouter = () => new Router({

View File

@ -1,27 +1,40 @@
import Layout from '@/layout'
const blockchainManagementRouter = {
path: '/blockchain',
import emptyLayout from '@/layout/emptyLayout'
const blockChainRouter = {
path: '/blockChain',
component: Layout,
name: 'blockchain',
name: '云际记账',
meta: {
title: 'blockchain',
icon: 'qukuailian'
title: '云际记账',
icon: 'yunjijizhang'
},
children: [
{
path: 'blockchainBrowser',
component: () => import('@/views/blockChain/blockchainBrowser'),
name: 'blockchainBrowser',
meta: { title: 'blockchainBrowser', icon: 'gailan', affix: true },
hidden: false
path: 'blockChainBrowser',
component: () => import('@/views/blockChain/blockChainBrowser'),
name: 'blockChainBrowser',
meta: { title: '块链浏览器', icon: 'gailan', affix: true }
},
{
path: 'blockchainLog',
component: () => import('@/views/blockChain/blockchainLog'),
name: 'blockchainLog',
meta: { title: 'blockchainLog', icon: 'qukuailianchaxun', affix: true },
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 },
hidden: false
}
]
}
export default blockchainManagementRouter
export default blockChainRouter

View File

@ -1,57 +1,19 @@
import Layout from '@/layout'
// import emptyLayout from '@/layout/emptyLayout'
const fileManagementRouter = {
path: '/fileManagement',
component: Layout,
meta: {
title: 'storageMana',
title: 'fileManagement',
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/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 },
component: () => import('@/views/fileManagement/fileList/list'),
name: 'fileManagement',
meta: { title: 'overview', icon: 'gailan', affix: true },
hidden: false
}
]
}
export default fileManagementRouter

View File

@ -2,7 +2,6 @@ import Layout from '@/layout'
const permissionRouter = {
path: '/permissionManagement',
component: Layout,
name: 'permissionManagement',
meta: {
title: 'authManagement',
icon: 'xiangmuguanli'
@ -36,13 +35,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

View File

@ -1,20 +0,0 @@
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

View File

@ -5,7 +5,7 @@ const taskManagementRouter = {
name: 'taskManagement',
meta: {
title: 'taskManagement',
icon: 'renwuguanli1'
icon: 'rongqizu'
},
children: [
{
@ -36,47 +36,33 @@ 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: 'renwuliebiao1', affix: true },
meta: { title: 'taskList', icon: 'gailan', affix: true },
hidden: false
},
{
path: 'cloudList',
component: () => import('@/views/taskManagement/cloudList/taskList'),
name: 'cloudList',
meta: { title: 'cloudList', icon: 'shusuanziyuan', affix: true },
meta: { title: 'cloudList', icon: 'gailan', affix: true },
hidden: false
},
{
path: 'aiList',
component: () => import('@/views/taskManagement/aiList/taskList'),
name: 'aiList',
meta: { title: 'aiList', icon: 'zhisuanrenwu', affix: true },
meta: { title: 'aiList', icon: 'gailan', affix: true },
hidden: false
},
{
path: 'hpcList',
component: () => import('@/views/taskManagement/hpcList/taskList'),
name: 'hpcList',
meta: { title: 'hpcList', icon: 'chaosuan', affix: true },
meta: { title: 'hpcList', icon: 'gailan', affix: true },
hidden: false
},
{
path: 'appCenter',
component: () => import('@/views/taskManagement/hpcList/appCenter'),
name: 'appCenter',
meta: { activeMenu: '/taskManagement/hpcList' },
hidden: true
}
]
}

View File

@ -7,8 +7,6 @@ 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,

View File

@ -5,14 +5,14 @@ import { asyncRoutes, constantRoutes } from '@/router'
* @param routes asyncRoutes
* @param roles
*/
export function filterAsyncRoutes(routes, menuNames) {
export function filterAsyncRoutes(routes, menus) {
const res = []
routes.forEach(route => {
const tmp = { ...route }
if (menuNames.includes(tmp.name)) {
if (menus.includes(tmp.name)) {
if (tmp.children) {
tmp.children = filterAsyncRoutes(tmp.children, menuNames)
tmp.children = filterAsyncRoutes(tmp.children, menus)
}
res.push(tmp)
}
@ -33,13 +33,13 @@ const mutations = {
}
const actions = {
generateRoutes({ commit }, { roles, menuNames }) {
generateRoutes({ commit }, { menus, roleName }) {
return new Promise(resolve => {
let accessedRoutes = []
if (roles.includes('admin')) {
if (roleName === 'admin') {
accessedRoutes = asyncRoutes
} else {
accessedRoutes = filterAsyncRoutes(asyncRoutes, menuNames)
accessedRoutes = filterAsyncRoutes(asyncRoutes, menus)
}
commit('SET_ROUTES', accessedRoutes)
resolve(accessedRoutes)

View File

@ -2,18 +2,14 @@
import {
login,
logout,
getInfo
// , getUserMenus
} from '@/api/authority/permissionManagement'
import { getUserID } from '@/api/jcs/jcs'
import { getToken, setToken, removeToken, setBCToken } from '@/utils/auth'
getInfo } from '@/api/authority/user'
import { getUserMenus } from '@/api/authority/menu'
import { getToken, setToken, removeToken } 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: [],
@ -33,12 +29,6 @@ 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
},
@ -65,10 +55,9 @@ const actions = {
const { username, password } = userInfo
return login(username, password).then(response => {
const data = response.data
const tokenStr = data.tokenHead + data.token
const tokenStr = data.token
commit('SET_TOKEN', tokenStr)
setToken(tokenStr)
setBCToken(tokenStr)
})
},
@ -86,6 +75,7 @@ const actions = {
res.forEach((e, index) => {
data[dictMap[index]] = e.data.list
})
commit('SET_DICT', data)
resolve(data)
}).catch(error => {
@ -96,39 +86,15 @@ 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 { roles, username, menus, id } = data
const menuNames = collectId(menus, names)
commit('SET_MENU', menuNames)
commit('SET_ROLES', roles)
const { roleName, username } = data
commit('SET_ROLES', [roleName])
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)
@ -136,35 +102,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)

View File

@ -21,18 +21,18 @@
> .el-tabs__header {
border-bottom: 1px solid var(--tabsHeaderBorderColor);
.el-tabs__item {
border-left: none;
background: rgba(255,255,255,0.1);
margin-right: 0.2rem;
border-left: 1px solid var(--tabsHeaderBorderColor);
border-bottom: none;
&:first-child {
border-left: none;
}
&.is-active {
border-bottom: 0.15rem solid #3C9CFF;
border-bottom-color: var(--tabsHeaderBorderColor);
}
}
.el-tabs__nav {
border: none;
border: 1px solid var(--tabsHeaderBorderColor);
border-bottom: none;
}
}
}
@ -192,25 +192,3 @@
}
}
}
.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;
}

View File

@ -477,8 +477,7 @@ span.default {
padding-left: 40px;
}
.el-tabs--card > .el-tabs__header .el-tabs__nav {
border-radius: 0;
border: none;
border-radius: 0.75rem 2px 0 0;
}
.el-tabs__header {
margin: 0 0 1.5rem;
@ -801,30 +800,16 @@ 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-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 {
.el-radio-button__inner {
background: rgba(255, 255, 255, 0.4);
border: none;
color: #FFFFFF;
padding: 0.75rem 1.25rem;
}
.el-checkbox-group{
text-align: left;
}
.el-radio-button:first-child .el-radio-button__inner, .el-checkbox-button:first-child .el-checkbox-button__inner{
.el-radio-button:first-child .el-radio-button__inner{
border: none;
}
.el-checkbox-button__inner{
border-left: 1px solid #dddddd;
}
.el-radio-button__inner:hover {
color: #FFFFFF;
}
@ -935,76 +920,4 @@ 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;
}

View File

@ -9,12 +9,6 @@ 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 => {

View File

@ -1,64 +0,0 @@
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

View File

@ -21,6 +21,7 @@
:pagination="true"
page-key="pageNum"
limit-key="pageSize"
:default-sort="{prop: 'createTime', order: 'ascending'}"
tooltip-effect="dark"
@total-fetched="getTotalAdapter"
>

View File

@ -1,18 +1,46 @@
<template>
<div class="blockchainBrowser">
<div>
<el-card>
<Exhibition :data="exhibitionArray" />
</el-card>
<el-row>
<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-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-card>
</el-col>
<el-col :span="9">
<el-card>
</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">
<div slot="header" class="clearfix">
<span>最近7日交易量</span>
</div>
@ -21,384 +49,347 @@
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-card>
<el-col :span="8">
<el-card class="blockList" style="min-height: 380px">
<div slot="header" class="clearfix">
<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>
<span>交易</span>
</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="12">
<el-card :class="currentBlock === null ? '' : 'arrow-left'">
<el-col :span="8">
<el-card class="blockList" style="min-height: 380px">
<div slot="header" class="clearfix">
<span>{{ currentBlock === null ? '最新交易' : '区块'+currentBlock.number+'的交易' }}</span>
<el-button v-if="currentBlock!== null" style="float: right; padding: 0;" type="text" @click="getFiveRecord()">返回</el-button>
<span>评论</span>
</div>
<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>
<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>
<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 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>
<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" />
</div>
</el-dialog>
<!-- <DataList v-model="dialogCertVisible" :transaction-data="transactionData" /> -->
</div>
</template>
<script>
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'
import moment from 'moment'
import List from '@/components/list'
import Exhibition from '@/components/Exhibition'
import viewCertification from '@/mixin/viewCertification'
import * as echarts from 'echarts'
export default {
components: {
// DataList,
FormData },
mixins: [blockChain],
FormData,
Exhibition,
List
},
mixins: [viewCertification],
data() {
return {
currentBlock: null,
blockchainDetail: false,
dialogCertVisible: false,
transactionData: {},
certificationData: {},
transactionMap: {
id: '交易ID',
typeName: '记录类型',
txHash: '交易哈希',
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
}
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: [],
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: []
}
]
tradeList: [],
dialogDetailVisible: false,
detailData: {},
dataMap: {
transId: '交易ID',
ledgerName: '数据标题',
txHash: '交易哈希',
createDate: '交易时间',
blockHash: '区块哈希',
blockNum: '区块高度'
}
}
},
watch: {
dialogCertVisible(val) {
if (val === false) {
this.getSearch()
}
computed: {
tradeListLength() {
return this.tradeList.length >= 5 ? 5 : this.tradeList.length
}
},
mounted() {
this.$nextTick(() => {
this.getSearch()
this.$Api.getCurrentChannel().then(res => {
this.currentChannel = res.currentChannel
localStorage.setItem('currentChannel', this.currentChannel)
this.getBlockList()
this.getStatisticsCount()
this.getUserCount()
this.getTradeCount()
this.getChartData()
})
},
methods: {
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
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
}]
}
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)
})
}
// 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" scoped>
.blockchainBrowser{
.num{
display: flex;
overflow: hidden;
white-space: nowrap;
img{
height: 10vh;
margin-right: 0.625rem;
}
>div{
font-family: Impact;
font-size: 1.625rem;
color: #FFFFFF;
}
<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{
font-size: 0.9rem;
color: #9EACBE;
font-family: Impact;
font-size: 36px;
}
}
.block{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
min-height: 46vh;
.block-name{
.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;
}
}
.hash-name{
}
.blockListItem{
width: 25%;
float: left;
// margin: 10px;
padding: 10px;
.item{
border: 1px solid #eeeeee;
padding: 5px 10px;
padding-top: 15px;
position: relative;
}
.active{
background-color: #5b7595;
transition: all .3s cubic-bezier(.7, .3, .1, 1);
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;
}
}
.tag{
background: rgba(255, 255, 255, 0.1);
border-radius: 0.75rem;
.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{
font-size: 0.8rem;
margin: 0 0.5rem;
padding: 0.5vh 0.7vh;
float: right;
text-align: left;
width: 410px;
margin: auto;
padding: 10px 15px;
}
#lineChart{
width: 100%;
height: 16vh;
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%;
}
}
}
.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;
}
#lineChart{
width: 100%;
height: 30vh;
}
</style>

View File

@ -0,0 +1,106 @@
<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>

View File

@ -0,0 +1,56 @@
<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>

View File

@ -1,353 +0,0 @@
<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>

View File

@ -1,97 +0,0 @@
<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>

View File

@ -1,109 +0,0 @@
<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>

View File

@ -1,237 +0,0 @@
<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]"
/>
<!-- 234积分相关 567文件相关 89任务相关 -->
<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>

View File

@ -1,288 +0,0 @@
<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>

View File

@ -2,14 +2,13 @@
<div>
<Navbar />
<el-card class="list-detail">
<el-page-header content="算力清单" @back="goBack" />
<el-page-header content="资源清单" @back="goBack" />
<List
ref="multipleTable"
class="multipleTable"
:columns="columns"
:pagination="false"
list-key="data"
:get-list-action="getCpList"
func-name="getServerResourceData"
/>
</el-card>
</div>
@ -18,38 +17,34 @@
<script>
import List from '@/components/list'
import Navbar from '@/layout/components/Navbar'
import { getCpList } from '@/api/pcm/dashboard'
export default {
components: { List, Navbar },
data() {
return {
getCpList,
columns: [
{ prop: 'name', label: '名称' },
// { prop: 'ip', label: 'ip' },
// { prop: 'publicIp', label: 'ip' },
// { prop: 'hpcPartition', label: '' },
// { prop: 'cpuName', label: 'cpu' },
// { prop: 'cpuGHz', label: 'cpu' },
// { prop: 'cpuCores', label: 'cpu' },
// { prop: 'cpuSingleCycle', label: 'cpu' },
// { prop: 'cpuGFlops', label: 'cpu/GFlops' },
// { prop: 'totalThreads', label: 'cpu线' },
// { prop: 'gpuDcu', label: 'gpudcu' },
// { prop: 'gpuGFlops', label: 'gpu/GFlops' },
// { prop: 'memory', label: '' },
{ prop: 'resourceType', label: '算力资源类型' },
{ prop: 'num', label: '卡数(张)' },
{ prop: 'singleTFLOPS', label: '单卡算力(TFLOPS@FP32)' },
// { prop: 'region', label: '' },
{ prop: 'totalPFLOPS', width: 140, label: '算力总量(PFLOPS@FP32)' }
{ prop: 'name', label: '资产名称' },
{ prop: 'ip', label: 'ip' },
{ prop: 'publicIp', label: '公网ip' },
{ prop: 'hpcPartition', label: '超算队列' },
{ prop: 'cpuName', label: 'cpu名称' },
{ prop: 'cpuGHz', label: 'cpu单核主频' },
{ prop: 'cpuCores', label: 'cpu单节点核心数' },
{ prop: 'cpuSingleCycle', label: 'cpu单周期指令执行数' },
{ prop: 'cpuGFlops', label: 'cpu理论峰值/GFlops' },
{ prop: 'totalThreads', label: 'cpu单节点线程数' },
{ prop: 'gpuDcu', label: 'gpu或dcu名称' },
{ prop: 'gpuGFlops', label: 'gpu理论峰值/GFlops' },
{ prop: 'memory', label: this.$t('page.memory') },
{ prop: 'num', label: '节点数' },
{ prop: 'region', label: '地域' },
{ prop: 'flops', width: 140, label: '理论峰值/GFlops' }
]
}
},
methods: {
goBack() {
this.$router.push('/monitorSelectPcm')
this.$router.push('/cluster/clusterMapViews')
}
}

View File

@ -1,165 +0,0 @@
<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>

View File

@ -1,370 +0,0 @@
<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>

View File

@ -1,556 +0,0 @@
<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>

View File

@ -1,116 +0,0 @@
<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>

View File

@ -1,179 +0,0 @@
<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>

View File

@ -1,183 +0,0 @@
<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>

View File

@ -1,232 +0,0 @@
<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>

View File

@ -1,573 +0,0 @@
<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>

View File

@ -0,0 +1,423 @@
<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>

View File

@ -1,676 +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="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>

View File

@ -1,144 +0,0 @@
<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>

View File

@ -1,146 +0,0 @@
<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>

View File

@ -1,335 +0,0 @@
<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>

View File

@ -1,143 +0,0 @@
<template>
<div class="chainList">
<ul class="chain" :style="'width: '+ blockChainList*7 + 'vw'">
<li v-for="(item, index) in blockChainList" :key="index" class="chainItem">
<div class="item" @click="goChain" />
<div class="itemChain" />
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
blockChainList: [
{
name: ''
},
{
name: ''
},
{
name: ''
},
{
name: ''
},
{
name: ''
}
],
active: 0,
timer: ''
}
},
mounted() {
this.$nextTick(() => {
const vw = window.innerWidth / 100
const elwrapper = document.getElementsByClassName('chainList')[0]
elwrapper.style.width = '25vw'
const elBody = document.getElementsByClassName('chain')[0]
const elRow = document.getElementsByClassName('chainItem')
for (const node of elRow) {
node.style.width = '7vw'
}
elBody.style.left = 0
elBody.style.transactionDuration = '2000ms'
this.timer = setInterval(() => {
if (this.active < parseInt(this.blockChainList.length) - 2) {
this.active += 1
elBody.style.left = parseInt(elBody.style.left) - parseInt(vw * 3.5) + 'px'
} else {
if (this.isClear) {
clearInterval(this.timer)
}
// if (this.isAgain) {
this.active = 0
elBody.style.left = 0
// } else {
// clearInterval(this.timer)
// }
}
}, '5000')
})
},
destroyed() {
clearInterval(this.timer)
},
methods: {
goChain() {
this.$store.dispatch('user/setRouteType', 'blockChain')
this.$router.push({ path: '/blockChain/blockList' })
}
}
}
</script>
<style lang="scss" scoped>
.chainList{
width: 100%;
height: 6vh;
overflow: hidden;
position: relative;
padding: 0 10px;
ul {
width: 1000px;
height: 6vh;
list-style: none;
// overflow-x: auto;
white-space: nowrap;
margin: 0;
padding: 0;
position: absolute;
transition:left 1s ease-in-out;
left: 0;
}
li{
width: 7vw;
height: 6vh;
display: block;
float: left;
.item{
width: 50%;
height: 6vh;
display: block;
cursor: pointer;
background: url('../../../assets/monitor/chainItem.png') center no-repeat;
background-size: contain;
float: left;
position: relative;
.data{
display: block;
position: absolute;
width: 200px;
height: 50px;
z-index: 99;
border: 1px solid rgba(62, 223, 252, 1);
background-color: rgba(1, 14, 41, 0.8);
color: #ffffff;
// display: none;
}
&:hover{
background-image: url('../../../assets/monitor/chainItemClick.png');
// background-position: -1px -1px;
.data{
display: block;
}
}
}
.itemChain{
width: 50%;
height: 1vh;
margin-top: 2vh;
float: left;
// position: absolute;
background: url('../../../assets/monitor/chain.png') center no-repeat;
background-size: contain;
}
}
}
</style>

View File

@ -1,312 +0,0 @@
<template>
<!-- 计算域信息 -->
<div style="height:100%">
<el-row class="top">
<el-col :span="10"><div class="img" /></el-col>
<el-col :span="14">
<div class="text">
<el-carousel direction="vertical" :autoplay="true" @change="changeItem">
<el-carousel-item v-for="(item, index) in areaItem" :key="'areaItem' + index" class="areaList">
<div class="area">{{ item.domainName || 'DomainName' }}</div>
<table>
<tr>
<td>
<span>资源类型</span>
</td>
<td>
{{ item.resourceType }}
</td>
</tr>
<tr>
<td>
<span>适配技术栈</span>
</td>
<td>
{{ item.stack }}
</td>
</tr>
</table>
</el-carousel-item>
</el-carousel>
</div>
</el-col>
</el-row>
<el-row class="bottom">
<el-col :span="10">
<div id="radarChart" ref="radarChart" style="width: 100%; height: 16vh" />
</el-col>
<el-col :span="14">
<div class="text">
<table>
<tr>
<td>
<span>本地存储</span>
</td>
<td>
<el-progress :stroke-width="8" :percentage="Number(computePercent.diskUsage)" />
</td>
<td>
<span>/ {{ computePercent.diskTotal }} GB</span>
</td>
</tr>
<tr>
<td>
<span>节点数</span>
</td>
<td>
<el-progress :stroke-width="8" :percentage="Number(computePercent.nodeUsage)" />
</td>
<td>
<span> / {{ computePercent.nodeTotal }} </span>
</td>
</tr>
<tr>
<td>
<span>内存</span>
</td>
<td>
<el-progress :stroke-width="8" :percentage="Number(computePercent.memoryUsage)" />
</td>
<td>
<span>/ {{ computePercent.memoryTotal }} GB</span>
</td>
</tr>
<tr>
<td>
<span>cpuUsage</span>
</td>
<td>
<el-progress :stroke-width="8" :percentage="Number(computePercent.cpuUsage)" />
</td>
<td>
<span>/ {{ computePercent.cpuTotal }} Core</span>
</td>
</tr>
</table>
</div>
</el-col>
</el-row>
</div>
</template>
<script>
import * as echarts from 'echarts'
import { getComputeArea } from '@/api/container/monitorSelect.js'
import { debounce } from '@/utils'
export default {
data() {
return {
areaItem: [],
radarChart: undefined,
computePercent: {
diskUsage: 0,
memoryUsage: 0,
nodeUsage: 0,
cpuUsage: 0
}
}
},
mounted() {
getComputeArea().then((res) => {
this.areaItem = res.data.domainResourceList
const charts = echarts.init(this.$refs.radarChart)
const { diskUsage, memoryUsage, nodeUsage, cpuUsage } = this.areaItem[0]
this.computePercent = this.areaItem[0]
charts.setOption(this.returnRadarChart([diskUsage, memoryUsage, nodeUsage, cpuUsage]))
window.addEventListener('resize', debounce(() => {
charts.resize()
}, 100))
this.radarChart = charts
})
},
methods: {
changeItem(e) {
const { diskUsage, memoryUsage, nodeUsage, cpuUsage } = this.areaItem[e]
this.computePercent = this.areaItem[e]
this.radarChart.setOption(this.returnRadarChart([diskUsage, memoryUsage, nodeUsage, cpuUsage]))
},
fontSize(rem) {
const scale = window.innerHeight / 900
console.log(scale)
return scale >= 1 ? 16 * rem : 14 * rem
},
returnRadarChart(data) {
return {
tooltip: {
trigger: 'item',
backgroundColor: '#000033',
textStyle: { color: '#fff' },
borderWidth: 0,
position: 'right'
},
radar: {
radius: '60%',
shape: 'circle',
splitArea: {
show: false,
areaStyle: {
color: ['rgba(255,255,255,0.45)', 'rgba(255,255,255,0.35)', 'rgba(255,255,255,0.25)', 'rgba(255,255,255,0.15)', 'rgba(255,255,255,0.1)']
}
},
splitLine: {
lineStyle: {
color: 'rgba(14, 55, 100, 1)'
}
},
axisLine: { // 线
show: false // show
},
name: { // ()
formatter: '{value}',
textStyle: {
fontSize: this.fontSize(0.7)
}
},
indicator: [
{ name: '本地存储', max: 100 },
{ name: '内存', max: 100 },
{ name: '节点数', max: 100 },
{ name: 'cpuUsage', max: 100 }
],
nameGap: 4
},
series: [{
name: '计算域信息',
type: 'radar',
symbol: 'none',
data: [
{
value: data
}
],
itemStyle: {
color: ['red'],
opacity: 1
},
lineStyle: {
color: 'rgba(35, 162, 236, 0.8)',
type: 'dashed'
},
areaStyle: //
{
color: 'rgba(1, 154, 251, 0.5)'
}
}]
}
}
}
}
</script>
<style lang="scss" scoped>
.top{
// display: flex;
// justify-content: space-between;
// padding: 5px 3%;
margin: 1vh 0;
::v-deep .el-carousel__indicators{
display: none;
}
.img{
height: 8vh;
background: url('../../../assets/images/monitorSelect/computingArea.png') center no-repeat;
background-size: auto 100%;
// margin-left: 3vw;
}
}
.text{
// width: 65%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
height: 8vh;
.areaList{
height: 8vh;
}
span{
font-size: 1rem;
}
.area{
height: 2vh;
line-height: 2vh;
font-size: 1.13rem;
margin: 0.4vh 0;
background-image: linear-gradient(0deg, #00C0FF 0%, #ffffff 100%);
background-clip: text;
-webkit-text-fill-color: transparent;
}
table{
padding: 0;
border-spacing: 0px;
width: 100%;
td{
@media screen and (max-height: 900px) {
transform: scale(0.8);
transform-origin: 0 0;
}
color: #DDDDDD;
height: 3vh;
}
}
}
.bottom{
margin-top: 2vh;
.text{
margin-top: 1.5vh;
height: 14vh;
}
table tr td:nth-child(2) {
padding-right: 2.5rem;
}
span{
margin: 0;
// height: 2.4vh;
// line-height: 3.4vh;
// @media screen and (max-height: 900px) {
// transform: scale(0.8);
// transform-origin: 0 0;
// }
}
}
::v-deep {
.el-progress{
height: 2.4vh;
line-height: 2.4vh;
}
.el-progress-bar{
margin: 0;
line-height: 2.5rem;
margin-right: 0px;
padding-right: 0px;
margin-left: -10px;
}
.el-progress__text{
color: white;
font-size: 0.5rem!important;
}
.el-progress-bar__outer {
background-color: rgba(135, 189, 245, 0.2);
}
.el-progress-bar__inner{
background-image: linear-gradient(90deg, #419eff, #00d9a6);
}
}
// @media screen and (min-width: 1921px) {
// .top{
// .img{
// width: auto;
// height: 100%;
// }
// .text{
// .area{
// font-size: 20px;
// }
// }
// }
// }
</style>

View File

@ -1,96 +0,0 @@
<template>
<!-- 算力中心总数 -->
<div>
<div class="two">
<div v-for="(item, index) in dataArray" :key="'data'+index">
<p class="title">{{ item.name }}</p>
<div class="num">{{ item.value }}</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
dataArray: [
{
name: '算力中心总数(计算域)',
value: 34
},
{
name: '已接入算力 POps@FP16',
value: '112.06'
},
{
name: '接入集群数',
value: '48'
}
]
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
.two{
display: flex;
justify-content: space-between;
margin-top: 10px;
// text-align: center;
>div{
padding: 10px;
padding-top: 0;
background: url('../../../assets/images/monitorSelect/dataBg.png') no-repeat left;
background-size: auto 100%;
}
.title{
font-size: 1.1rem;
margin: 0.5rem;
margin-bottom: 0.3rem;
letter-spacing: 0.1rem;
font-weight: bold;
color: #DDDDDD;
}
.num{
font-size: 1.9rem;
font-family: Impact;
font-weight: 400;
// padding-bottom: 5px;
text-align: right;
width: 80%;
// text-indent: 130%;
letter-spacing: 0.1rem;
display: inline-block;
padding: 0 15px 3px;
}
}
// @media screen and (min-width: 1921px) {
// .one{
// background-size: 39px 39px;
// font-size: 20px;
// .num{
// font-size: 38px;
// }
// }
// .two{
// p{
// margin: 16px 0 ;
// }
// .title{
// font-size: 14px;
// }
// .num{
// font-size: 27px;
// padding: 0 17px 5px;
// }
// }
// }
</style>

View File

@ -1,219 +0,0 @@
<!-- 算力使用趋势 -->
<template>
<div :id="id" ref="echart" style="width: 100%; height: 80%" />
</template>
<script>
import { debounce } from '@/utils'
export default {
name: 'LineChart',
props: {
id: {
type: String,
default: ''
},
data: {
type: Object,
default: () => ({})
},
config: {
type: Object,
default: () => ({})
},
type: {
type: Number,
default: 0
}
},
data() {
return {
Data: { used: [], xData: [] }
// xDataNumber: 120,
}
},
watch: {
data: {
handler(newValue, oldValue) {
// console.log(newValue)
const TempData = JSON.parse(JSON.stringify(newValue))
this.Data.used = TempData.used
this.Data.xData = TempData.xData
this.drawLine()
},
deep: true
}
},
mounted() {
// this.Data = { used: [59688.1, 59252.5, 59189.0, 55766.5, 55537.2, 54804.4, 52764.9], xData: ["2022-06-30", "2022-07-31", "2022-07-31", "2022-08-31", "2022-09-30", "2022-10-31", "2022-11-30"] }
this.$nextTick(() => {
this.drawLine()
})
},
destroyed() {
clearInterval(this.timer)
},
methods: {
fontSize(rem) {
const scale = window.innerHeight / 900
return scale >= 1 ? 16 * rem : 12 * rem
},
drawLine() {
const scaleRate = window.innerHeight / 1080 >= 1
// domecharts
const chart = this.$echarts.init(this.$refs.echart)
var option
option = {
title: {
text: '',
textStyle: {
color: '#008B45'
}
},
color: ['rgba(79, 172, 254, 1)'],
tooltip: {
trigger: 'axis',
axisPointer: {
show: false
},
backgroundColor: '#000033',
textStyle: { fontSize: this.fontSize(0.7), color: '#fff' },
borderWidth: 0
},
grid: {
right: '5%',
bottom: '25%',
top: scaleRate ? '15%' : '20%',
left: '13%'
},
xAxis: {
type: 'category',
boundaryGap: false,
data: this.Data.xData,
axisLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}
},
axisLabel: {
show: true,
interval: 28,
// rotate: -18,
// padding: [1, 0, 0, -10],
margin: scaleRate ? 14 : 10,
textStyle: {
fontSize: this.fontSize(0.75),
lineHeight: scaleRate ? 20 : 10,
color: '#DDDDDD',
fontFamily: 'Source Han Sans CN'
},
formatter: function(params) {
return params.slice(5).replaceAll('-', '/')
}
// formatter: function(params) {
// switch (params) {
// case '2023-04-30':
// return params.slice(2).replaceAll('-', '/')
// case '2023-03-31':
// return params.slice(2).replaceAll('-', '/')
// case '2023-02-28':
// return params.slice(2).replaceAll('-', '/')
// case '2023-01-31':
// return params.slice(2).replaceAll('-', '/')
// case '2022-12-31':
// return params.slice(2).replaceAll('-', '/')
// case '2022-11-30':
// return params.slice(2).replaceAll('-', '/')
// case '2022-10-31':
// return params.slice(2).replaceAll('-', '/')
// case '2022-09-30':
// return params.slice(2).replaceAll('-', '/')
// default:
// // return params.slice(2).replaceAll('-', '/')
// }
// }
},
axisTick: {
// x
show: false
}
},
yAxis: {
type: 'value',
name: this.config.unit,
// nameTextStyle: { //
// padding: this.config.unit.length > 7 ? [0, 0, 0, 45] : [0, 0, 0, 0]
// },
nameTextStyle: {
color: '#aaa',
fontSize: this.fontSize(0.75),
nameLocation: 'start'
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}
},
nameGap: 10,
data: [],
axisLine: {
lineStyle: {
color: '#fff'
}
},
axisLabel: {
show: true,
interval: 0,
align: 'right',
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)',
fontFamily: 'Source Han Sans CN'
}
},
scale: true,
min: 0,
splitNumber: 3
},
series: [
{
name: this.config.status[0] ? this.config.status[0] : '',
type: 'line',
symbol: 'none',
label: {
show: false
},
data: this.Data.used,
areaStyle: {
opacity: 1,
color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgba(0, 242, 254, 1)' // 0%
},
{
offset: 1,
color: 'rgba(79, 172, 254, 1)' // 100%
}
])
}
}
],
animation: true,
animationDuration: function(idx) {
//
return idx * 500
},
animationEasing: 'backln'
}
chart.setOption(option)
window.addEventListener('resize', debounce(() => {
chart.resize()
}, 100))
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,306 +0,0 @@
<!-- 算力使用情况 -->
<template>
<div :id="id" ref="echart" style="width: 95%; height: 85%" />
</template>
<script>
import { debounce } from '@/utils'
export default {
name: 'Histogram',
props: {
id: {
type: String,
default: ''
},
data: {
type: Object,
default: () => { }
},
config: {
type: Object,
default: () => ({})
}
},
data() {
return {
timer: null,
Data: {
unused: [], used: [], xData: []
},
barWidth: '40%',
Max: 0
}
},
watch: {
data: {
handler(newValue, oldValue) {
const Data = { unused: [], used: [], xData: [] }
clearInterval(this.timer)
const TempData = JSON.parse(JSON.stringify(newValue))
// if (TempData.xData.length <= 5) {
// this.barWidth = this.fontSize(1.62)
// } else {
// this.barWidth = this.fontSize(0.81)
// }
Data.xData = TempData.xData
Data.used = TempData.used ? TempData.used : []
Data.unused = TempData.unused ? TempData.unused : []
if (Data.unused.length !== 0) { this.Max = Math.max(...Data.used) + Math.max(...Data.unused) } else { this.Max = Math.max(...Data.used) }
const num = this.digit(this.Max)
let number = this.Max.toString()[0]
number = parseFloat(number)
if (number < 9) {
number++
if (num <= 3) { this.Max = number + '00' } else if (num <= 4) { this.Max = number + '000' } else if (num <= 5) { this.Max = number + '0000' }
} else {
if (num <= 3) { this.Max = 1000 } else if (num <= 4) { this.Max = 10000 } else if (num <= 5) { this.Max = 100000 }
}
if (TempData.xData.length <= 5) {
this.Data = Data
this.drawLine()
} else {
this.Data.unused = Data.unused.slice(0, 5)
this.Data.used = Data.used.slice(0, 5)
this.Data.xData = Data.xData.slice(0, 5)
this.drawLine()
this.timer = setInterval(() => {
const unused = Data.unused.shift()
const used = Data.used.shift()
const xData = Data.xData.shift()
Data.unused.push(unused)
Data.used.push(used)
Data.xData.push(xData)
this.Data.unused = Data.unused.slice(0, 5)
this.Data.used = Data.used.slice(0, 5)
this.Data.xData = Data.xData.slice(0, 5)
this.drawLine()
}, 3000)
}
},
deep: true
}
},
mounted() {
// this.Data = {
// used: [1400, 700, 200, 800, 600], xData
// : ["", "", "", "GPU",""]
// }
this.$nextTick(() => {
this.drawLine()
})
},
destroyed() {
clearInterval(this.timer)
},
methods: {
fontSize(rem) {
const scale = window.innerHeight / 900
return scale >= 1 ? 16 * rem : 12 * rem
},
drawLine() {
const scaleRate = window.innerHeight / 900 >= 1
const chart = this.$echarts.init(this.$refs.echart)
var option
option = {
title: {
text: '',
textStyle: {
color: '#008B45'
},
padding: [10, 0, 0, 10] //
},
color: ['rgba(135, 189, 245, 1)', 'rgba(62, 223, 252, 1)', 'rgba(5, 155, 252, 1)'],
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'none',
show: false
},
backgroundColor: '#000033',
textStyle: { fontSize: this.fontSize(0.7), color: '#fff' },
borderWidth: 0
},
legend: {
right: '0',
itemWidth: 15,
selectedMode: false, //
textStyle: {
color: '#fff',
fontSize: this.fontSize(0.75),
fontFamily: 'Source Han Sans CN'
}
},
grid: {
right: '1%',
bottom: '20%',
top: scaleRate ? '15%' : '20%',
left: '15%'
},
xAxis: {
type: 'category',
data: this.Data.xData,
axisLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}
},
axisLabel: {
show: true,
interval: 0,
textStyle: {
fontSize: this.fontSize(0.75),
lineHeight: scaleRate ? 20 : 10,
color: 'rgba(221, 221, 221, 1)',
fontFamily: 'Source Han Sans CN'
},
margin: scaleRate ? (this.config.unit.length > 10 ? 35 : 8) : 10,
formatter: function(params) {
var provideNumber = 4 //
return params.slice(0, provideNumber) + (params.length > provideNumber ? '...' : '')
}
},
axisTick: {
// x
alignWithLabel: true
}
},
yAxis: {
type: 'value',
// offset: this.config.unit.length > 10 ? -40 : 0,
splitLine: {
show: true,
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}
},
name: this.config.unit,
nameTextStyle: {
color: '#aaa',
padding: [0, 10, 0, 0],
fontSize: this.fontSize(0.75),
nameLocation: 'start'
},
nameGap: 10,
data: [],
axisLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}
},
axisLabel: {
show: true,
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)',
fontFamily: 'Source Han Sans CN'
}
},
scale: true,
min: 0,
max: 30000,
splitNumber: 3
},
series: [
{
name: this.config.status[0] ? this.config.status[0] : '',
type: 'bar',
stack: 'total',
barWidth: this.barWidth,
label: {
show: false
},
emphasis: {
focus: 'series'
},
data: this.Data.used ? this.Data.used : [],
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: 'rgb(24, 144, 255)' // 0%
},
{
offset: 1,
color: 'rgba(24, 144, 255,0.5)' // 100%
}
],
global: false // false
}
}
},
{
name: this.config.status[1] ? this.config.status[1] : '',
type: 'bar',
stack: 'total',
barWidth: this.barWidth,
label: {
show: false
},
emphasis: {
focus: 'series'
},
data: this.Data.unused !== [] ? this.Data.unused : [],
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: 'rgba(30, 231, 231,0.5)' // 0%
},
{
offset: 1,
color: 'rgb(30, 231, 231)' // 100%
}
],
global: false // false
}
}
}
],
animation: true,
animationDuration: function(idx) {
//
return idx * 100
},
animationEasing: 'backln'
}
chart.setOption(option)
window.addEventListener('resize', debounce(() => {
chart.resize()
}, 100))
},
digit(val) {
let num = Math.trunc(val)
// const number = num.toString() //
// var temp = num
var count = 0
if (num === 0) {
return 0
} else {
while (num !== 0) {
count++ //
num = parseInt(num / 10) // num 使
}
return count
}
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,154 +0,0 @@
<template>
<div class="taskArea">
<el-row class="taskDiv">
<el-col v-for="(item,index) in taskDetail" :key="'task'+index" :span="8">
<div class="num">{{ item.num }}</div>
<div class="name">{{ item.name }}</div>
</el-col>
</el-row>
<dt-srcoll v-if="fresh" class="scrollList" :new-data="dutyRateData" :menu-data="menuData" :line-height="7" :is-again="true" :table-height="37" />
</div>
</template>
<script>
import DtSrcoll from '../components/scroll'
export default {
components: {
DtSrcoll
},
props: {
data: {
type: Object,
default: () => ({})
}
},
data() {
return {
taskDetail: [
{
name: '运行任务合计',
num: 0
},
{
name: '运行卡时数',
num: 0
},
{
name: '运行时长',
num: 0
}
],
menuData: [ //
{
name: '作业名称',
prop: 'name'
},
{
name: '作业状态',
prop: 'status'
},
{
name: '策略',
prop: 'strategy'
},
{
name: '协同状态',
prop: 'synergyStatus'
},
{
name: '承接方',
prop: 'serviceName'
}
],
dutyRateData: [],
fresh: false
}
},
watch: {
data: {
handler(newValue, oldValue) {
this.fresh = false
this.taskDetail[0].num = newValue.totalCount
this.taskDetail[1].num = newValue.cardTime
this.taskDetail[2].num = newValue.totalRunTime
this.dutyRateData = newValue.tableData.map(e => { e.strategy = '时间优先'; return e })
this.$nextTick(() => {
this.fresh = true
})
},
deep: true
}
}
}
</script>
<style lang="scss" scoped>
.taskArea{
height: 29vh;
}
.scrollList{
height: 32vh;
overflow: hidden;
}
.taskDiv{
display: flex;
justify-content: space-between;
text-align: center;
margin-bottom: 1%;
// height: calc(100% - 190px);
>div{
// width: 25%;
.num{
font-size: 1.5rem;
font-family: Impact;
color: #FFFFFF;
letter-spacing: 0.1rem;
// height: 3vh;
// line-height: 4vh;
height: 30%;
line-height: 200%;
}
.name{
font-size: 1rem;
letter-spacing: 0.1rem;
font-weight: bold;
height: 70%;
line-height: 300%;
background: url('../../../assets/images/monitorSelect/task.png') no-repeat center;
background-size: auto 100%;
}
}
}
::v-deep{
.el-table--mini th, .el-table--mini td{
// padding: 0.375rem 0;
height: 2vh;
padding: 0;
}
.el-table--mini th{
height: 4vh;
}
.el-table thead {
font-size: 1rem;
}
.el-table__body {
font-size: 0.9rem;
}
}
// @media screen and (min-width: 1921px) {
// .taskDiv{
// margin-bottom: 1%;
// >div{
// .num{
// font-size: 26px;
// }
// .name{
// font-size: 16px;
// height: 80px;
// line-height: 55px;
// }
// }
// }
// }
</style>

View File

@ -1,232 +0,0 @@
<!-- 计算资源负载 -->
<template>
<div id="myBarEchart" ref="myBarEchart" style="width: 100%; height: 80%" />
</template>
<script>
import * as echarts from 'echarts'
import { getTotalAverage } from '@/api/top-menu/TotalNum'
import moment from 'moment'
import { debounce } from '@/utils'
export default {
data() {
const day = [[], [], [], [], [], [], []]
for (let i = 0; i < 7; i++) {
day[i][0] = moment().subtract(7 - i, 'days').endOf('day').unix()
day[i][1] = moment().subtract(7 - i, 'days').endOf('day').format('MMDD')
}
return {
day,
cpuAverage: [], // cpu
ramAverage: [] //
}
},
computed: {
jcceTheme() {
return localStorage.getItem('jcceTheme')
}
},
mounted() {
this.getAllData()
},
methods: {
fontSize(rem) {
const scale = window.innerHeight / 900
return scale >= 1 ? 16 * rem : 12 * rem
},
//
async getAllData() {
await getTotalAverage().then(res => {
const data = res.data
// cpu (%)
const cpuData = data.find(item => item.metric_name === 'cpu_avg_usage').data.result[0].values || []
cpuData.forEach(element => {
this.cpuAverage.push((element[1] - 0).toFixed(2))
// this.date.push(moment(element[0] * 1000).format('MM/DD'))
})
this.cpuAverage = this.cpuAverage.slice(0, 7)
// (%)
const ramAverage = data.find(item => item.metric_name === 'mem_avg_usage').data.result[0].values || []
ramAverage.forEach(element => {
this.ramAverage.push(((element[1] - 0) / 1024 / 1024 / 1024).toFixed(2))
})
this.ramAverage = this.ramAverage.slice(0, 7)
})
this.initCharts()
},
// echart
initCharts() {
const scaleRate = window.innerHeight / 900 >= 1
const chart = echarts.init(this.$refs.myBarEchart)
//
const legend = ['CPU整体负载', '内存整体负载', 'CPU平均负载', '内存平均负载']
// const legend = ['CPU', '', 'CPU']
chart.setOption({
legend: {
right: '0',
itemWidth: 14,
data: legend,
itemHeight: scaleRate ? 10 : 2,
selectedMode: false, //
textStyle: {
color: '#FFFFFF',
fontSize: this.fontSize(0.7)
}
},
grid: {
right: '12%',
bottom: '16%',
top: scaleRate ? '25%' : '30%',
left: '12%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#000033'
}
},
backgroundColor: '#000033',
textStyle: { fontSize: this.fontSize(0.7), color: '#fff' },
borderWidth: 0,
formatter: (params) => {
let val = params[0].name
for (let i = 0; i < params.length; i++) {
const unit = params[i].seriesName.indexOf('CPU') > -1 ? '核' : 'GB'
val += '<br/>' + params[i].marker + (params[i].seriesName.indexOf('平均') > -1 ? '七日' : '') + params[i].seriesName + ' ' + params[i].value + unit
}
return val
}
},
xAxis: {
type: 'category',
data: this.day.map(n => n[1]),
axisTick: {
show: false
},
axisLabel: {
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)'
},
interval: 0,
margin: scaleRate ? 14 : 10
},
axisLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.01)'
}
}
},
yAxis: [
{
name: '单位:核',
nameTextStyle: {
color: '#aaa',
// padding: [0, 10, 0, 0],
fontSize: this.fontSize(0.75),
nameLocation: 'start'
},
axisLabel: {
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)'
},
formatter: '{value}'
},
splitLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}},
axisLine: {
lineStyle: {
color: '#DDDDDD'
}
},
splitNumber: 3,
position: 'left',
alignTicks: true
},
{
name: '单位GB',
nameTextStyle: {
color: '#aaa',
// padding: [0, 10, 0, 0],
fontSize: this.fontSize(0.75),
nameLocation: 'start'
},
axisLabel: {
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)'
},
formatter: '{value}'
},
position: 'right',
alignTicks: true,
splitLine: {
lineStyle: {
color: 'rgba(255,255,255,0.1)'
}},
splitNumber: 3,
axisLine: {
lineStyle: {
color: '#999999'
}
}
}
],
color: '#3282CE',
series: [
{
name: legend[2],
data: this.cpuAverage,
type: 'line',
showSymbol: true,
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#30BFB6',
shadowColor: '#30BFB6',
shadowBlur: 8
},
yAxisIndex: 0,
lineStyle: {
color: '#30BFB6', // 线
width: 1
},
smooth: true
},
{
name: legend[3],
data: this.ramAverage,
yAxisIndex: 1,
type: 'line',
showSymbol: true,
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#87BDF5',
shadowColor: '#87BDF5',
shadowBlur: 8
},
lineStyle: {
color: '#87BDF5',
width: 1
},
smooth: true
}
]
})
window.addEventListener('resize', debounce(() => {
chart.resize()
}, 100))
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,355 +0,0 @@
<!-- 计算资源负载 -->
<template>
<div id="myBarEchart" ref="myBarEchart" style="width: 100%; height: 80%" />
</template>
<script>
import * as echarts from 'echarts'
import { getTotalAverage } from '@/api/top-menu/TotalNum'
import moment from 'moment'
import { debounce } from '@/utils'
export default {
data() {
const day = [[], [], [], [], [], [], []]
for (let i = 0; i < 7; i++) {
day[i][0] = moment().subtract(7 - i, 'days').endOf('day').unix()
day[i][1] = moment().subtract(7 - i, 'days').endOf('day').format('MM/DD')
}
return {
day,
ramLoad: [], //
cpuLoad: [], // CPU
cpuAverage: [], // cpu
ramAverage: [] //
}
},
computed: {
jcceTheme() {
return localStorage.getItem('jcceTheme')
}
},
mounted() {
this.getAllData()
},
methods: {
fontSize(rem) {
const scale = window.innerHeight / 900
return scale >= 1 ? 16 * rem : 12 * rem
},
//
async getAllData() {
await getTotalAverage().then(res => {
this.ramLoad = res.data.memoryLoad
this.ramAverage = res.data.memoryAvg
this.cpuLoad = res.data.cpuLoad
this.cpuAverage = res.data.cpuAvg
// const data = res.data
// // GB
// const ramData = data.find(item => item.metric_name === 'mem_total_usage').data.result[0].values || []
// ramData.forEach(element => {
// this.ramLoad.push(((element[1] - 0) / 1024 / 1024 / 1024).toFixed(2))
// // this.date.push(moment(element[0] * 1000).format('MM/DD'))
// })
// this.ramLoad = this.ramLoad.slice(0, 7)
// // CPU Core
// const cpuLoad = data.find(item => item.metric_name === 'cpu_total_usage').data.result[0].values || []
// cpuLoad.forEach(element => {
// this.cpuLoad.push(((element[1] - 0)).toFixed(2))
// })
// this.cpuLoad = this.cpuLoad.slice(0, 7)
// // cpu (%)
// const cpuData = data.find(item => item.metric_name === 'cpu_avg_usage').data.result[0].values || []
// cpuData.forEach(element => {
// this.cpuAverage.push((element[1] - 0).toFixed(2))
// // this.date.push(moment(element[0] * 1000).format('MM/DD'))
// })
// this.cpuAverage = this.cpuAverage.slice(0, 7)
// // (%)
// const ramAverage = data.find(item => item.metric_name === 'mem_avg_usage').data.result[0].values || []
// ramAverage.forEach(element => {
// this.ramAverage.push(((element[1] - 0) / 1024 / 1024 / 1024).toFixed(2))
// })
// this.ramAverage = this.ramAverage.slice(0, 7)
})
this.initCharts()
},
// echart
initCharts() {
const scaleRate = window.innerHeight / 900 >= 1
const chart = echarts.init(this.$refs.myBarEchart)
//
const legend = ['CPU整体负载', '内存整体负载', 'CPU平均负载', '内存平均负载']
// const legend = ['CPU', '', 'CPU']
chart.setOption({
legend: {
right: '0',
itemWidth: 14,
data: legend,
itemHeight: scaleRate ? 10 : 2,
selectedMode: false, //
textStyle: {
color: '#FFFFFF',
fontSize: this.fontSize(0.7)
}
},
grid: {
right: '12%',
bottom: '16%',
top: scaleRate ? '25%' : '30%',
left: '12%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#000033'
}
},
backgroundColor: '#000033',
textStyle: { fontSize: this.fontSize(0.7), color: '#fff' },
borderWidth: 0,
formatter: (params) => {
let val = params[0].name
for (let i = 0; i < params.length; i++) {
const unit = params[i].seriesName.indexOf('CPU') > -1 ? '核' : 'GB'
val += '<br/>' + params[i].marker + (params[i].seriesName.indexOf('平均') > -1 ? '七日' : '') + params[i].seriesName + ' ' + params[i].value + unit
}
return val
}
},
xAxis: {
type: 'category',
data: this.day.map(n => n[1]),
axisTick: {
show: false
},
axisLabel: {
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)'
},
interval: 0,
margin: scaleRate ? 14 : 10
},
axisLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.01)'
}
}
},
yAxis: [
{
name: '单位:核',
nameTextStyle: {
color: '#aaa',
// padding: [0, 10, 0, 0],
fontSize: this.fontSize(0.75),
nameLocation: 'start'
},
axisLabel: {
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)'
},
formatter: '{value}'
},
splitLine: {
lineStyle: {
color: 'rgba(135, 189, 245, 0.1)'
}},
axisLine: {
lineStyle: {
color: '#DDDDDD'
}
},
splitNumber: 3,
position: 'left',
alignTicks: true
},
{
name: '单位GB',
nameTextStyle: {
color: '#aaa',
// padding: [0, 10, 0, 0],
fontSize: this.fontSize(0.75),
nameLocation: 'start'
},
axisLabel: {
textStyle: {
fontSize: this.fontSize(0.75),
color: 'rgba(221, 221, 221, 1)'
},
formatter: '{value}'
},
position: 'right',
alignTicks: true,
splitLine: {
lineStyle: {
color: 'rgba(255,255,255,0.1)'
}},
splitNumber: 3,
axisLine: {
lineStyle: {
color: '#999999'
}
}
}
],
color: '#3282CE',
series: [
{
name: legend[0],
type: 'pictorialBar',
symbolSize: [12, 3],
yAxisIndex: 0,
tooltip: {
show: false
},
symbolOffset: [-9, 3],
z: 12,
color: 'rgba(5, 155, 252, 0.8)',
data: this.cpuLoad
},
{
name: legend[0],
type: 'pictorialBar',
symbolSize: [16, 6],
yAxisIndex: 0,
tooltip: {
show: false
},
symbolOffset: [-9, 6],
z: 12,
color: 'rgba(5, 155, 252, 0.5)',
data: this.cpuLoad
},
{
name: legend[0],
type: 'pictorialBar',
symbolSize: [20, 9],
yAxisIndex: 0,
tooltip: {
show: false
},
symbolOffset: [-9, 9],
z: 12,
color: 'rgba(5, 155, 252, 0.25)',
data: this.cpuLoad
},
{
type: 'bar',
name: legend[0],
barWidth: '10',
yAxisIndex: 0,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(5, 155, 252, 0)' }, { offset: 1, color: 'rgba(5, 155, 252, 1)' }])
}
},
data: this.cpuLoad
},
{
name: legend[1],
yAxisIndex: 1,
type: 'pictorialBar',
symbolSize: [12, 3],
tooltip: {
show: false
},
symbolOffset: [9, 3],
z: 12,
color: 'rgba(62, 223, 252, 1)',
data: this.ramLoad
},
{
name: legend[1],
yAxisIndex: 1,
type: 'pictorialBar',
symbolSize: [16, 6],
tooltip: {
show: false
},
symbolOffset: [9, 6],
z: 12,
color: 'rgba(62, 223, 252, 0.5)',
data: this.ramLoad
},
{
name: legend[1],
yAxisIndex: 1,
type: 'pictorialBar',
symbolSize: [20, 9],
tooltip: {
show: false
},
symbolOffset: [9, 9],
z: 12,
color: 'rgba(62, 223, 252, 0.25)',
data: this.ramLoad
},
{
type: 'bar',
name: legend[1],
barWidth: '10',
barGap: '80%',
yAxisIndex: 1,
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(5, 155, 252, 0)' }, { offset: 1, color: 'rgba(62, 223, 252, 1)' }])
}
},
data: this.ramLoad
},
{
name: legend[2],
data: this.cpuAverage,
type: 'line',
showSymbol: true,
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#30BFB6',
shadowColor: '#30BFB6',
shadowBlur: 8
},
yAxisIndex: 0,
lineStyle: {
color: '#30BFB6', // 线
width: 1
},
smooth: true
},
{
name: legend[3],
data: this.ramAverage,
yAxisIndex: 1,
type: 'line',
showSymbol: true,
symbol: 'circle',
symbolSize: 8,
itemStyle: {
color: '#87BDF5',
shadowColor: '#87BDF5',
shadowBlur: 8
},
lineStyle: {
color: '#87BDF5',
width: 1
},
smooth: true
}
]
})
window.addEventListener('resize', debounce(() => {
chart.resize()
}, 100))
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,131 +0,0 @@
<template>
<!-- 存储资源用量 -->
<div>
<div class="unUse use">
<div class="data">
<p class="num">{{ storageData.storageUsing }}TB</p>
<p class="percent"> {{ Math.round(storageData.usingRate*10000) /100 }}%</p>
</div>
<span class="type">未使用 </span>
</div>
<div class="used use">
<span class="type"> 已使用 </span>
<div class="data">
<p class="num">{{ storageData.storageUsed }}TB</p>
<p class="percent"> {{ Math.round(storageData.usageRate*10000) /100 }}%</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
data: {
type: Object,
default: () => ({})
}
},
data() {
return {
storageData: {}
}
},
watch: {
data: {
handler(newValue, oldValue) {
this.storageData = newValue
},
deep: true
}
}
}
</script>
<style lang="scss" scoped>
.use{
height: 8.5vh;
font-size: 1rem;
font-weight: bold;
margin-top: 1vh;
position: relative;
.data {
width: calc(100% - 14.3vh);
background: url(../../../assets/monitor/g-2.png) no-repeat;
background-size: 100% 62%;
background-position: -1vh 1.3vh;
height: 90%;
position: absolute;
top: 0;
right: 0;
font-family: PangMenZhengDao;
font-weight: 400;
.num{
font-size: 1.875rem;
color: #FFFFFF;
line-height: 1.25rem;
padding-top: 0.6rem;
margin:0 12%;
text-align: right;
letter-spacing: 0.1rem;
}
.percent{
// float: left;
position: absolute;
left: 0;
top: 0;
line-height: 7.5vh;
letter-spacing: 0.1rem;
margin: 0;
text-indent: 1rem;
font-size: 1.2rem;
color: #3EDFFC;
}
// display: block;
}
.type {
display: block;
width: 14.3vh;
height: 100%;
position: absolute;
top: 0;
background: url(../../../assets/monitor/g-1.png) no-repeat;
background-size: auto 100%;
text-align: right;
line-height: 7.5vh;
// padding: 0 10px;
}
}
.unUsed{
.type{
left: 0;
}
}
.used{
position:relative;
.data{
left: 0;
-moz-transform: matrix(-1, 0, 0, 1, 0, 0);
-webkit-transform: matrix(-1, 0, 0, 1, 0, 0);
-o-transform: matrix(-1, 0, 0, 1, 0, 0);
z-index: -1;
.num, .percent{
-moz-transform: matrix(-1, 0, 0, 1, 0, 0);
-webkit-transform: matrix(-1, 0, 0, 1, 0, 0);
-o-transform: matrix(-1, 0, 0, 1, 0, 0);
z-index: -1;
}
.num{
text-align: left;
}
}
.type{
text-align: left;
position: absolute;
right: 0;
background-image: url(../../../assets/monitor/b-1.png);
}
}
</style>

View File

@ -1,232 +0,0 @@
<template>
<div>
<el-table id="dbM" :data="newData" border style="width: 100%" align="center" size="mini" class="customer-table">
<el-table-column :label="menuData[0].name" :prop="menuData[0].prop" min-width="70" :show-overflow-tooltip="true" />
<el-table-column :label="menuData[1].name" min-width="70" align="center">
<template slot-scope="scope">
<div v-if="scope.row.status=='Completed'" class="other">已完成</div>
<div v-if="scope.row.status=='Running'" class="running">运行中</div>
<div v-if="scope.row.status=='Submitted'" class="other">已提交</div>
<div v-if="scope.row.status=='Saved'" class="other">已保存</div>
<div v-if="scope.row.status=='Failed'" class="pending">失败</div>
</template>
</el-table-column>
<el-table-column :label="menuData[2].name" :prop="menuData[2].prop" min-width="50" align="left" :show-overflow-tooltip="true" />
<el-table-column :label="menuData[3].name" :prop="menuData[3].prop" min-width="70" align="left" :show-overflow-tooltip="true" />
<el-table-column :label="menuData[4].name" :prop="menuData[4].prop" min-width="70" align="left" :show-overflow-tooltip="true" />
<slot name="footerTable" />
</el-table>
</div>
</template>
<script>
export default {
name: 'DtSrcoll',
props: {
newData: {
type: Array, //
default: () => []
},
menuData: {
type: Array,
default: () => []
}, //
lineHeight: { //
type: Number,
default: 4
},
rowTime: { //
type: Number,
default: 2000
},
duration: { //
type: Number,
default: 500
},
tableHeight: { //
type: Number,
default: 33
},
isClear: { //
type: Boolean,
default: false
},
isAgain: { //
type: Boolean,
default: false
},
isScroll: { //
type: Boolean,
default: true
}
},
data() {
return {
active: 0,
timer: ''
}
},
watch: {
newData: {
handler(newValue, oldValue) {
this.newData = newValue
},
deep: true
}
},
mounted() {
console.log(this.lineHeight)
const _this = this
this.$nextTick(() => {
const vh = window.innerHeight / 100
const elwrapper = document.getElementsByClassName('el-table__body-wrapper')[0]
elwrapper.style.height = this.lineHeight * 3.95 * 2 + 'vh'
const elBody = document.getElementsByClassName('el-table__body')[0]
const elRow = document.getElementsByClassName('el-table__row')
for (const node of elRow) {
node.style.height = '3.95vh'
}
elBody.style.top = 0
elBody.style.transactionDuration = this.duration + 'ms'
if (_this.isScroll) {
_this.timer = setInterval(() => {
if (_this.active < parseInt(_this.newData.length) - parseInt(_this.lineHeight)) {
_this.active += 1
elBody.style.top = parseInt(elBody.style.top) - parseInt(vh * 4) + 'px'
} else {
if (this.isClear) {
clearInterval(this.timer)
}
if (_this.isAgain) {
_this.active = 0
elBody.style.top = 0
} else {
clearInterval(_this.timer)
}
}
}, _this.rowTime)
}
})
},
destroyed() {
clearInterval(this.timer)
}
}
</script>
<style lang="scss" scoped>
::v-deep{
.el-table__body {
position: absolute;
transition: all 500ms linear;
background-color: transparent !important;
color: #fff;
font-size: 0.9rem;
overflow: hidden;
}
.el-table,
.el-table__expanded-cell {
color: #fff;
background-color: transparent !important;
}
.el-table th,
.el-table tr,
.el-table td {
color: #fff;
background-color: transparent !important;
}
.el-table .cell{
line-height: 3.95vh;
}
.el-table tr:nth-child(even) td{
background: rgba(35,185,255,0.06) !important;
}
.el-table--border,
.el-table--group {
border: 0px;
}
.el-table td.el-table__cell,
.el-table th.el-table__cell.is-leaf {
background-color: transparent !important;
border: 0px solid transparent !important;
}
.el-table--border,
.el-table--group {
border: 0px solid transparent !important;
}
.customer-table {
text-align: center !important;
}
.el-table__footer-wrapper,
.el-table__header-wrapper {
font-size: 0.9rem;
background: rgba(35,185,255,0.12);
}
.el-table--scrollable-x .el-table__body-wrapper {
overflow: hidden;
}
/* 去掉表格单元格边框 */
.customer-table th {
border: none;
}
.customer-table td,
.customer-table th.is-leaf {
border: none;
}
/* 表格最外边框 */
.el-table--border,
.el-table--group {
border: none;
}
/* 头部边框 */
.customer-table thead tr th.is-leaf {
border: 0px solid #EBEEF5;
border-right: none;
}
.customer-table thead tr th:nth-last-of-type(2) {
border-right: 0px solid #EBEEF5;
}
/* 表格最外层边框-底部边框 */
.el-table--border::after,
.el-table--group::after {
width: 0;
}
.customer-table::before {
width: 0;
}
.customer-table .el-table__fixed-right::before,
.el-table__fixed::before {
width: 0;
}
/* 表格有滚动时表格头边框 */
.el-table--border th.gutter:last-of-type {
border: 1px solid #EBEEF5;
border-left: none;
}
.pending, .other, .running {
width: 3.625rem;
height: 1.3rem;
line-height: 1.2rem;
background: linear-gradient(90deg, #0BBAFB 0%, #4285EC 100%);
border-radius: 1rem;
}
}
</style>

View File

@ -1,826 +0,0 @@
<template>
<div>
<div class="monitor">
<div class="top-menu">
<div class="menu">
<a href="">首页</a>
<!-- <a @click="viewMenu()">数算资源</a> -->
</div>
<!-- <div class="right">
<a @click="viewMenu('hpc/hpcOverview')">超算资源</a>
<a @click="toMonitor()">监控运维</a>
</div> -->
</div>
<div class="top">
<div class="top-title">
<h1>算网融合智能协同平台</h1>
</div>
</div>
<div class="floatLeft">
<div class="left">
<div class="left_1">
<div class="title"><p>计算域信息</p></div>
<ComputeDomain />
</div>
<div class="left_2">
<div class="title"><p>云际组件状态</p></div>
<el-row class="taskDiv">
<el-col v-for="(item,index) in taskDetail" :key="'task'+index" :span="12">
<div class="num">{{ item.num }}</div>
<div class="name">{{ item.name }}</div>
</el-col>
</el-row>
<!-- <ComputingPowerTrend id="ComputingPowerTrend" :data="tendData" :config="tendConfig" /> -->
</div>
<div class="left_3">
<div class="title"><p>存储资源用量</p></div>
<StorageResourceUsage :data="powerData" />
<!-- <ComputingPowerUse id="ComputingPowerUse" :data="centerData" :config="statusConfig" /> -->
</div>
<!-- <div class="left_4">
<div class="title"><p>分布记账</p></div>
<ChainLink :key="resizeKey" />
</div> -->
</div>
</div>
<div class="floatRight">
<div class="right">
<div class="right_1">
<div class="title"> <el-button class="createBtn" type="primary" size="mini" round @click="toHashCat()"><div>典型应用验证</div></el-button><p></p></div>
<CumulativeTasks :data="taskData" />
</div>
<div class="right_2">
<div class="title"><p>计算资源整体负载</p></div>
<ResourceLoadWhole />
</div>
<!-- <div class="right_3">
<div class="title"><p>计算资源平均负载</p></div>
<ResourceLoadAverage />
</div> -->
</div>
</div>
<div class="middle">
<ComputingPowerTotal />
</div>
<Earth :key="resizeKey" :center="{name: monitorSettingForm.center, longitude: Number(monitorSettingForm.centerPosition.split(',')[0]), latitude: Number(monitorSettingForm.centerPosition.split(',')[1])}" />
</div>
<el-dialog
title="创建云际跨域任务"
:visible.sync="dialogVisible"
width="30%"
>
<el-upload
action="#"
:http-request="httpRequest"
:limit="1"
:on-remove="handleRemove"
:file-list="fileList"
>
<el-button size="small" type="primary">点击选择yaml文件</el-button>
</el-upload>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button type="primary" @click="submitFile()"> </el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import moment from 'moment'
import ComputeDomain from './components/ComputeDomain.vue'
import ComputingPowerTotal from './components/ComputingPowerTotal.vue'
import ResourceLoadWhole from './components/ResourceLoadWhole.vue'
import CumulativeTasks from './components/CumulativeTasks.vue'
import StorageResourceUsage from './components/StorageResourceUsage.vue'
import Earth from '@/views/prometheusMonitor/earthDev'
import { getComputePower, getScreenInfo, getCPUsage } from '@/api/container/monitorSelect.js'
import { getTaskCount, createScheduleTask } from '@/api/top-menu/TotalNum'
import { order } from '@/utils/data-process'
import { getMonitorSetting } from '@/api/container/monitorSelect'
import { debounce } from '@/utils'
export default {
components: { ComputeDomain, ComputingPowerTotal, ResourceLoadWhole, CumulativeTasks, StorageResourceUsage, Earth },
data() {
return {
monitorSettingForm: {
'title': '广域协同智能计算系统面板',
'titleColor': '#409EFF',
'mainColor': '',
'mainColor2': '',
'textColor': '',
'backgroundColor': '',
'center': '',
'centerPosition': '',
'provinceBgColor': ''
},
taskDetail: [
{
name: 'API每秒请求数 times/s',
num: 119.083
},
{
name: 'API请求延迟 ms',
num: 2.71
},
{
name: '调度器 调度次数',
num: 5
},
{
name: '调度失败的 容器节点',
num: 1
}
],
resizeKey: 0,
dialogVisible: false,
rs: new FormData(),
fileList: [],
powerData: {},
pageSize: 100,
taskData: {},
currentDate: '',
tendData: { used: [], xData: [] },
centerData: { used: [], xData: [] },
tendConfig: { unit: '单位: 卡时', status: ['使用量'] },
statusConfig: { unit: '单位: 卡时', status: ['使用量'] },
tabLightList: [
{
id: 'cluster',
title: '容器管理',
icon: 'rongqiguanli',
path: '/cluster/clusterMapViews'
},
{
id: 'virtual',
title: '虚拟机管理',
icon: 'xunijiguanlimokuai',
path: '/virtual/overview'
},
{
id: 'jccSchedule',
title: '调度中心',
icon: 'yunweijiankongmokuai',
path: '/jccSchedule/resourceLogicView'
},
{
id: 'disk',
title: '云际存储',
icon: 'xunijiguanli-juan',
path: '/disk'
},
{
id: 'functions',
title: '函数管理',
icon: 'fuwu',
path: '/functions/overview'
},
{
id: 'blockChain',
title: '云际记账',
icon: 'yunjijizhang',
path: '/blockChain/blockChainBrowser'
},
{
id: 'hpc',
title: '超算管理',
icon: 'fuwu',
path: '/hpc/hpcOverview'
},
{
id: 'hpc',
title: '智算管理',
icon: 'fuwu',
description: '智算管理描述',
path: '/modelarts/overview'
}
]
}
},
computed: {
jcceTheme() {
return localStorage.getItem('jcceTheme')
},
filteredLightTab() {
return this.tabLightList.filter(e => this.menus.includes(e.id))
}
},
created() {
getMonitorSetting().then(e => {
this.monitorSettingForm = e.data
})
this.getTend()
this.getAccrueCenter()
this.getTrainJob()
this.resize()
window.addEventListener('resize', debounce(() => {
this.resizeKey++
}, 100))
},
mounted() {
this.getPower()
// this.scaleListener()
},
methods: {
getPower() {
getScreenInfo().then((res) => {
this.powerData = res.data
})
},
toMonitor() {
window.open('http://192.168.19.164:8181/#/taskList')
},
toHashCat() {
window.open('https://dev.jointcloud.net/hashcat/')
},
handleRemove() {
this.rs.delete('file')
},
httpRequest(data) {
const isJar = data.file.name.indexOf('.yaml') === (data.file.name.length - 5)
if (!isJar) {
this.$message.warning('上传文件只能是 yaml 格式!')
} else {
this.rs.set('file', data.file)
}
},
submitFile() {
if (!this.rs.has('file')) {
this.$message.warning('请上传yaml文件')
return false
} else {
createScheduleTask(this.rs).then(res => {
if (res.code === 200) {
this.$message.success('操作成功')
this.dialogVisible = false
this.getTrainJob()
}
})
}
},
viewMenu(path) {
path ? this.$store.dispatch('user/setRouteType', path.split('/')[0]) : {}
this.$router.push({ path: path || `/monitorSelectBk` })
},
// scaleListener() {
// window.addEventListener('resize', this.resize())
// },
resize() {
// 1080
const scale = window.innerHeight / 900
if (scale >= 1) {
document.documentElement.style.fontSize = `${16 * scale}px`
} else {
document.documentElement.style.fontSize = `${14 * scale}px`
}
},
getCurrentDate() {
const date = moment().format('yyyy年MM月DD日')
const week = moment().format('E')
switch (week) {
case '1':
this.currentDate = date + ' ' + '星期一'
break
case '2':
this.currentDate = date + ' ' + '星期二'
break
case '3':
this.currentDate = date + ' ' + '星期三'
break
case '4':
this.currentDate = date + ' ' + '星期四'
break
case '5':
this.currentDate = date + ' ' + '星期五'
break
case '6':
this.currentDate = date + ' ' + '星期六'
break
case '0':
this.currentDate = date + ' ' + '星期日'
break
}
},
// changePage(type) {
// if (type === 'left') {
// //
// } else {
// //
// }
// },
getImg(src) {
const srcName = src === 'disk' || src === 'jccSchedule' ? 'blockChain' : src
return require('@/assets/img/' + srcName + '.png')
},
selectMonitor(monitor) {
if (monitor === '/disk') {
if (this.name === 'admin') {
window.location.href = '/disk/storage/sourceSetting'
} else {
window.location.href = '/disk/storage/diskList'
}
}
this.$store.dispatch('user/setRouteType', monitor.split('/')[1])
this.$router.push({ path: monitor })
},
getTend() {
getComputePower().then((res) => {
this.tendData = { used: [], xData: [] }
if (res.dailyComputerPowers !== null) {
const timeArr = []// 12
for (let i = 0; i < 180; i++) {
timeArr.push(
`${moment(new Date()).subtract(i, 'days').format('YYYY-MM-DD')}`
)
}
timeArr.reverse()//
const arr = [] //
for (let i = 0; i < timeArr.length; i++) {
arr.push({ date: timeArr[i], computerPower: 0 })
// arr
for (let j = 0; j < res.dailyComputerPowers.length; j++) {
if (res.dailyComputerPowers[j].date === timeArr[i]) {
arr[i] = { date: res.dailyComputerPowers[j].date, computerPower: res.dailyComputerPowers[j].computerPower }
}
}
}
arr.forEach((item) => {
this.tendData.used.push(item.computerPower.toFixed(1))
this.tendData.xData.push(item.date)
})
}
})
},
getTaskTotal() {
// getAccrueCenter().then((res) => {
// if (res.perCenterComputerPowers) {
// const data = res.accOtJobInfo
// this.accrueData = {
// config1: data.accCardRunSec,
// config2: data.accOtJobNum,
// config3: data.accRunSec
// }
// }
// })
},
getAccrueCenter() {
getCPUsage().then((res) => {
this.centerData = { used: [], xData: [] }
if (res.perCenterComputerPowers) {
const data = res.accOtJobInfo
this.accrueData = {
config1: data.accCardRunSec,
config2: data.accOtJobNum,
config3: data.accRunSec
}
const data1 = res.perCenterComputerPowers.filter(item => {
if (item.computerPower !== 0) {
return item
}
})
// this.timer = setInterval(() => {
// this.getTaskTotal()
// }, 1000)
data1.sort(order)
data1.forEach((item) => {
if (item.computerPower !== 0) {
this.centerData.used.push(item.computerPower.toFixed(1))
this.centerData.xData.push(item.centerName)
}
})
}
})
},
getTrainJob() {
getTaskCount().then(e => {
this.taskData = {
tableData: [],
totalCount: e.data?.allJobCount || 0,
cardTime: e.data?.allCardRunTime || 0,
totalRunTime: e.data?.allJobRunTime || 0
}
e.data?.trainJobs?.forEach((item) => {
this.taskData.tableData.push({
name: item.name,
status: item.status,
strategy: item.strategy,
serviceName: item.serviceName,
synergyStatus: item.synergyStatus
// undertaker: this.showUnderTaker(item)
})
})
})
},
showUnderTaker(item) {
if (item.tasks == null) {
return ''
} else if (item.tasks.length > 2) {
return item.tasks[0].centerName[0] + '等'
} else {
if (item.tasks[0].centerName == null) {
return ''
} else {
return item.tasks[0].centerName[0]
}
}
}
}
}
</script>
<style lang="scss" scoped>
@import "~@/styles/variables.scss";
::v-deep {
.el-dialog {
background: #2c3a4e !important;
color: white;
}
.el-upload-list__item-name {
color: #ffffff;
}
.el-upload-list__item:hover {
background-color: rgb(86, 90, 95)
}
.el-button--default {
color: white;
background: rgba(255,255,255,0.1);
border-color: rgba(255,255,255,0.01);
}
.el-dialog__title {
color: white;
}
}
.monitor {
background: url('../../assets/monitor/monitor_bg.jpeg') no-repeat;
background-size: 100% 100%;
width: 100%;
min-width: 1200px;
height: 100vh;
min-height: 900px;
overflow: hidden;
color: white;
font-size: 0.8rem;
font-family: Source Han Sans CN;
font-weight: 400;
display: block;
overflow: hidden;
.top {
width: 100%;
height: 8vh;
// vertical-align: baseline;
position: absolute;
z-index: 99;
background: url(../../assets/monitor/top-bg.png) center top no-repeat;
background-size: 100% 65%;
.top-title{
margin:0 auto;
// font-weight: bold;
// font-family: PangMenZhengDao;
// float: left;
// padding: 1rem 8rem;
// padding-right: 0;
height: 100%;
background: url(../../assets/monitor/c-top.png) center no-repeat;
background-size: 55% 10vh;
h1{
margin: 0;
font-size: 2rem;
line-height: 6vh;
letter-spacing: 0.3rem;
text-align: center;
text-shadow: 3px 5px 0px rgba(17,20,22,0.22);
background: linear-gradient(0deg, rgba(36,83,152,0.35) 0%, rgba(255,255,255,0.35) 100%);
background-clip: text;
-webkit-text-fill-color: #ffffff;
// background: linear-gradient(0deg, rgba(36,83,152,0.35) 0%, rgba(255,255,255,0.35) 100%);
// -webkit-background-clip: text;
// -webkit-text-fill-color: transparent;
}
// box-shadow: 0px 20px 10px 0px #02020a96;
}
}
.top-menu{
width: 100%;
position: absolute;
z-index: 100;
.menu a, .right a {
float: left;
font-size: 1.13rem;
display: block;
padding: 0.9rem 60px;
height: 3.5rem;
letter-spacing: 0.2rem;
}
.menu a, .right a{
&:hover{
background: url(../../assets/monitor/t-p.png) center no-repeat;
background-size: auto 70%;
}
}
.menu a:first-child{
background: url(../../assets/monitor/t-p.png) center no-repeat;
background-size: auto 70%;
}
.right {
a { float: right;}
// float: right;
}
}
.title{
background: url('../../assets/monitor/title-bg.png') no-repeat left;
background-size: 105% 100%;
background-position: -3.5vh;
height: 4.5vh;
p{
font-size: 1.4rem;
height: 2.8rem;
line-height: 2.3rem;
text-indent: 2.8vw;
margin: 0;
font-family: Source Han Sans CN;
font-weight: bold;
color: #FFFFFF;
letter-spacing: 0.2rem;
text-shadow: 0px 2px 8px rgba(5,28,55,0.42);
background: linear-gradient(0deg, rgba(14,197,236,1) 0%, rgba(49,190,255,1) 0%, rgba(239,252,254,1) 58.7646484375%);
background-clip: text;
-webkit-text-fill-color: transparent;
}
}
.floatLeft, .floatRight{
margin-top: 5vh;
}
.middle{
width: 38vw;
position: absolute;
left: 31vw;
z-index: 99;
margin-top: 10vh;
}
.floatLeft, .floatRight{
padding: 0 1vh 0 2vh;
padding-top: 5vh;
padding-bottom: 4vh;
}
.floatLeft .left::before, .floatRight .right::after{
// margin-top: 6vh;
content: '';
width: 27vw;
height: 95vh;
display:block;
position: absolute;
top: -5.2vh;
right: -2vh;
background: url(../../assets/monitor/left.png) no-repeat;
background-size: 100% 98%;
z-index: -1;
}
.floatLeft .left:after, .floatRight .right:before{
content: '';
width: 2vw;
height: 85vh;
position: absolute;
right: -3.5vw;
top: 3px;
display: block;
background: url(../../assets/monitor/leftr.png) no-repeat;
background-size: 100% 98%;
}
.floatRight .right:before{
left: -3.5vw;
-moz-transform: matrix(-1, 0, 0, 1, 0, 0);
-webkit-transform: matrix(-1, 0, 0, 1, 0, 0);
-o-transform:matrix(-1,0,0,1,0,0);
}
.floatLeft{
// background: #02020a96;
// box-shadow: 20px -30px 30px 0px #02020a96;
width: 27vw;
display: block;
// overflow: hidden;
position: absolute;
left: 0;
z-index: 10;
height: 95vh;
min-height: 800px;
.left {
width: 100%;
height: 90vh;
padding-left: 10px;
display: block;
position: relative;
&:before{
left: -2vh;
}
.left_1{
height: 32vh;
overflow: hidden;
}
.left_2 {
height: 30vh;
.taskDiv{
// display: flex;
// justify-content: space-between;
text-align: center;
margin-bottom: 1%;
// height: calc(100% - 190px);
>div{
background: url('../../assets/images/monitorSelect/data-bg.png') no-repeat center;
background-size: auto 100%;
height: 11vh;
margin-top: 2vh;
// width: 25%;
.num{
font-size: 1.5rem;
font-family: Impact;
color: #FFFFFF;
letter-spacing: 0.1rem;
font-family: PangMenZhengDao;
// height: 3vh;
// line-height: 4vh;
height: 3vh;
line-height: 2rem;
margin-bottom: 1vh;
}
.name{
font-size: 0.8rem;
letter-spacing: 0.1rem;
width: 60%;
margin: auto;
// font-weight: bold;
height: 70%;
// line-height: 300%;
}
}
}
}
.left_3 {
width: 100%;
height: 15vh;
}
// .left_4{
// height: 12vh;
// }
}
}
.floatRight {
// background: #02020a96;
// box-shadow: -20px -30px 30px 0px #02020a96;
background: none;
width: 27vw;
display: block;
// overflow: hidden;
position: absolute;
right: 0;
z-index: 10;
height: 95vh;
min-height: 800px;
padding: 0 2vh 0 1vh;
padding-top: 5vh;
padding-bottom: 4vh;
.createBtn{
height: 2.5vh;
line-height: 2.3vh;
margin: 0;
padding: 0 1rem;
position: absolute;
top: 0.5vh;
right: 2vh;
div{
font-size: 0.9rem;
@media screen and (max-height: 900px) {
transform: scale(0.8);
// transform-origin: 0;
}
}
}
.right {
width: 100%;
height: 100%;
padding-right: 10px;
display: block;
position: relative;
&:after{
// padding: 0 20px 0 10px;
-moz-transform: matrix(-1, 0, 0, 1, 0, 0);
-webkit-transform: matrix(-1, 0, 0, 1, 0, 0);
-o-transform:matrix(-1,0,0,1,0,0);
z-index: -1;
// padding-top: 50px;
// padding-bottom: 40px;
}
.right_1{
height: 50vh;
overflow: hidden;
}
.right_2{
// height: 31%;
height: 40vh;
}
.right_3{
height: 21vh;
// height: 27%;
}
}
}
// .fixedBottom {
// width:50vw;
// bottom: 0;
// display: block;
// position: absolute;
// z-index: 10;
// height: 13vh;
// left: 25vw;
// .el-row{position:relative; height: 100%}
// .lightLeft{
// font-size: 30px;
// position: absolute;
// left: -20px;
// top: 3vh;
// z-index: 10;
// color: #DDD;
// }
// .lightRight{
// font-size: 30px;
// position: absolute;
// right: -20px;
// top: 3vh;
// z-index: 10;
// color: #DDD;
// }
// // displayflex
// .div-block{
// display: flex;
// width: 100%;
// height: 100%;
// overflow: hidden;
// .monitorSelectDiv{
// display: block;
// height: 100%;
// width: 8.33vw;
// }
// > div{
// display: block;
// width: 100%;
// max-width: 8.5vw;
// font-size: 20px;
// color: #ffffff;
// height: 100vh;
// position: relative;
// text-align: center;
// &:hover{
// color: #3182CE;
// }
// .svg-icon {
// font-size: 80px;
// margin: 0 auto;
// }
// .selectTitle {
// margin-bottom: 24px;
// font-size: 16px;
// }
// span{
// display: block;
// padding: 0 100px;
// font-size: 14px;
// line-height: 24px;
// }
// }
// }
// }
}
// @media screen and (min-width: 1921px) {
// .monitor {
// font-size: 16px;
// .top {
// .top-title {
// font-size: 32px;
// padding: 10px 100px;
// img{
// top: 35px;
// }
// }
// }
// .title{
// font-size: 20px;
// height: 70px;
// }
// .middle, .floatLeft, .floatRight{
// margin-top: 110px;
// }
// }
// }
</style>
<style lang="less" rel="stylesheet/less">
@import "../../common/font/font.css";
</style>

View File

@ -2,7 +2,7 @@
<!-- 算力中心总数 -->
<div>
<div class="two">
<div v-for="(item, index) in dataArray" :key="'data'+index" style="cursor: pointer;" @click="item.path && viewMenu(item.path)">
<div v-for="(item, index) in dataArray" :key="'data'+index">
<p class="title">{{ item.name }}</p>
<div class="num">{{ item.value }}</div>
</div>
@ -23,13 +23,11 @@ export default {
dataArray: [
{
name: '算力中心总数(计算域)',
value: '-',
path: 'resourceList'
value: '-'
},
{
name: '已接入算力 POps@FP16',
value: '-',
path: 'resourceList'
value: '-'
},
{
name: '接入集群数',
@ -49,10 +47,7 @@ export default {
}
},
methods: {
viewMenu(path) {
path ? this.$store.dispatch('user/setRouteType', path.split('/')[0]) : {}
this.$router.push({ path: path || `/monitorSelectBk` })
}
}
}

View File

@ -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"
:default-sort="{prop: 'sort', order: 'ascending'}"
row-key="id"
tooltip-effect="dark"
>
<template v-slot:filterBtns>
<el-button size="medium" type="primary" @click="handleAdd">创建</el-button>
<el-button v-if="showBtn" size="medium" type="info" @click="goBack">返回上级菜单</el-button>
<el-button size="medium" type="primary" @click="handleAdd"> {{ $t('message.create') }} </el-button>
</template>
</List>
</el-card>
<el-dialog
:close-on-click-modal="false"
:title="isEdit?'编辑菜单':'添加菜单'"
:title="isEdit? $t('permission.editMenu'): $t('permission.addMenu')"
:visible.sync="dialogVisible"
width="50%"
>
@ -27,40 +27,81 @@
ref="menuFrom"
:model="menu"
:rules="rules"
label-width="150px"
label-width="auto"
>
<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-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>
<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>
<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>
</span>
</el-dialog>
</div>
@ -68,17 +109,19 @@
<script>
import List from '@/components/list'
import { deleteMenu, getMenuList, createMenu, updateMenu, getMenu, updateHidden } from '@/api/authority/permissionManagement'
import { deleteMenu, getUserMenus, createMenu, updateMenu } from '@/api/authority/menu'
// import { newEval } from '@/utils'
import moment from 'moment'
const defaultMenu = {
title: '',
parentId: 0,
name: '',
icon: '',
hidden: 0,
sort: 0
'parentId': [0],
'name': '',
'path': '',
'redirect': '',
'component': '',
'sort': null,
'title': '',
'icon': '',
'status': true,
'defaultMenu': false
}
export default {
components: { List },
@ -88,111 +131,64 @@ export default {
dialogVisible: false,
menu: Object.assign({}, defaultMenu),
isEdit: false,
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' }
]
}
selectMenuList: []
}
},
computed: {
showBtn() {
return this.$route.query.parentId
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' }]
}
}
},
watch: {
$route(route) {
this.resetParentId()
this.getList()
}
},
mounted() {
this.resetParentId()
this.getList()
},
methods: {
goBack() {
this.$router.go(-1)
},
getList() {
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: '无上级菜单' })
getUserMenus().then(e => {
this.listData = e.data
this.selectMenuList = [].concat(e.data)
this.selectMenuList.unshift({ id: '0', title: this.$t('permission.root') })
}).catch(e => {
})
},
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()
})
handleCascader(val) {
this.menu.parentId = val
},
handleAdd() {
this.dialogVisible = true
@ -200,66 +196,44 @@ export default {
this.menu = Object.assign({}, defaultMenu)
},
handleDelete(index, row) {
this.$confirm('是否要删除该菜单', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
this.$confirm(this.$t('permission.wantDelete'), this.$t('page.info'), {
confirmButtonText: this.$t('message.confirm'),
cancelButtonText: this.$t('message.cancel'),
type: 'warning'
}).then(() => {
deleteMenu(row.id).then(response => {
this.$message({
message: '删除成功',
type: 'success',
duration: 1000
})
deleteMenu({ id: row.id }).then(response => {
this.$message({ message: this.$t('page.deleteSuccess'), type: 'success', duration: 1000 })
this.getList()
})
})
},
handleUpdate(index, row) {
this.dialogVisible = true
this.menuId = row.id
getMenu(this.menuId).then(response => {
this.menu = response.data
this.isEdit = true
this.dialogVisible = true
})
this.menu = Object.assign({}, row)
this.menu.parentId = [row.parentId]
this.isEdit = true
},
handleDialogConfirm() {
this.$refs.menuFrom.validate((valid) => {
if (valid) {
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()
})
}
})
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()
})
}
} else {
this.$message({
message: '验证失败',
type: 'error',
duration: 1000
})
this.$message({ message: this.$t('message.verificationFailed'), type: 'success', duration: 1000 })
return false
}
})
@ -267,10 +241,10 @@ export default {
}
}
</script>
<style scoped>
.btnBox {
display: flex;
align-items: center;
justify-content: center;
<style scoped lang="scss">
::v-deep{
.el-table__expand-icon {
color: #FFFFFF;
}
}
</style>

View File

@ -0,0 +1,99 @@
<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>

View File

@ -1,151 +0,0 @@
<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>

View File

@ -3,119 +3,150 @@
<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="resourceCategoryVisible=true">资源分类</el-button>
<el-button size="medium" type="primary" @click="handleAdd">添加</el-button>
<el-button size="medium" type="primary" @click="handleAdd"> {{ $t('page.add') }} </el-button>
</template>
</List>
</el-card>
<el-dialog
:close-on-click-modal="false"
:title="isEdit?'编辑资源':'添加资源'"
:title="isEdit? $t('page.editResource') : $t('page.addResource')"
:visible.sync="dialogVisible"
width="40%"
>
<p>
<el-alert
:title="$t('page.apiInfo')"
type="warning"
:closable="false"
/>
</p>
<el-form
ref="resourceForm"
:model="resource"
label-width="150px"
size="small"
:rules="rules"
label-width="auto"
>
<el-form-item label="资源名称:">
<el-input v-model="resource.name" style="width: 250px" />
<el-form-item :label="$t('page.apiPath')" prop="path">
<el-input v-model="resource.path" />
</el-form-item>
<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-form-item :label="$t('page.request')" prop="method">
<el-select v-model="resource.method" style="width: 100%;">
<el-option
v-for="item in categoryOptions"
:key="item.value"
:label="item.label"
:value="item.value"
v-for="it in filterMap.method.dataSource"
:key="it.label"
:label="it.label"
:value="it.label"
/>
</el-select>
</el-form-item>
<el-form-item label="描述:">
<el-input
v-model="resource.description"
type="textarea"
:rows="5"
style="width: 250px"
/>
<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>
</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>
<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>
</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, createResource, updateResource, deleteResource, listAllCate } from '@/api/authority/permissionManagement'
import { getResourceList, addApi, editApi, deleteApi
// deleteApisByIds
} from '@/api/authority/api'
// import { newEval } from '@/utils'
import moment from 'moment'
import ResourceCategoryList from './resourceCategoryList.vue'
const defaultResource = {
id: null,
name: null,
url: null,
categoryId: null,
description: ''
'name': null,
'path': null,
'description': '',
'apiGroup': null,
'method': null
}
export default {
components: { List, ResourceCategoryList },
components: { List },
data() {
return {
getResourceList,
listData: [],
dialogVisible: false,
resourceCategoryVisible: false,
resource: Object.assign({}, defaultResource),
isEdit: false,
categoryOptions: [],
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> } },
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') },
{
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>
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>
}
}
]
},
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() {
@ -132,19 +163,15 @@ export default {
this.dialogVisible = true
this.isEdit = false
this.resource = Object.assign({}, defaultResource)
this.resource.categoryId = this.defaultCategoryId
},
handleDelete(index, row) {
this.$confirm('是否要删除该资源?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
this.$confirm(this.$t('message.isDeleteResource'), this.$t('page.info'), {
confirmButtonText: this.$t('message.confirm'),
cancelButtonText: this.$t('message.cancel'),
type: 'warning'
}).then(() => {
deleteResource(row.id).then(response => {
this.$message({
type: 'success',
message: '删除成功!'
})
deleteApi({ id: row.id + '' }).then(response => {
this.$message({ message: this.$t('page.deleteSuccess'), type: 'success', duration: 1000 })
this.$refs.multipleTable.getList()
})
})
@ -155,41 +182,25 @@ export default {
this.resource = Object.assign({}, row)
},
handleDialogConfirm() {
this.$confirm('是否要确认?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (this.isEdit) {
updateResource(this.resource.id, this.resource).then(response => {
this.$message({
message: '修改成功!',
type: 'success'
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.dialogVisible = false
this.$refs.multipleTable.getList()
})
} else {
createResource(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()
})
}
}
})
},
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
})
}
}
}

View File

@ -3,35 +3,35 @@
<el-card>
<List
ref="multipleTable"
:key="$i18n.locale"
class="multipleTable"
:columns="columns"
:get-list-action="getRoleList"
:pagination="true"
page-key="pageNum"
limit-key="pageSize"
list-key="data"
tooltip-effect="dark"
>
<template v-slot:filterBtns>
<el-button size="medium" type="primary" @click="handleAdd">创建</el-button>
<el-button size="medium" type="primary" @click="handleRoleAdd">{{ $t('message.create') }}</el-button>
</template>
</List>
</el-card>
<el-dialog
:close-on-click-modal="false"
:title="isEdit?'编辑角色':'添加角色'"
:title="isEdit?$t('permission.editRole'):$t('permission.addRole')"
:visible.sync="dialogVisible"
width="40%"
>
<el-form
ref="roleForm"
:model="role"
label-width="150px"
:rules="rules"
label-width="auto"
size="small"
>
<el-form-item label="角色名称:">
<el-form-item prop="name" :label="$t('permission.roleName')">
<el-input v-model="role.name" style="width: 250px" />
</el-form-item>
<el-form-item label="描述:">
<el-form-item prop="description" :label="$t('page.description')">
<el-input
v-model="role.description"
type="textarea"
@ -39,27 +39,28 @@
style="width: 250px"
/>
</el-form-item>
<el-form-item label="是否启用:">
<el-form-item prop="status" :label="$t('permission.isUse')">
<el-radio-group v-model="role.status">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
<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-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>
<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>
</span>
</el-dialog>
<el-dialog
:close-on-click-modal="false"
title="分配菜单"
:title="$t('permission.assignMenu')"
:visible.sync="menuSelectDialog"
width="50%"
>
<el-tree
ref="tree"
ref="menuTree"
:data="menuTreeList"
:default-checked-keys="menuIds"
show-checkbox
default-expand-all
node-key="id"
@ -67,37 +68,27 @@
:props="defaultProps"
/>
<div style="margin-top: 20px" align="center">
<el-button type="primary" @click="handleSave()">保存</el-button>
<el-button @click="handleClear()">清空</el-button>
<el-button type="primary" @click="handleMenuSave()"> {{ $t('message.save') }} </el-button>
</div>
</el-dialog>
<el-dialog
:close-on-click-modal="false"
title="分配资源"
:title="$t('permission.assignResource')"
:visible.sync="resourceSelectDialog"
width="50%"
>
<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>
<el-tree
ref="apiTree"
:data="apiTreeList"
:default-checked-keys="apiIds"
show-checkbox
default-expand-all
node-key="key"
highlight-current
:props="apiDefaultProps"
/>
<div style="margin-top: 20px" align="center">
<el-button type="primary" @click="handleResourceSave()">保存</el-button>
<el-button @click="handleResourceClear()">清空</el-button>
<el-button type="primary" @click="handleResourceSave()"> {{ $t('message.save') }} </el-button>
</div>
</el-dialog>
</div>
@ -105,16 +96,16 @@
<script>
import List from '@/components/list'
import { getRoleList, createRole, updateRole, updateRoleStatus, deleteRole, fetchTreeList, listMenuByRole, allocMenu, fetchAllResourceList, listAllCate, allocResource, listResourceByRole } from '@/api/authority/permissionManagement'
import { createRole, updateRole, deleteRole, allocMenu, getRoleList, allocApis } from '@/api/authority/role'
import { getMenuTree } from '@/api/authority/menu'
import { getElTreeApis } from '@/api/authority/api'
// import { newEval } from '@/utils'
import moment from 'moment'
const defaultRole = {
id: null,
name: null,
description: null,
adminCount: 0,
status: 1
'id': undefined,
'name': undefined,
'description': undefined,
'status': true
}
export default {
components: { List },
@ -127,316 +118,149 @@ export default {
resourceSelectDialog: false,
role: Object.assign({}, defaultRole),
isEdit: false,
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>
}
}
],
labelWidth: Math.round(document.body.offsetHeight / 1048 * 100) + 'px',
apiTreeList: [],
apiIds: [],
menuTreeList: [],
menuIds: [],
defaultProps: {
children: 'children',
label: 'title'
},
apiDefaultProps: {
children: 'children',
label: (data) => {
return data.apiGroup
}
},
roleId: null,
allResource: null,
allResourceCate: null
}
},
mounted() {
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') }]
}
}
},
methods: {
formatDate(t) {
return moment(t).local().format('YYYY-MM-DD hh:mm:ss')
},
handleAdd() {
handleRoleAdd() {
this.dialogVisible = true
this.isEdit = false
this.role = Object.assign({}, defaultRole)
},
handleStatusChange(row) {
console.log(row.status)
this.$confirm('是否要修改该状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
handleRoleDelete(index, row) {
this.$confirm(this.$t('permission.wantDeleteRole'), this.$t('page.info'), {
confirmButtonText: this.$t('message.confirm'),
cancelButtonText: this.$t('message.cancel'),
type: 'warning'
}).then(() => {
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: '删除成功!'
})
deleteRole({ id: row.id + '' }).then(response => {
this.$message({ type: 'success', message: this.$t('page.deleteSuccess') })
this.$refs.multipleTable.getList()
})
})
},
handleUpdate(index, row) {
handleRoleUpdate(row) {
this.dialogVisible = true
this.isEdit = true
this.role = Object.assign({}, row)
},
handleDialogConfirm() {
this.$confirm('是否要确认?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (this.isEdit) {
updateRole(this.role.id, this.role).then(response => {
this.$message({
message: '修改成功!',
type: 'success'
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.dialogVisible = false
this.$refs.multipleTable.getList()
})
} else {
createRole(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()
})
}
}
})
},
handleSelectMenu(index, row) {
this.roleId = row.id
this.treeList()
this.getRoleMenu(row.id)
},
treeList() {
fetchTreeList().then(response => {
this.menuTreeList = response.data
getMenuTree({ id: row.id }).then(response => {
this.menuTreeList = response.data.list
this.menuIds = response.data.menuIds
this.menuSelectDialog = true
})
},
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 => {
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 })
this.menuSelectDialog = false
this.$message({
message: '分配成功',
type: 'success',
duration: 1000
})
this.$refs.multipleTable.getList()
})
})
},
handleClear() {
this.$refs.tree.setCheckedKeys([])
.catch(() => {})
},
handleSelectResource(index, row) {
this.roleId = row.id
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)
})
},
getAllResourceCateList() {
listAllCate().then(response => {
getElTreeApis({ id: row.id }).then(response => {
this.apiTreeList = response.data.list
this.apiIds = response.data.checkedKey
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)
}
}
return cateResource
},
getResourceByRole(roleId) {
listResourceByRole(roleId).then(response => {
const allocResource = response.data
this.allResource.forEach(item => {
item.checked = this.getResourceChecked(item.id, allocResource)
})
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 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)
}
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()
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()
})
.catch(() => {})
}
}
}

View File

@ -3,6 +3,7 @@
<el-card>
<List
ref="multipleTable"
:key="$i18n.locale"
class="multipleTable"
:columns="columns"
:get-list-action="getUserList"
@ -12,71 +13,83 @@
tooltip-effect="dark"
>
<template v-slot:filterBtns>
<el-button size="medium" type="primary" @click="handleAdd">创建</el-button>
<el-button size="medium" type="primary" @click="handleAdd">{{ $t('message.create') }}</el-button>
</template>
</List>
</el-card>
<el-dialog
:close-on-click-modal="false"
:title="isEdit?'编辑用户':'添加用户'"
:title="isEdit ? $t('permission.editUser') : $t('permission.addUser')"
:visible.sync="dialogVisible"
width="40%"
>
<el-form
ref="adminForm"
:model="admin"
label-width="150px"
:rules="rules"
label-width="auto"
size="small"
>
<el-form-item label="帐号:">
<el-input v-model="admin.username" style="width: 250px" />
<el-form-item prop="username" :label="$t('page.userName')">
<el-input v-model="admin.username" />
</el-form-item>
<el-form-item label="姓名:">
<el-input v-model="admin.nickName" style="width: 250px" />
<el-form-item prop="nickname" :label="$t('permission.nickName')">
<el-input v-model="admin.nickname" />
</el-form-item>
<el-form-item label="邮箱:">
<el-input v-model="admin.email" style="width: 250px" />
<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>
<el-form-item label="密码:">
<el-input v-model="admin.password" type="password" style="width: 250px" />
<el-form-item prop="phone" :label="$t('permission.phone')">
<el-input v-model="admin.phone" type="tel" />
</el-form-item>
<el-form-item label="备注:">
<el-input
v-model="admin.note"
type="textarea"
:rows="5"
style="width: 250px"
/>
<el-form-item prop="email" :label="$t('permission.email')">
<el-input v-model="admin.email" type="email" />
</el-form-item>
<el-form-item label="是否启用:">
<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-radio-group v-model="admin.status">
<el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio>
<el-radio :label="true">{{ $t('permission.enable') }}</el-radio>
<el-radio :label="false">{{ $t('permission.deactivate') }}</el-radio>
</el-radio-group>
</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>
<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>
</span>
</el-dialog>
<el-dialog
:close-on-click-modal="false"
title="分配角色"
:visible.sync="allocDialogVisible"
width="30%"
:title="$t('permission.editPass')"
:visible.sync="passDialogVisible"
width="40%"
>
<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>
<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>
<span slot="footer" class="dialog-footer">
<el-button size="small" @click="allocDialogVisible = false"> </el-button>
<el-button type="primary" size="small" @click="handleAllocDialogConfirm()"> </el-button>
<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>
</span>
</el-dialog>
</div>
@ -84,65 +97,135 @@
<script>
import List from '@/components/list'
import { getUserList, createAdmin, updateAdmin, updateUserStatus, deleteAdmin, getRoleByAdmin, allocRole, fetchAllRoleList } from '@/api/authority/permissionManagement'
import { editUser, addUser, getUserList, deleteUser, switchStatus, modifyPass } from '@/api/authority/user'
import { getRoleList } from '@/api/authority/role'
// import { newEval } from '@/utils'
import moment from 'moment'
const defaultAdmin = {
id: null,
username: null,
password: null,
nickName: null,
email: null,
note: null,
status: 1
status: true
}
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,
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) => {
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) => {
return <el-switch
onChange={() => this.handleStatusChange(row)}
activeValue={1}
inactiveValue={0}
activeValue={true}
inactiveValue={false}
value={row.status}>
</el-switch>
} },
{
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>
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>
}
}
]
},
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: {
formatDate(t) {
return moment(t).local().format('YYYY-MM-DD hh:mm:ss')
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()
})
}
})
},
handleAdd() {
this.dialogVisible = true
@ -150,119 +233,46 @@ export default {
this.admin = Object.assign({}, defaultAdmin)
},
handleStatusChange(row) {
this.$confirm('是否要修改该状态?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
this.$confirm(this.$t('permission.modifyStatus'), this.$t('page.info'), {
confirmButtonText: this.$t('message.confirm'),
cancelButtonText: this.$t('message.cancel'),
type: 'warning'
}).then(() => {
updateUserStatus(row.id, { status: !row.status ? 1 : 0 }).then(response => {
switchStatus({ id: row.id, status: !row.status }).then(response => {
this.$refs.multipleTable.getList()
this.$message({
type: 'success',
message: '修改成功!'
})
this.$message({ message: this.$t('message.updateSuccess'), type: 'success' })
})
}).catch(() => {
this.$message({
type: 'info',
message: '取消修改'
})
this.$message({ type: 'info', message: this.$t('permission.cancelModify') })
this.$refs.multipleTable.getList()
})
},
handleDelete(index, row) {
this.$confirm('是否要删除该用户?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
handleDelete(id) {
this.$confirm(this.$t('permission.isDelUser'), this.$t('page.info'), {
confirmButtonText: this.$t('message.confirm'),
cancelButtonText: this.$t('message.cancel'),
type: 'warning'
}).then(() => {
deleteAdmin(row.id).then(response => {
this.$message({
type: 'success',
message: '删除成功!'
})
deleteUser({ id }).then(response => {
this.$message({ type: 'success', message: this.$t('page.deleteSuccess') })
this.$refs.multipleTable.getList()
})
})
},
handleUpdate(index, row) {
handleUpdate(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.allocAdminId = row.id
this.allocDialogVisible = true
this.getRoleListByAdmin(row.id)
this.changePass.id = row.id
this.passDialogVisible = true
},
getAllRoleList() {
fetchAllRoleList().then(response => {
getRoleList().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>

View File

@ -163,7 +163,6 @@ export default {
this.renderer = null
this.camera = null
this.aniId = null
this.raycaster = null
}
},
methods: {
@ -777,9 +776,7 @@ export default {
this.renderer.setSize(this.width, this.height)
// this.renderer.setClearColor(0x03060f, 1) //
const earth = document.getElementById('earth')
if (earth) {
earth.appendChild(this.renderer.domElement)
}
earth.appendChild(this.renderer.domElement)
this.animate()
})
},
@ -945,7 +942,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 && arr) ? this.raycaster.intersectObjects(arr, true) : []
var intersects = this.raycaster.intersectObjects(arr, true)
if (this.activeTab !== 'dsxs') {
if (intersects.length) {
this.scene.getObjectByName('csText').visible = false
@ -981,7 +978,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 ? this.raycaster.intersectObjects(arr, true) : []
var intersects = this.raycaster.intersectObjects(arr, true)
if (intersects && intersects.length) {
const hubCode = intersects[0].object.userData.hubCode
if (hubCode === 9 || hubCode === 5) {

View File

@ -1,198 +0,0 @@
<template>
<transition name="el-zoom-in-center">
<div class="transition-box province">
<province v-model="third" :map-type="9" :cluster="provinceClusters" @selectedCity="selectCity" />
</div>
</transition>
</template>
<script>
import province from './provinceDev.vue'
import dataCenter from './dataCenter'
export default {
components: { province },
props: {
center: {
type: Object,
default: () => {
return {
name: '鹏城云脑',
longitude: 114.057868,
latitude: 22.543099
}
}
}
},
data() {
return {
dataCenter,
loading: true,
provinceType: 5,
third: false,
provinceClusters: [],
mapCount: {},
selectCity: ''
}
},
mounted() {
this.provinceClusters = dataCenter.centerList
this.third = true
},
beforeDestroy() {
},
methods: {}
}
</script>
<style lang="scss" scoped>
.loading {
width: 100vw;
height: 100vh;
display: block;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: rgba(#071b45, 0.8);
}
.circle-breath {
background: #3EDFFC;
box-shadow: 0 0 0 0 rgb(250, 249, 250);
height: 10vh;
width: 10vh;
margin: 40vh auto;
// display: block;
border-radius: 50%;
animation: donghua 2.4s infinite;
.loadingGlobe{
font-size: 10vh;
animation: zhuan 3s linear infinite;
}
}
@keyframes zhuan {
0% {transform: rotateZ(0deg)}
25% {transform: rotateZ(90deg)}
50% {
transform: rotateZ(180deg)
}
75% {
transform: rotateZ(270deg)
}
100% {
transform: rotateZ(360deg)
}
}
@keyframes donghua {
0% {
transform: scale(0.60);
/* 注意rgba中的a的设置 */
box-shadow: 0 0 0 0 rgba(73, 171, 204, 0.6);
}
60% {
transform: scale(1);
box-shadow: 0 0 0 36px rgba(73, 182, 204, 0);
}
100% {
transform: scale(0.60);
box-shadow: 0 0 0 0 rgba(73, 167, 204, 0);
}
}
.province{
width: 100%;
height: 100%;
display: block;
position: absolute;
overflow: hidden;
top: 0;
left: 0;
background: url('../../assets/monitor/province-bg.png') center no-repeat;
background-size: 100% 100%;
}
.switchBtn {
font-size: 2.5rem;
position: absolute;
bottom: 6.5vh;
right: 30vw;
z-index: 100;
color: #fff;
}
.toChina{
bottom: 2.3vh;
}
.activeBtn{
color: #3EDFFC
}
.chinaDetail{
position:absolute;
bottom: 80px;
right: 28vw;
z-index: 100;
width: 140px;
.el-button,.el-button + .el-button{
margin: 0;
margin-bottom: 5px;
padding: 5px 15px;
width: 100%;
background-color: #b3afaf33;
color: #fff;
border-radius: 0;
text-align: left;
border: 0;
line-height: 2rem;
.svg-icon{
font-size: 1.4rem;
margin-right: 0.6rem;
}
}
.svg-icon{
font-size: 2rem;
margin-right: 0.6rem;
}
.active{
background-color: #ffffff6b!important;
}
}
.provinceDetail{
position:absolute;
bottom: 90px;
left: 30vw;
z-index: 100;
width: 400px;
height: auto;
// background-color: #cbdae51a;
}
.switchDataBtn{
position: absolute;
bottom: 3vh;
right: 35vw;
.el-button,.el-button + .el-button{
width: 10vw;
margin-bottom: 5px;
padding: 5px 15px;
// width: 100%;
// background-color: #24253a;
background-image: url('../../assets/images/monitorSelect/btn.png');
background-repeat: no-repeat;
background-size: 100% 100%;
border-radius: 0;
font-size: 1.2rem;
font-family: Source Han Sans CN;
font-weight: bold;
letter-spacing: 0.2rem;
// text-align: left;
border: 0;
line-height: 3rem;
}
.el-button--default{
color: #91d4fe;
}
.active{
color: #ffffff;
background-image: url('../../assets/images/monitorSelect/btn-p.png')!important;
}
}
</style>

View File

@ -1,552 +0,0 @@
<template>
<div>
<div class="top">
<div class="canvasBox">
<canvas id="container" />
</div>
</div>
<div class="spin">
<div class="circle circle1">
<div class="turnAround" />
</div>
<div class="circle circle2">
<div class="turnAround" />
</div>
<div class="circle circle3">
<div class="turnAround" />
</div>
</div>
</div>
</template>
<script>
import guangdongJson from './geoJson/guangdong.json'
import guangdongOutline from './geoJson/guangdongOutline.json'
import chuanyuJson from './geoJson/chuanyu.json'
import gansuJson from './geoJson/gansu.json'
import guizhouJson from './geoJson/guizhou.json'
import jingjinjiJson from './geoJson/jingjinji.json'
import neimengguJson from './geoJson/neimenggu.json'
import ningxiaJson from './geoJson/ningxia.json'
import changsanjiaoJson from './geoJson/changsanjiao.json'
import hunanJson from './geoJson/hunan.json'
import hunanOutline from './geoJson/hunanOutline.json'
export default {
props: {
value: {
type: Boolean,
default: false
},
mapType: {
type: Number,
default: 1
},
// count: {
// type: Object,
// default: () => { return { ys: 0, zs: 0, cs: 0 } }
// },
cluster: {
type: Array,
default: () => []
}
},
data() {
return {
selectedCity: '',
allJSON: {
guangdongJson,
chuanyuJson,
gansuJson,
guizhouJson, jingjinjiJson, neimengguJson, ningxiaJson, changsanjiaoJson,
guangdongOutline, hunanJson, hunanOutline
},
currentIndex: 0,
interval: undefined,
img: undefined,
activeTab: '',
scale: 1,
geoCenter: {},
offsetX: 0,
offsetY: 0,
eventType: '',
cursorFlag: false,
mapMap: {
1: 'ningxia',
2: 'neimenggu',
3: 'gansu',
4: 'guizhou',
5: 'guangdong',
6: 'chuanyu',
7: 'changsanjiao',
8: 'jingjinji',
9: 'hunan'
},
mapName: {
1: '宁夏回族自治区',
2: '内蒙古自治区',
3: '甘肃省',
4: '贵州省',
5: '粤港澳大湾区',
6: '川渝地区',
7: '长三角地区',
8: '京津冀地区',
9: '湖南省'
}
// geoCenterY: 0
}
},
computed: {
dialogVisible: {
get() {
return this.value
},
set(value) {
this.$emit('input', value)
}
}
},
watch: {
mapType(val) {
if (val) {
this.getBoxArea()
this.drawMap()
}
}
},
mounted() {
this.getBoxArea()
this.$nextTick(() => {
this.img = new Image()
this.img.src = process.env.VUE_APP_PUBLIC_SOURCE_API + '/click-point.svg'
this.img.addEventListener('load', () => {
this.setDataRoll()
})
const canvas = document.querySelector('#container')
//
canvas.addEventListener('mousemove', (event) => {
this.offsetX = event.offsetX / 0.55
this.offsetY = event.offsetY / 0.65
this.eventType = 'mousemove'
this.drawMap()
})
//
canvas.addEventListener('click', (event) => {
this.offsetX = event.offsetX / 0.55
this.offsetY = event.offsetY / 0.65
this.eventType = 'click'
clearInterval(this.interval)
this.drawMap()
})
})
},
methods: {
setDataRoll() {
clearInterval(this.interval)
this.interval = setInterval(() => {
this.currentIndex = (this.currentIndex + 1) % this.cluster.length//
this.drawMap()
}, 4000)
},
clickback() {
this.dialogVisible = false
},
filterData(data) {
this.selectedCity = data
if (data === '') {
this.setDataRoll()
}
this.$emit('selectedCity', data)
},
drawMap() {
const canvas = document.querySelector('#container')
const ctx = canvas.getContext('2d')
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight)
this.initOutline()
this.initMap()
this.setPoint()
},
setPoint() {
const canvas = document.querySelector('#container')
const ctx = canvas.getContext('2d')
ctx.beginPath()
this.cluster.forEach((e, i) => {
const position = this.toScreenPosition(e.longitude, e.latitude)
if (this.currentIndex === i) {
ctx.drawImage(this.img, position.x - 40, position.y - 55, 80, 80)
ctx.fillStyle = 'rgba(255, 197, 39, 1)'
ctx.font = '30px PangMenZhengDao'
ctx.fillText(e.name, position.x - e.name.length / 2 * 35, position.y - 55)
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'
const txtlength = e.name.length > e.address.length ? e.name.length : e.address.length
ctx.fillRect(position.x + 20, position.y + 5, txtlength * 27, 90)
ctx.strokeStyle = '#3EDFFC'
ctx.strokeRect(position.x + 20, position.y + 5, txtlength * 27, 90)
ctx.fillStyle = '#FFFFFF'
ctx.font = '20px Arial'
ctx.fillText('名称:' + e.name, position.x + 20 + 20, position.y + 5 + 40)
ctx.fillText('地址:' + e.address || '-', position.x + 20 + 20, position.y + 5 + 70)
} else {
ctx.beginPath()
ctx.arc(position.x, position.y, 5, 0, Math.PI * 2) // 5
ctx.fillStyle = '#ffffff' //
ctx.fill()
ctx.closePath()
}
})
ctx.stroke()
ctx.restore()
},
getBoxArea() {
const canvasW = window.innerWidth
const canvasH = window.innerHeight
let N = -90; let S = 90; let W = 180; let E = -180
this.allJSON[this.mapMap[this.mapType] + 'Json'].features.forEach(item => {
if (item.geometry.type === 'Polygon') {
item.geometry.coordinates = [item.geometry.coordinates]
}
item.geometry.coordinates.forEach(area => {
area[0].forEach(elem => {
if (elem[0] < W) {
W = elem[0]
}
if (elem[0] > E) {
E = elem[0]
}
if (elem[1] > N) {
N = elem[1]
}
if (elem[1] < S) {
S = elem[1]
}
})
})
})
var wScale = canvasW / Math.abs(E - W)
var hScale = canvasH / Math.abs(N - S)
this.scale = (wScale > hScale ? hScale : wScale) * 0.9
this.geoCenter = {
W: W,
N: N,
xoffset: canvasW / 2 - Math.abs(E - W) / 2 * this.scale,
yoffset: canvasH / 2 - Math.abs(N - S) / 2 * this.scale
}
},
toScreenPosition(longitude, latitude) {
return {
x: (longitude - this.geoCenter.W) * this.scale + this.geoCenter.xoffset,
y: (this.geoCenter.N - latitude) * this.scale + this.geoCenter.yoffset
}
},
initMap() {
const canvas = document.querySelector('#container')
const ctx = canvas.getContext('2d')
this.cursorFlag = false
ctx.beginPath()
ctx.strokeStyle = '#3EDFFC'
ctx.lineWidth = 1
this.allJSON[this.mapMap[this.mapType] + 'Json'].features.forEach(elem => {
const coordinates = elem.geometry.coordinates
coordinates.forEach(multiPolygon => {
multiPolygon.forEach(polygon => {
ctx.save()
ctx.beginPath()
// ctx.translate(0, 0)
for (let i = 0; i < polygon.length; i++) {
const position = this.toScreenPosition(polygon[i][0], polygon[i][1])
if (i === 0) {
ctx.moveTo(position.x, position.y - 5)
} else {
ctx.lineTo(position.x, position.y - 5)
}
}
ctx.closePath()
ctx.strokeStyle = '#34CEE9'
ctx.lineWidth = 1
if (ctx.isPointInPath(this.offsetX, this.offsetY)) {
this.cursorFlag = true
ctx.fillStyle = '#a2f7ff'
if (this.eventType === 'click') {
this.filterData(elem.properties.name)
//
}
} else {
if (this.eventType === 'mousemove' && this.selectedCity === '') ctx.fillStyle = 'transparent'
}
if (this.selectedCity === elem.properties.name) ctx.fillStyle = '#00eaff'
ctx.fill()
ctx.stroke()
ctx.restore()
})
})
})
if (this.cursorFlag) {
canvas.style.cursor = 'pointer'
} else {
canvas.style.cursor = 'default'
}
},
initOutline() {
const canvas = document.querySelector('#container')
const ctx = canvas.getContext('2d')
const canvasW = canvas.width = window.innerWidth
const canvasH = canvas.height = window.innerHeight
ctx.clearRect(0, 0, canvasW, canvasH)
ctx.fillStyle = 'transparent'
ctx.fillRect(0, 0, canvasW, canvasH)
ctx.beginPath()
ctx.strokeStyle = '#3EDFFC'
ctx.lineWidth = 1
this.allJSON[this.mapMap[this.mapType] + 'Outline'].features.forEach(elem => {
const coordinates = elem.geometry.coordinates
ctx.save()
coordinates.forEach(multiPolygon => {
multiPolygon.forEach(polygon => {
for (let i = 0; i < polygon.length; i++) {
const position = this.toScreenPosition(polygon[i][0], polygon[i][1])
if (i === 0) {
ctx.moveTo(position.x, position.y + 5)
} else {
ctx.lineTo(position.x, position.y + 5)
}
}
})
})
})
ctx.closePath()
if (!ctx.isPointInPath(this.offsetX, this.offsetY)) {
if (this.eventType === 'click') {
this.filterData('')
//
}
}
ctx.fillStyle = '#3edffc'
var grd = ctx.createLinearGradient(0, 0, 1500, 0)
for (let i = 0; i < 1000; i++) {
grd.addColorStop(i / 1000, 'white')
grd.addColorStop(i / 1000 + 0.001, '#059BFC')
}
ctx.fillStyle = grd
// ctx.shadowColor = '#3EDFFC'
// ctx.shadowBlur = 0
// // ctx.shadowOffsetX = 50
// ctx.shadowOffsetY = 20
ctx.fill()
ctx.stroke()
ctx.restore()
ctx.beginPath()
this.allJSON[this.mapMap[this.mapType] + 'Outline'].features.forEach(elem => {
const coordinates = elem.geometry.coordinates
ctx.save()
coordinates.forEach(multiPolygon => {
multiPolygon.forEach(polygon => {
for (let i = 0; i < polygon.length; i++) {
const position = this.toScreenPosition(polygon[i][0], polygon[i][1])
if (i === 0) {
ctx.moveTo(position.x, position.y - 5)
} else {
ctx.lineTo(position.x, position.y - 5)
}
}
})
})
})
ctx.closePath()
var g = ctx.createRadialGradient(700, 600, 50, 1000, 600, 600)
g.addColorStop(0, '#29a0ee')
g.addColorStop(1, '#0b4eaf')
ctx.fillStyle = g
ctx.fill()
ctx.stroke()
ctx.restore()
}
}
}
</script>
<style lang="scss" scoped>
.back{
position:absolute;
top: 20vh;
left: 31vw;
z-index: 99;
}
.data-view {
position: absolute;
right: 0px;
border: 1px solid #3EDFFC;
padding: 0 10px;
margin: 10px;
background-color: #1a2d47ad;
bottom: 0;
font-size: 0.8rem;
p{
color: #DDDDDD;
text-indent: 1rem;
position: relative;
}
p:before{
content: '';
display: block;
width: 8px;
height: 8px;
border-radius: 8px;
background-color: #0fe765;
position: absolute;
left: 3px;
top: 3px;
}
p:nth-child(3):before{
background-color: #3EDFFC;
}
p:nth-child(4):before{
background-color: #f3ca45;
}
h5{font-weight: bold; font-size: 1rem; margin: 1rem 0}
}
.top{
width: 100%;
position: absolute;
display: block;
height: 60vh;
z-index: 8;
}
.center{
position:absolute;
bottom: 11vh;
right: 30vw;
z-index: 100;
width: 20vh;
.el-button,.el-button + .el-button{
margin: 0;
// margin-bottom: 10px;
// padding: 10px 15px;
padding: 0.5vh 2rem;
height: 5vh;
width: 100%;
background: url(../../assets/monitor/b.png) left no-repeat;
background-size: 100% 100%;
font-weight: 500;
font-style: italic;
color: #FFFFFF;
text-shadow: 0px 2px 6px rgba(19,23,27,0.31);
border-radius: 0;
text-align: left;
border: 0;
// line-height: 4vh;
div{
font-size: 1.2rem;
@media screen and (max-height: 900px) {
// transform: scale(0.8);
font-size: 0.8rem;
}
}
}
.active{
background: url(../../assets/monitor/b-p.png) left no-repeat;
background-size: 100% 100%;
}
}
.canvasBox{
width: 100%;
height: 100%;
position: relative;
}
#container {
width: 55vw;
height: 65vh;
margin: auto;
margin-top: 18vh;
display: block;
}
.spin{
width: 100%;
height: 30vh;
display: block;
position: absolute;
bottom: 0;
perspective: 200vh;
z-index: 0;
// animation: rotate 13s linear infinite;
.circle {
width: 50vw;
height: 30vh;
position: absolute;
left: 0;
top: -49vh;
display: block;
// border: 1px solid #ffffff;
}
.circle1{
width: 28vw;
height: 80vh;
top: -25.5vh;
left: 36vw;
transform: rotateX(80deg);
.turnAround{
width: 100%;
height: 100%;
animation: rotate 8s linear infinite;
background: url('../../assets/monitor/circle1.png') center no-repeat;
background-size: 80% auto;
}
}
.circle2{
width: 54vw;
height: 99vh;
left: 23vw;
top: -34vh;
transform: rotateX(80deg);
.turnAround{
width: 100%;
height: 100%;
animation: backRotate 15s linear infinite;
background: url('../../assets/monitor/circle2.png') center no-repeat;
background-size: 80% auto;
}
}
.circle3{
width: 46vw;
height: 80vh;
left: 27vw;
top: -25vh;
transform: rotateX(80deg);
.turnAround{
width: 100%;
height: 100%;
animation: rotate 10s linear infinite;
background: url('../../assets/monitor/circle3.png') center no-repeat;
background-size: 80% auto;
opacity: 0.5;
}
}
@keyframes rotate {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
@keyframes backRotate {
0% {
transform: rotate(360deg);
}
100% {
transform: rotate(0deg);
}
}
}
</style>

View File

@ -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 => {

View File

@ -154,7 +154,7 @@ export default {
})
},
goBack() {
this.$router.push({ path: '/taskManagement/instanceCenter' })
this.$router.push({ path: '/taskManagement/aiList' })
},
saveForm() {
this.$refs.formData.validate((valid) => {

Some files were not shown because too many files have changed in this diff Show More