@@ -0,0 +1,97 @@ | |||
package com.ruoyi.web.controller.file; | |||
import com.ruoyi.common.core.controller.BaseController; | |||
import com.ruoyi.common.core.domain.AjaxResult; | |||
import com.ruoyi.file.model.FileModel; | |||
import com.ruoyi.file.model.FileSystemFilter; | |||
import com.ruoyi.file.object.ProjectState; | |||
import com.ruoyi.file.object.StateMachine; | |||
import com.ruoyi.file.service.FileSystemService; | |||
import com.ruoyi.file.service.StateService; | |||
import io.swagger.annotations.Api; | |||
import io.swagger.annotations.ApiOperation; | |||
import org.springframework.beans.factory.annotation.Autowired; | |||
import org.springframework.security.access.prepost.PreAuthorize; | |||
import org.springframework.web.bind.annotation.GetMapping; | |||
import org.springframework.web.bind.annotation.PathVariable; | |||
import org.springframework.web.bind.annotation.PostMapping; | |||
import org.springframework.web.bind.annotation.RequestMapping; | |||
import org.springframework.web.bind.annotation.RestController; | |||
import java.util.List; | |||
/** | |||
* 状态Controller | |||
* | |||
* @author zhao | |||
* @date 2023-10-19 | |||
*/ | |||
@Api(tags = "状态") | |||
@RestController | |||
@RequestMapping("/state") | |||
public class StateController extends BaseController | |||
{ | |||
@Autowired | |||
private StateService stateService; | |||
/** | |||
* 查询项目状态列表 | |||
*/ | |||
@ApiOperation("查询项目状态列表") | |||
@PreAuthorize("@ss.hasPermi('admin:state:list')") | |||
@GetMapping("/list") | |||
public AjaxResult list() | |||
{ | |||
List<ProjectState> detail = stateService.list(); | |||
return AjaxResult.success(detail); | |||
} | |||
/** | |||
* 查询项目状态 | |||
*/ | |||
@ApiOperation("查询项目状态") | |||
@PreAuthorize("@ss.hasPermi('admin:state:detail')") | |||
@GetMapping("/detail/{token}") | |||
public AjaxResult detail(@PathVariable String token) | |||
{ | |||
ProjectState detail = stateService.detail(token); | |||
return null != detail ? AjaxResult.success(detail) : AjaxResult.error(); | |||
} | |||
/** | |||
* GC | |||
*/ | |||
@ApiOperation("GC") | |||
@PreAuthorize("@ss.hasPermi('admin:state:gc')") | |||
@PostMapping("/gc") | |||
public AjaxResult gc() | |||
{ | |||
long count = stateService.gc(); | |||
return AjaxResult.success(count); | |||
} | |||
/** | |||
* 查询状态机信息 | |||
*/ | |||
@ApiOperation("查询状态机信息") | |||
@PreAuthorize("@ss.hasPermi('admin:state:machine')") | |||
@GetMapping("/machine") | |||
public AjaxResult stateMachine() | |||
{ | |||
StateMachine stateMachine = stateService.stateMachine(); | |||
return AjaxResult.success(stateMachine); | |||
} | |||
/** | |||
* 备份 | |||
*/ | |||
@ApiOperation("dump") | |||
@PreAuthorize("@ss.hasPermi('admin:state:dump')") | |||
@PostMapping("/dump") | |||
public AjaxResult dump() | |||
{ | |||
stateService.dump(); | |||
return AjaxResult.success(); | |||
} | |||
} |
@@ -6,9 +6,9 @@ spring: | |||
druid: | |||
# 主库数据源 | |||
master: | |||
url: jdbc:mysql://127.0.0.1:3306/rongxin_gxzb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 | |||
username: xxx | |||
password: xxxx | |||
url: jdbc:mysql://localhost:3318/nsgk_file_transfer?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 | |||
username: gly | |||
password: glyadmin | |||
# 从库数据源 | |||
slave: | |||
# 从数据源开关/默认关闭 | |||
@@ -71,7 +71,7 @@ spring: | |||
# 地址 | |||
host: rongxin-redis-m-svc.prod | |||
# 端口,默认为6379 | |||
port: 6279 | |||
port: 6379 | |||
# 数据库索引 | |||
database: 0 | |||
# 密码 | |||
@@ -94,8 +94,7 @@ spring: | |||
# 生产环境配置 | |||
server: | |||
# 服务器的HTTP端口 | |||
port: ${NODE_PORT} | |||
address: ${NODE_HOST} | |||
port: 8077 | |||
aliyun: | |||
oss: | |||
@@ -1,7 +1,7 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<configuration> | |||
<!-- 日志存放路径 --> | |||
<property name="log.path" value="/mnt/data/logs/rongxin.gxzb.api" /> | |||
<property name="log.path" value="D:/NsgkSoft/files/nsgk/logs" /> | |||
<!-- 日志输出格式 --> | |||
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" /> | |||
@@ -1,6 +1,11 @@ | |||
package com.ruoyi.file.object; | |||
import cn.hutool.core.bean.BeanUtil; | |||
import cn.hutool.core.bean.copier.CopyOptions; | |||
import java.util.Date; | |||
import java.util.List; | |||
import java.util.Map; | |||
public final class ProjectState | |||
{ | |||
@@ -123,6 +128,14 @@ public final class ProjectState | |||
return sb.toString(); | |||
} | |||
public static ProjectState FromMap(Map<?, ?> parms) | |||
{ | |||
CopyOptions options = CopyOptions.create(); | |||
options.setIgnoreError(true); | |||
ProjectState projectState = BeanUtil.mapToBean(parms, ProjectState.class, false, options); | |||
return projectState; | |||
} | |||
public ProjectState() {} | |||
public ProjectState(String token) | |||
@@ -1,7 +1,12 @@ | |||
package com.ruoyi.file.object; | |||
import cn.hutool.core.bean.BeanUtil; | |||
import cn.hutool.core.bean.copier.CopyOptions; | |||
import java.util.ArrayList; | |||
import java.util.Date; | |||
import java.util.LinkedHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
public final class StateMachine | |||
@@ -21,16 +26,19 @@ public final class StateMachine | |||
public long gcCount; // GC次数 | |||
public Date lastGCTime; // 最近GC时间 | |||
private final Map<String, ProjectState> projectStateMap = new LinkedHashMap<>(); | |||
public static final StateMachine INSTANCE = new StateMachine(); | |||
public Date startTime = new Date(); // 本次开始时间 | |||
public Date lastEndTime; // 上次结束时间 | |||
private final Map<String, ProjectState> stateMap = new LinkedHashMap<>(); | |||
public static final StateMachine INSTANCE = new StateMachine(); | |||
public synchronized void AddState(ProjectState state) | |||
{ | |||
ProjectState projectState = projectStateMap.get(state.token); | |||
ProjectState projectState = stateMap.get(state.token); | |||
if(null != projectState) | |||
projectState.Sum(state); | |||
else | |||
projectStateMap.put(state.token, state); | |||
stateMap.put(state.token, state); | |||
Sum(state); | |||
} | |||
@@ -55,13 +63,13 @@ public final class StateMachine | |||
this.maxHandleDuration += state.maxHandleDuration; | |||
} | |||
private ProjectState GetState(String token) | |||
private ProjectState State(String token) | |||
{ | |||
ProjectState state = projectStateMap.get(token); | |||
ProjectState state = stateMap.get(token); | |||
if(null == state) | |||
{ | |||
state = new ProjectState(token); | |||
projectStateMap.put(token, state); | |||
stateMap.put(token, state); | |||
} | |||
return state; | |||
} | |||
@@ -69,94 +77,94 @@ public final class StateMachine | |||
public void AddUploadSize(String token, long uploadSize) | |||
{ | |||
this.uploadSize += uploadSize; | |||
GetState(token).AddUploadSize(uploadSize); | |||
State(token).AddUploadSize(uploadSize); | |||
} | |||
public void AddWriteSize(String token, long writeSize) | |||
{ | |||
this.writeSize += writeSize; | |||
GetState(token).AddWriteSize(writeSize); | |||
State(token).AddWriteSize(writeSize); | |||
} | |||
public void AddNumUpload(String token, long numUpload) | |||
{ | |||
this.numUpload += numUpload; | |||
GetState(token).AddNumUpload(numUpload); | |||
State(token).AddNumUpload(numUpload); | |||
} | |||
public void AddNumWrite(String token, long numWrite) | |||
{ | |||
this.numWrite += numWrite; | |||
GetState(token).AddNumWrite(numWrite); | |||
State(token).AddNumWrite(numWrite); | |||
} | |||
public void AddNumError(String token, long numError) | |||
{ | |||
this.numError += numError; | |||
GetState(token).AddNumError(numError); | |||
State(token).AddNumError(numError); | |||
} | |||
public void SetLastUploadTime(String token, Date lastUploadTime) | |||
{ | |||
this.lastUploadTime = lastUploadTime; | |||
GetState(token).SetLastUploadTime(lastUploadTime); | |||
State(token).SetLastUploadTime(lastUploadTime); | |||
} | |||
public void SetLastWriteTime(String token, Date lastWriteTime) | |||
{ | |||
this.lastWriteTime = lastWriteTime; | |||
GetState(token).SetLastWriteTime(lastWriteTime); | |||
State(token).SetLastWriteTime(lastWriteTime); | |||
} | |||
public void SetLastErrorTime(String token, Date lastErrorTime) | |||
{ | |||
this.lastErrorTime = lastErrorTime; | |||
GetState(token).SetLastErrorTime(lastErrorTime); | |||
State(token).SetLastErrorTime(lastErrorTime); | |||
} | |||
public void SetMaxUploadSize(String token, long maxUploadSize) | |||
{ | |||
if(maxUploadSize > this.maxUploadSize) | |||
this.maxUploadSize = maxUploadSize; | |||
GetState(token).SetMaxUploadSize(maxUploadSize); | |||
State(token).SetMaxUploadSize(maxUploadSize); | |||
} | |||
public void SetMaxWriteSize(String token, long maxWriteSize) | |||
{ | |||
if(maxWriteSize > this.maxWriteSize) | |||
this.maxWriteSize += maxWriteSize; | |||
GetState(token).SetMaxWriteSize(maxWriteSize); | |||
State(token).SetMaxWriteSize(maxWriteSize); | |||
} | |||
public void SetMaxHandleDuration(String token, long maxHandleDuration) | |||
{ | |||
if(maxHandleDuration > this.maxHandleDuration) | |||
this.maxHandleDuration += maxHandleDuration; | |||
GetState(token).SetMaxHandleDuration(maxHandleDuration); | |||
State(token).SetMaxHandleDuration(maxHandleDuration); | |||
} | |||
public void IncrUploadSize(String token, long uploadSize) | |||
{ | |||
this.uploadSize += uploadSize; | |||
GetState(token).AddUploadSize(uploadSize); | |||
State(token).AddUploadSize(uploadSize); | |||
} | |||
public void IncrNumUpload(String token) | |||
{ | |||
this.numUpload++; | |||
GetState(token).AddNumUpload(1); | |||
State(token).AddNumUpload(1); | |||
} | |||
public void IncrNumWrite(String token) | |||
{ | |||
this.numWrite++; | |||
GetState(token).AddNumWrite(1); | |||
State(token).AddNumWrite(1); | |||
} | |||
public void IncrNumError(String token) | |||
{ | |||
this.numError++; | |||
GetState(token).AddNumError(1); | |||
State(token).AddNumError(1); | |||
} | |||
public void GC() | |||
@@ -166,5 +174,81 @@ public final class StateMachine | |||
lastGCTime = new Date(); | |||
} | |||
public ProjectState GetState(String token) | |||
{ | |||
return stateMap.get(token); | |||
} | |||
public List<ProjectState> GetStates() | |||
{ | |||
return new ArrayList<>(stateMap.values()); | |||
} | |||
public void FromMap(Map<?, ?> parms) | |||
{ | |||
CopyOptions options = CopyOptions.create(); | |||
options.setIgnoreProperties("startTime"); | |||
options.setIgnoreError(true); | |||
BeanUtil.fillBeanWithMap(parms, this, options); | |||
Object obj = parms.get("stateMap"); | |||
if(obj instanceof Map) | |||
{ | |||
Map<?, ?> m = (Map<?, ?>) obj; | |||
m.forEach((k, v) -> { | |||
ProjectState s = ProjectState.FromMap((Map<?, ?>)v); | |||
stateMap.put(s.token, s); | |||
}); | |||
} | |||
} | |||
public Map<?, ?> ToMap() | |||
{ | |||
Map<String, Object> map = BeanUtil.beanToMap(this); | |||
map.put("stateMap", stateMap); | |||
return map; | |||
} | |||
public void Finish() | |||
{ | |||
lastEndTime = new Date(); | |||
} | |||
public String ToString(String split) | |||
{ | |||
StringBuilder sb = new StringBuilder(); | |||
sb.append("上传文件大小: ").append(uploadSize); | |||
sb.append(split); | |||
sb.append("写入文件大小: ").append(writeSize); | |||
sb.append(split); | |||
sb.append("上传文件数: ").append(numUpload); | |||
sb.append(split); | |||
sb.append("写入文件数: ").append(numWrite); | |||
sb.append(split); | |||
sb.append("上传错误数: ").append(numError); | |||
sb.append(split); | |||
sb.append("最近上传时间: ").append(lastUploadTime); | |||
sb.append(split); | |||
sb.append("最近写入时间: ").append(lastWriteTime); | |||
sb.append(split); | |||
sb.append("最近错误时间: ").append(lastErrorTime); | |||
sb.append(split); | |||
sb.append("最大上传文件大小: ").append(maxUploadSize); | |||
sb.append(split); | |||
sb.append("最大写入文件大小: ").append(maxWriteSize); | |||
sb.append(split); | |||
sb.append("最大处理间隔: ").append(maxHandleDuration); | |||
sb.append(split); | |||
sb.append("GC次数: ").append(gcCount); | |||
sb.append(split); | |||
sb.append("最近GC时间: ").append(lastGCTime); | |||
sb.append(split); | |||
sb.append("本次开始时间: ").append(startTime); | |||
sb.append(split); | |||
sb.append("上次结束时间: ").append(lastEndTime); | |||
sb.append(split); | |||
sb.append("记录数: ").append(stateMap.size()); | |||
return sb.toString(); | |||
} | |||
private StateMachine() {} | |||
} |
@@ -0,0 +1,90 @@ | |||
package com.ruoyi.file.service; | |||
import com.alibaba.fastjson2.JSON; | |||
import com.ruoyi.common.core.redis.RedisCache; | |||
import com.ruoyi.common.utils.StringUtils; | |||
import com.ruoyi.common.utils.spring.SpringUtils; | |||
import com.ruoyi.file.object.ProjectState; | |||
import com.ruoyi.file.object.StateMachine; | |||
import com.ruoyi.file.utils.ProjectUtils; | |||
import lombok.extern.slf4j.Slf4j; | |||
import org.springframework.stereotype.Service; | |||
import javax.annotation.PostConstruct; | |||
import javax.annotation.PreDestroy; | |||
import java.util.Date; | |||
import java.util.List; | |||
import java.util.Map; | |||
@Service | |||
@Slf4j | |||
public class StateService | |||
{ | |||
private static final String STATE_MACHINE_KEY = "STATE_MACHINE"; | |||
public ProjectState detail(String token) | |||
{ | |||
return StateMachine.INSTANCE.GetState(token); | |||
} | |||
public List<ProjectState> list() | |||
{ | |||
return StateMachine.INSTANCE.GetStates(); | |||
} | |||
public long gc() | |||
{ | |||
StateMachine.INSTANCE.GC(); | |||
return StateMachine.INSTANCE.gcCount; | |||
} | |||
public StateMachine stateMachine() | |||
{ | |||
return StateMachine.INSTANCE; | |||
} | |||
public void dump() | |||
{ | |||
destroy(); | |||
} | |||
@PostConstruct | |||
public void init() | |||
{ | |||
try | |||
{ | |||
RedisCache redisCache = SpringUtils.getBean(RedisCache.class); | |||
String stateMachine = redisCache.getCacheObject(STATE_MACHINE_KEY); | |||
if(StringUtils.isNotEmpty(stateMachine)) | |||
{ | |||
Map<?, ?> map = JSON.parseObject(stateMachine, Map.class); | |||
StateMachine.INSTANCE.FromMap(map); | |||
log.info("读取持久化状态机信息: "); | |||
log.info(StateMachine.INSTANCE.ToString("; ")); | |||
} | |||
} | |||
catch(Exception e) | |||
{ | |||
e.printStackTrace(); | |||
} | |||
} | |||
@PreDestroy | |||
public void destroy() | |||
{ | |||
try | |||
{ | |||
StateMachine.INSTANCE.Finish(); | |||
Map<?, ?> map = StateMachine.INSTANCE.ToMap(); | |||
String json = JSON.toJSONString(map); | |||
RedisCache redisCache = SpringUtils.getBean(RedisCache.class); | |||
redisCache.setCacheObject(STATE_MACHINE_KEY, json); | |||
log.info("备份持久化状态机信息: "); | |||
log.info(StateMachine.INSTANCE.ToString("; ")); | |||
} | |||
catch(Exception e) | |||
{ | |||
e.printStackTrace(); | |||
} | |||
} | |||
} |
@@ -128,6 +128,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter | |||
.antMatchers("/open/**").permitAll() | |||
// 静态资源 | |||
.antMatchers("/static/**").permitAll() | |||
.antMatchers("/adminLogout").permitAll() | |||
// 除上面外的所有请求全部需要鉴权认证 | |||
.anyRequest().authenticated() | |||
@@ -229,7 +229,8 @@ public class SysUserServiceImpl implements ISysUserService | |||
{ | |||
if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin()) | |||
{ | |||
throw new ServiceException("不允许操作超级管理员用户"); | |||
if(!SecurityUtils.getLoginUser().getUser().isAdmin()) | |||
throw new ServiceException("不允许操作超级管理员用户"); | |||
} | |||
} | |||
@@ -0,0 +1,36 @@ | |||
import request from '@/utils/request' | |||
export function stateList() { | |||
return request({ | |||
url: '/state/list', | |||
method: 'get', | |||
}) | |||
} | |||
export function stateDetail(token) { | |||
return request({ | |||
url: '/state/detail/' + token, | |||
method: 'get', | |||
}) | |||
} | |||
export function gc() { | |||
return request({ | |||
url: '/state/gc', | |||
method: 'post', | |||
}) | |||
} | |||
export function stateMachine() { | |||
return request({ | |||
url: '/state/machine', | |||
method: 'get', | |||
}) | |||
} | |||
export function dump() { | |||
return request({ | |||
url: '/state/dump', | |||
method: 'post', | |||
}) | |||
} |
@@ -64,6 +64,7 @@ | |||
<el-dropdown :split-button="false" type="text" class="dropdown el-dropdown-link"> | |||
<span style="cursor: pointer; font-size: 10px; color:#1890FF"><!--更多--><i class="el-icon-arrow-down el-icon--right"></i></span> | |||
<el-dropdown-menu slot="dropdown" style="padding: 10px"> | |||
<el-button size="mini" type="text" icon="el-icon-view" @click="viewProjectState(scope.row)" v-hasPermi="['admin:state:detail']">状态</el-button> | |||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['file:project:remove']">删除</el-button> | |||
</el-dropdown-menu> | |||
</el-dropdown> | |||
@@ -136,6 +137,11 @@ | |||
<el-dialog title="选择目录" :visible.sync="fileOpen" width="600px" append-to-body> | |||
<ServerFileChooser v-model="form.diskPath" :file-type="2" @selected="closeFileChooser"/> | |||
</el-dialog> | |||
<FullscreenDialog title="项目状态" :visible.sync="stateOpen" @close="closeProjectState"> | |||
<ProjectState :token="projectToken"/> | |||
</FullscreenDialog> | |||
</div> | |||
</template> | |||
@@ -143,11 +149,15 @@ | |||
import {listProject, getProject, delProject, addProject, updateProject, switchDisable} from "@/api/file/project"; | |||
import DeptSelect from "@/components/common/DeptSelect.vue"; | |||
import ServerFileChooser from "@/components/ServerFileChooser.vue"; | |||
import FullscreenDialog from "@/components/FullscreenDialog.vue"; | |||
import ProjectState from "@/views/file/state/ProjectState.vue"; | |||
export default { | |||
name: "Project", | |||
components: { | |||
ProjectState, | |||
FullscreenDialog, | |||
ServerFileChooser, | |||
DeptSelect | |||
}, | |||
@@ -225,6 +235,8 @@ export default { | |||
// 对话框显示只读的详情 | |||
viewOpen: false, | |||
fileOpen: false, | |||
stateOpen: false, | |||
projectToken: null, | |||
}; | |||
}, | |||
created() { | |||
@@ -248,6 +260,7 @@ export default { | |||
this.open = false; | |||
this.viewOpen = false; | |||
this.fileOpen = false; | |||
this.stateOpen = false; | |||
this.reset(); | |||
}, | |||
// 表单重置 | |||
@@ -382,6 +395,14 @@ export default { | |||
this.$modal.msgSuccess(what + "成功"); | |||
}).catch(() => {}); | |||
}, | |||
viewProjectState(row) { | |||
this.projectToken = row.token; | |||
this.stateOpen = true; | |||
}, | |||
closeProjectState() { | |||
this.stateOpen = false; | |||
this.projectToken = null; | |||
}, | |||
}, | |||
}; | |||
</script> |
@@ -0,0 +1,65 @@ | |||
<template> | |||
<Descriptions> | |||
<el-descriptions-item label="上传字节数">{{state.uploadSize}}</el-descriptions-item> | |||
<el-descriptions-item label="写入字节数">{{state.writeSize}}</el-descriptions-item> | |||
<el-descriptions-item label="上传文件数">{{state.numUpload}}</el-descriptions-item> | |||
<el-descriptions-item label="写入文件数">{{state.numWrite}}</el-descriptions-item> | |||
<el-descriptions-item label="处理错误数">{{state.numError}}</el-descriptions-item> | |||
<el-descriptions-item label="最近上传时间">{{state.lastUploadTime}}</el-descriptions-item> | |||
<el-descriptions-item label="最近写入时间">{{state.lastWriteTime}}</el-descriptions-item> | |||
<el-descriptions-item label="最近错误时间">{{state.lastErrorTime}}</el-descriptions-item> | |||
<el-descriptions-item label="最大上传字节数">{{state.maxUploadSize}}</el-descriptions-item> | |||
<el-descriptions-item label="最大写入字节数">{{state.maxWriteSize}}</el-descriptions-item> | |||
<el-descriptions-item label="最长处理时间">{{state.maxHandleDuration}}</el-descriptions-item> | |||
</Descriptions> | |||
</template> | |||
<script> | |||
import Descriptions from "@/components/common/Descriptions.vue"; | |||
import {stateDetail} from "@/api/file/state"; | |||
export default { | |||
name: 'ProjectState', | |||
components: {Descriptions}, | |||
props: { | |||
token: { | |||
type: String, | |||
} | |||
}, | |||
data() { | |||
return { | |||
state: {}, | |||
}; | |||
}, | |||
created() { | |||
this.getStateDetail(); | |||
}, | |||
methods: { | |||
getStateDetail() { | |||
this.state = {}; | |||
if(!this.token) | |||
return; | |||
stateDetail(this.token).then((resp) => { | |||
if(resp.data) | |||
{ | |||
this.state = resp.data; | |||
} | |||
else | |||
{ | |||
this.$message.error('暂无状态'); | |||
} | |||
}); | |||
}, | |||
}, | |||
watch: { | |||
token(newVal) { | |||
this.getStateDetail(); | |||
}, | |||
}, | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
</style> |
@@ -0,0 +1,203 @@ | |||
<template> | |||
<div class="app-container"> | |||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> | |||
<el-form-item> | |||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> | |||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> | |||
</el-form-item> | |||
</el-form> | |||
<el-row :gutter="10" class="mb8"> | |||
<el-col :span="1.5"> | |||
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="gc" v-hasPermi="['admin:state:gc']">GC</el-button> | |||
</el-col> | |||
<el-col :span="1.5"> | |||
<el-button type="primary" plain icon="el-icon-download" size="mini" @click="dump" v-hasPermi="['admin:state:gc']">Dump</el-button> | |||
</el-col> | |||
<right-toolbar :showSearch.sync="showSearch" @queryTable="refresh"></right-toolbar> | |||
</el-row> | |||
<Descriptions> | |||
<el-descriptions-item label="上传字节数">{{state.uploadSize}}</el-descriptions-item> | |||
<el-descriptions-item label="写入字节数">{{state.writeSize}}</el-descriptions-item> | |||
<el-descriptions-item label="上传文件数">{{state.numUpload}}</el-descriptions-item> | |||
<el-descriptions-item label="写入文件数">{{state.numWrite}}</el-descriptions-item> | |||
<el-descriptions-item label="处理错误数">{{state.numError}}</el-descriptions-item> | |||
<el-descriptions-item label="最近上传时间">{{state.lastUploadTime}}</el-descriptions-item> | |||
<el-descriptions-item label="最近写入时间">{{state.lastWriteTime}}</el-descriptions-item> | |||
<el-descriptions-item label="最近错误时间">{{state.lastErrorTime}}</el-descriptions-item> | |||
<el-descriptions-item label="最大上传字节数">{{state.maxUploadSize}}</el-descriptions-item> | |||
<el-descriptions-item label="最大写入字节数">{{state.maxWriteSize}}</el-descriptions-item> | |||
<el-descriptions-item label="最长处理时间">{{state.maxHandleDuration}}</el-descriptions-item> | |||
<el-descriptions-item label="GC次数">{{state.gcCount}}</el-descriptions-item> | |||
<el-descriptions-item label="最近GC时间">{{state.lastGCTime}}</el-descriptions-item> | |||
<el-descriptions-item label="本次开始时间">{{state.startTime}}</el-descriptions-item> | |||
<el-descriptions-item label="上次结束时间">{{state.lastEndTime}}</el-descriptions-item> | |||
<el-descriptions-item label="记录数">{{total}}</el-descriptions-item> | |||
</Descriptions> | |||
<el-table v-loading="loading" :data="stateList" @selection-change="handleSelectionChange"> | |||
<!--<el-table-column type="selection" width="55" align="center" />--> | |||
<el-table-column type="index" label="序号" width="50" align="center" /> | |||
<!--<el-table-column label="ID" align="center" prop="id" min-width="60" />--> | |||
<el-table-column label="标识" align="center" prop="token" /> | |||
<el-table-column label="上传字节数" align="center" prop="uploadSize" /> | |||
<el-table-column label="上传文件数" align="center" prop="numUpload" /> | |||
<el-table-column label="处理错误数" align="center" prop="numError" /> | |||
<el-table-column label="最近上传时间" align="center" prop="lastUploadTime" /> | |||
<el-table-column label="最大上传字节数" align="center" prop="maxUploadSize" /> | |||
<el-table-column label="最长处理时间" align="center" prop="maxHandleDuration" /> | |||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width"> | |||
<template slot-scope="scope"> | |||
<el-button size="mini" type="text" icon="el-icon-view" @click="handleLook(scope.row)" v-hasPermi="['admin:state:detail']">查看</el-button> | |||
</template> | |||
</el-table-column> | |||
</el-table> | |||
<FullscreenDialog title="项目状态" :visible.sync="viewOpen" @close="closeProjectState"> | |||
<ProjectState :token="projectToken"/> | |||
</FullscreenDialog> | |||
</div> | |||
</template> | |||
<script> | |||
import DeptSelect from "@/components/common/DeptSelect.vue"; | |||
import ServerFileChooser from "@/components/ServerFileChooser.vue"; | |||
import FullscreenDialog from "@/components/FullscreenDialog.vue"; | |||
import ProjectState from "@/views/file/state/ProjectState.vue"; | |||
import {stateList, gc, stateMachine, dump} from "@/api/file/state"; | |||
import Descriptions from "@/components/common/Descriptions.vue"; | |||
export default { | |||
name: "State", | |||
components: { | |||
Descriptions, | |||
ProjectState, | |||
FullscreenDialog, | |||
ServerFileChooser, | |||
DeptSelect | |||
}, | |||
dicts: ['sys_bool'], | |||
data() { | |||
return { | |||
// 遮罩层 | |||
loading: false, | |||
// 遮罩按钮新增点击状态 | |||
diglogStatus: true, | |||
// 导出遮罩层 | |||
exportLoading: false, | |||
// 选中数组 | |||
ids: [], | |||
// 非单个禁用 | |||
single: true, | |||
// 非多个禁用 | |||
multiple: true, | |||
// 默认隐藏搜索条件 | |||
showSearch: false, | |||
// 总条数 | |||
total: 0, | |||
// 项目表格数据 | |||
stateList: [], | |||
// 弹出层标题 | |||
title: "", | |||
// 是否显示弹出层 | |||
open: false, | |||
// 是否禁用 字典 sys_bool字典 | |||
disabledOptions: [], | |||
// 查询参数 | |||
queryParams: { | |||
// 分页 | |||
pageNum: 1, | |||
pageSize: 10, | |||
// 查询排序 | |||
//orderByColumn: "id", | |||
//isAsc: "desc", | |||
// 翻译字典 | |||
//translate_dict: "1", | |||
}, | |||
// 表单参数 | |||
form: {}, | |||
// 详情组件列数 | |||
descColumn: 2, | |||
// 详情组件Label所占百分比, 最大={100 / descColumn}. 内容所占百分比={100 / descColumn - descLabelWidth} | |||
descLabelWidth: 15, | |||
// 对话框显示只读的详情 | |||
viewOpen: false, | |||
projectToken: null, | |||
state: {}, | |||
}; | |||
}, | |||
created() { | |||
this.getStateMachine(); | |||
this.getList(); | |||
}, | |||
methods: { | |||
/** 查询项目列表 */ | |||
getList() { | |||
this.loading = true; | |||
stateList(this.queryParams).then(response => { | |||
this.stateList = response.data; | |||
this.total = this.stateList.length; | |||
}).finally(() => this.loading = false ); | |||
}, | |||
// 取消按钮 | |||
cancel() { | |||
this.open = false; | |||
this.viewOpen = false; | |||
this.reset(); | |||
}, | |||
// 表单重置 | |||
reset() { | |||
this.form = { | |||
}; | |||
}, | |||
refresh() { | |||
this.getStateMachine(); | |||
this.getList(); | |||
}, | |||
/** 搜索按钮操作 */ | |||
handleQuery() { | |||
this.queryParams.pageNum = 1; | |||
this.getList(); | |||
}, | |||
/** 重置按钮操作 */ | |||
resetQuery() { | |||
this.resetForm("queryForm"); | |||
this.handleQuery(); | |||
}, | |||
// 多选框选中数据 | |||
handleSelectionChange(selection) { | |||
this.ids = selection.map(item => item.id) | |||
this.single = selection.length!==1 | |||
this.multiple = !selection.length | |||
}, | |||
/** 查看按钮操作 */ | |||
handleLook(row) { | |||
this.projectToken = row.token; | |||
this.viewOpen = true; | |||
}, | |||
closeProjectState() { | |||
this.viewOpen = false; | |||
this.projectToken = null; | |||
}, | |||
gc() { | |||
gc().then((resp) => { | |||
this.$message.success('成功'); | |||
}); | |||
}, | |||
getStateMachine() { | |||
this.state = {}; | |||
stateMachine().then((resp) => { | |||
this.state = resp.data; | |||
}); | |||
}, | |||
dump() { | |||
dump().then((resp) => { | |||
this.$message.success('成功'); | |||
}); | |||
}, | |||
}, | |||
}; | |||
</script> |
@@ -200,7 +200,7 @@ | |||
width="120" | |||
class-name="small-padding fixed-width" | |||
> | |||
<template slot-scope="scope" v-if="scope.row.userId !== 1"> | |||
<template slot-scope="scope" v-if="scope.row.userId !== 1 || isAdmin"> | |||
<el-button | |||
size="mini" | |||
type="text" | |||
@@ -402,6 +402,7 @@ import { getToken } from "@/utils/auth"; | |||
import Treeselect from "@riophae/vue-treeselect"; | |||
import "@riophae/vue-treeselect/dist/vue-treeselect.css"; | |||
import {listRole} from "@/api/system/role"; | |||
import {user_is_admin} from "@/utils/user"; | |||
export default { | |||
name: "User", | |||
@@ -738,10 +739,8 @@ export default { | |||
}, | |||
}, | |||
computed: { | |||
allowRoleOptions() { | |||
if(!this.roleOptions) | |||
return []; | |||
return this.roleOptions.filter((x) => x.roleKey !== 'farmer'); | |||
isAdmin() { | |||
return user_is_admin(); | |||
}, | |||
}, | |||
}; | |||