新增角色管理,优化服务列表

1.x
tanghc 5 years ago
parent 21792d39b1
commit de85e5aef9
  1. 2
      sop-admin/readme.md
  2. 2
      sop-admin/sop-admin-front/README.md
  3. 2
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/LogApi.java
  4. 126
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/ServiceApi.java
  5. 6
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/param/LogMonitorInstanceAddParam.java
  6. 2
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/RouteServiceInfo.java
  7. 44
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/api/service/result/ServiceInstanceVO.java
  8. 17
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ServiceInfo.java
  9. 26
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/bean/ServiceInstance.java
  10. 36
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/RegistrationService.java
  11. 104
      sop-admin/sop-admin-server/src/main/java/com/gitee/sop/adminserver/service/impl/RegistrationServiceEureka.java
  12. 2
      sop-admin/sop-admin-server/src/main/resources/public/index.html
  13. 2
      sop-admin/sop-admin-server/src/main/resources/public/static/css/chunk-009073d4.0af16c7e.css
  14. 2
      sop-admin/sop-admin-server/src/main/resources/public/static/js/app.095e8b9c.js
  15. 2
      sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-009073d4.28312808.js
  16. 1
      sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-2d22c2e3.46f37153.js
  17. 1
      sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-2d22c2e3.4a098244.js
  18. 1
      sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-4a59cbe4.a6360c68.js
  19. 1
      sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-4a59cbe4.b5e74cc4.js
  20. 2
      sop-admin/sop-admin-server/src/main/resources/public/static/js/chunk-6a68a33e.15951b55.js
  21. 2
      sop-admin/sop-admin-vue/src/views/service/limit/index.vue
  22. 2
      sop-admin/sop-admin-vue/src/views/service/limit/index2.vue
  23. 50
      sop-admin/sop-admin-vue/src/views/service/list/index.vue
  24. 15
      sop-admin/sop-admin-vue/src/views/service/log/index.vue
  25. 2
      sop-admin/sop-admin-vue/src/views/service/route/index.vue

@ -1,5 +1,5 @@
# 后台admin # 后台admin
- sop-admin-front: admin前端layui实现(停止维护) - sop-admin-front: admin前端layui实现(停止维护,改用sop-admin-vue)
- sop-admin-server: admin服务端 - sop-admin-server: admin服务端
- sop-admin-vue: admin前端vue实现 - sop-admin-vue: admin前端vue实现

@ -1,4 +1,4 @@
# admin前端页面(停止维护) # admin前端页面(停止维护,改用sop-admin-vue)
做到前后端分离。 做到前后端分离。

@ -114,7 +114,7 @@ public class LogApi {
@Api(name = "monitor.instance.add") @Api(name = "monitor.instance.add")
@ApiDocMethod(description = "添加监控实例") @ApiDocMethod(description = "添加监控实例")
void addServiceInstance(LogMonitorInstanceAddParam param) { void addServiceInstance(LogMonitorInstanceAddParam param) {
String ipPort = param.getIp() + ":" + param.getPort(); String ipPort = param.getIpPort();
this.checkInstance(ipPort); this.checkInstance(ipPort);
Query query = new Query(); Query query = new Query();

@ -6,33 +6,29 @@ import com.gitee.easyopen.annotation.ApiService;
import com.gitee.easyopen.doc.annotation.ApiDoc; import com.gitee.easyopen.doc.annotation.ApiDoc;
import com.gitee.easyopen.doc.annotation.ApiDocMethod; import com.gitee.easyopen.doc.annotation.ApiDocMethod;
import com.gitee.sop.adminserver.api.service.param.ServiceAddParam; import com.gitee.sop.adminserver.api.service.param.ServiceAddParam;
import com.gitee.sop.adminserver.api.service.param.ServiceInstanceParam;
import com.gitee.sop.adminserver.api.service.param.ServiceSearchParam; import com.gitee.sop.adminserver.api.service.param.ServiceSearchParam;
import com.gitee.sop.adminserver.api.service.result.ServiceInfo; import com.gitee.sop.adminserver.api.service.result.RouteServiceInfo;
import com.gitee.sop.adminserver.api.service.result.ServiceInfoVo; import com.gitee.sop.adminserver.api.service.result.ServiceInfoVo;
import com.gitee.sop.adminserver.bean.EurekaApplication; import com.gitee.sop.adminserver.api.service.result.ServiceInstanceVO;
import com.gitee.sop.adminserver.bean.EurekaApps; import com.gitee.sop.adminserver.bean.ServiceInfo;
import com.gitee.sop.adminserver.bean.EurekaInstance; import com.gitee.sop.adminserver.bean.ServiceInstance;
import com.gitee.sop.adminserver.bean.EurekaUri;
import com.gitee.sop.adminserver.bean.ServiceRouteInfo; import com.gitee.sop.adminserver.bean.ServiceRouteInfo;
import com.gitee.sop.adminserver.bean.ZookeeperContext; import com.gitee.sop.adminserver.bean.ZookeeperContext;
import com.gitee.sop.adminserver.common.BizException; import com.gitee.sop.adminserver.common.BizException;
import com.gitee.sop.adminserver.common.ZookeeperPathExistException; import com.gitee.sop.adminserver.common.ZookeeperPathExistException;
import com.gitee.sop.adminserver.common.ZookeeperPathNotExistException; import com.gitee.sop.adminserver.common.ZookeeperPathNotExistException;
import com.gitee.sop.adminserver.service.RegistrationService;
import com.gitee.sop.adminserver.service.impl.RegistrationServiceEureka;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.curator.framework.recipes.cache.ChildData; import org.apache.curator.framework.recipes.cache.ChildData;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import javax.annotation.PostConstruct; import javax.annotation.Resource;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@ -46,24 +42,19 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
public class ServiceApi { public class ServiceApi {
@Resource(type = RegistrationServiceEureka.class)
private RegistrationService registrationService;
OkHttpClient client = new OkHttpClient(); @Api(name = "zookeeper.service.list")
@ApiDocMethod(description = "zk中的服务列表", elementClass = RouteServiceInfo.class)
@Autowired List<RouteServiceInfo> listServiceInfo(ServiceSearchParam param) {
private Environment environment;
private String eurekaUrl;
@Api(name = "service.list")
@ApiDocMethod(description = "服务列表(旧)", elementClass = ServiceInfo.class)
List<ServiceInfo> listServiceInfo(ServiceSearchParam param) throws Exception {
String routeRootPath = ZookeeperContext.getSopRouteRootPath(); String routeRootPath = ZookeeperContext.getSopRouteRootPath();
List<ChildData> childDataList = ZookeeperContext.getChildrenData(routeRootPath); List<ChildData> childDataList = ZookeeperContext.getChildrenData(routeRootPath);
List<ServiceInfo> serviceInfoList = childDataList.stream() List<RouteServiceInfo> serviceInfoList = childDataList.stream()
.filter(childData -> childData.getData() != null && childData.getData().length > 0) .filter(childData -> childData.getData() != null && childData.getData().length > 0)
.map(childData -> { .map(childData -> {
String serviceNodeData = new String(childData.getData()); String serviceNodeData = new String(childData.getData());
ServiceInfo serviceInfo = JSON.parseObject(serviceNodeData, ServiceInfo.class); RouteServiceInfo serviceInfo = JSON.parseObject(serviceNodeData, RouteServiceInfo.class);
return serviceInfo; return serviceInfo;
}) })
.filter(serviceInfo -> { .filter(serviceInfo -> {
@ -121,39 +112,40 @@ public class ServiceApi {
} }
@Api(name = "service.instance.list") @Api(name = "service.instance.list")
@ApiDocMethod(description = "服务列表", elementClass = ServiceInfoVo.class) @ApiDocMethod(description = "获取注册中心的服务列表", elementClass = ServiceInfoVo.class)
List<ServiceInfoVo> listService(ServiceSearchParam param) throws Exception { List<ServiceInstanceVO> listService(ServiceSearchParam param) {
String json = this.requestEurekaServer(EurekaUri.QUERY_APPS); List<ServiceInfo> serviceInfos;
EurekaApps eurekaApps = JSON.parseObject(json, EurekaApps.class); try {
serviceInfos = registrationService.listAllService(1, 99999/* 获取所有实例 */);
List<ServiceInfoVo> serviceInfoVoList = new ArrayList<>(); } catch (Exception e) {
List<EurekaApplication> applicationList = eurekaApps.getApplications().getApplication(); log.error("获取服务实例失败", e);
return Collections.emptyList();
}
List<ServiceInstanceVO> serviceInfoVoList = new ArrayList<>();
AtomicInteger idGen = new AtomicInteger(1); AtomicInteger idGen = new AtomicInteger(1);
applicationList.stream() serviceInfos.stream()
.filter(eurekaApplication -> { .filter(serviceInfo -> {
if (StringUtils.isBlank(param.getServiceId())) { if (StringUtils.isBlank(param.getServiceId())) {
return true; return true;
} }
return StringUtils.containsIgnoreCase(eurekaApplication.getName(), param.getServiceId()); return StringUtils.containsIgnoreCase(serviceInfo.getServiceId(), param.getServiceId());
}) })
.forEach(eurekaApplication -> { .forEach(serviceInfo -> {
int pid = idGen.getAndIncrement(); int pid = idGen.getAndIncrement();
String name = eurekaApplication.getName(); String serviceId = serviceInfo.getServiceId();
ServiceInfoVo parent = new ServiceInfoVo(); ServiceInstanceVO parent = new ServiceInstanceVO();
parent.setId(pid); parent.setId(pid);
parent.setName(name); parent.setServiceId(serviceId);
parent.setParentId(0); parent.setParentId(0);
serviceInfoVoList.add(parent); serviceInfoVoList.add(parent);
List<EurekaInstance> instanceList = eurekaApplication.getInstance(); List<ServiceInstance> instanceList = serviceInfo.getInstances();
for (EurekaInstance instance : instanceList) { for (ServiceInstance instance : instanceList) {
ServiceInfoVo vo = new ServiceInfoVo(); ServiceInstanceVO instanceVO = new ServiceInstanceVO();
BeanUtils.copyProperties(instance, vo); BeanUtils.copyProperties(instance, instanceVO);
int id = idGen.getAndIncrement(); int id = idGen.getAndIncrement();
vo.setId(id); instanceVO.setId(id);
vo.setName(name); instanceVO.setParentId(pid);
vo.setParentId(pid); serviceInfoVoList.add(instanceVO);
vo.setServerPort(instance.fetchPort());
serviceInfoVoList.add(vo);
} }
}); });
@ -162,38 +154,24 @@ public class ServiceApi {
@Api(name = "service.instance.offline") @Api(name = "service.instance.offline")
@ApiDocMethod(description = "服务下线") @ApiDocMethod(description = "服务下线")
void serviceOffline(ServiceInstanceParam param) throws IOException { void serviceOffline(ServiceInstance param) {
this.requestEurekaServer(EurekaUri.OFFLINE_SERVICE, param.getServiceId(), param.getInstanceId()); try {
registrationService.offlineInstance(param);
} catch (Exception e) {
log.error("下线失败,param:{}", param, e);
throw new BizException("下线失败,请查看日志");
}
} }
@Api(name = "service.instance.online") @Api(name = "service.instance.online")
@ApiDocMethod(description = "服务上线") @ApiDocMethod(description = "服务上线")
void serviceOnline(ServiceInstanceParam param) throws IOException { void serviceOnline(ServiceInstance param) throws IOException {
this.requestEurekaServer(EurekaUri.ONLINE_SERVICE, param.getServiceId(), param.getInstanceId()); try {
} registrationService.onlineInstance(param);
} catch (Exception e) {
private String requestEurekaServer(EurekaUri eurekaUri, String... args) throws IOException { log.error("上线失败,param:{}", param, e);
Request request = eurekaUri.getRequest(this.eurekaUrl, args); throw new BizException("上线失败,请查看日志");
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
log.error("操作失败,url:{}, msg:{}, code:{}", eurekaUri.getUri(args), response.message(), response.code());
throw new BizException("操作失败", String.valueOf(response.code()));
}
}
@PostConstruct
protected void after() {
String eurekaUrls = environment.getProperty("eureka.client.serviceUrl.defaultZone");
if (StringUtils.isBlank(eurekaUrls)) {
throw new BizException("未指定eureka.client.serviceUrl.defaultZone参数");
}
String url = eurekaUrls.split("\\,")[0];
if (url.endsWith("/")) {
url = eurekaUrls.substring(0, eurekaUrls.length() - 1);
} }
this.eurekaUrl = url;
} }
} }

@ -12,8 +12,6 @@ public class LogMonitorInstanceAddParam {
@NotBlank(message = "serviceId不能为空") @NotBlank(message = "serviceId不能为空")
private String serviceId; private String serviceId;
@NotBlank(message = "ip不能为空") @NotBlank(message = "ipPort不能为空")
private String ip; private String ipPort;
private int port;
} }

@ -7,7 +7,7 @@ import lombok.Data;
* @author tanghc * @author tanghc
*/ */
@Data @Data
public class ServiceInfo { public class RouteServiceInfo {
@ApiDocField(description = "serviceId") @ApiDocField(description = "serviceId")
private String serviceId; private String serviceId;

@ -0,0 +1,44 @@
package com.gitee.sop.adminserver.api.service.result;
import com.alibaba.fastjson.annotation.JSONField;
import com.gitee.easyopen.doc.annotation.ApiDocField;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import java.util.Date;
/**
* @author tanghc
*/
@Data
public class ServiceInstanceVO {
@ApiDocField(description = "id")
private Integer id;
@ApiDocField(description = "服务名称(serviceId)")
private String serviceId;
@ApiDocField(description = "instanceId")
private String instanceId;
@ApiDocField(description = "ipPort")
private String ipPort;
@ApiDocField(description = "status,服务状态,UP:已上线,OUT_OF_SERVICE:已下线")
private String status;
@ApiDocField(description = "最后更新时间")
private String lastUpdatedTimestamp;
@ApiDocField(description = "parentId")
private Integer parentId;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
public Date getUpdateTime() {
if (StringUtils.isBlank(lastUpdatedTimestamp)) {
return null;
}
return new Date(Long.valueOf(lastUpdatedTimestamp));
}
}

@ -0,0 +1,17 @@
package com.gitee.sop.adminserver.bean;
import lombok.Data;
import java.util.Collections;
import java.util.List;
/**
* @author tanghc
*/
@Data
public class ServiceInfo {
/** 服务名称 */
private String serviceId;
/** 实例列表 */
private List<ServiceInstance> instances = Collections.emptyList();
}

@ -0,0 +1,26 @@
package com.gitee.sop.adminserver.bean;
import lombok.Data;
@Data
public class ServiceInstance {
/**
* 实例id
*/
private String instanceId;
/**
* 服务名称
*/
private String serviceId;
/**
* IP 端口
*/
private String ipPort;
/**
* 状态1上线2下线
*/
private String status;
}

@ -0,0 +1,36 @@
package com.gitee.sop.adminserver.service;
import com.gitee.sop.adminserver.bean.ServiceInfo;
import com.gitee.sop.adminserver.bean.ServiceInstance;
import java.util.List;
/**
* @author tanghc
*/
public interface RegistrationService {
/**
* 获取所有服务列表
*
* @param pageNo 当前页码
* @param pageSize 分页大小
* @return 返回服务列表
*/
List<ServiceInfo> listAllService(int pageNo, int pageSize) throws Exception;
/**
* 服务上线
*
* @param serviceInstance
*/
void onlineInstance(ServiceInstance serviceInstance) throws Exception;
/**
* 服务下线
*
* @param serviceInstance
*/
void offlineInstance(ServiceInstance serviceInstance) throws Exception;
}

@ -0,0 +1,104 @@
package com.gitee.sop.adminserver.service.impl;
import com.alibaba.fastjson.JSON;
import com.gitee.sop.adminserver.bean.EurekaApplication;
import com.gitee.sop.adminserver.bean.EurekaApps;
import com.gitee.sop.adminserver.bean.EurekaInstance;
import com.gitee.sop.adminserver.bean.EurekaUri;
import com.gitee.sop.adminserver.bean.ServiceInfo;
import com.gitee.sop.adminserver.bean.ServiceInstance;
import com.gitee.sop.adminserver.common.BizException;
import com.gitee.sop.adminserver.service.RegistrationService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* @author tanghc
*/
@Slf4j
@Service
public class RegistrationServiceEureka implements RegistrationService {
OkHttpClient client = new OkHttpClient();
@Autowired
private Environment environment;
private String eurekaUrl;
@Override
public List<ServiceInfo> listAllService(int pageNo, int pageSize) throws Exception {
String json = this.requestEurekaServer(EurekaUri.QUERY_APPS);
EurekaApps eurekaApps = JSON.parseObject(json, EurekaApps.class);
List<ServiceInfo> serviceInfoList = new ArrayList<>();
List<EurekaApplication> applicationList = eurekaApps.getApplications().getApplication();
for (EurekaApplication eurekaApplication : applicationList) {
ServiceInfo serviceInfo = new ServiceInfo();
serviceInfo.setServiceId(eurekaApplication.getName());
List<EurekaInstance> instanceList = eurekaApplication.getInstance();
if (CollectionUtils.isNotEmpty(instanceList)) {
serviceInfo.setInstances(new ArrayList<>(instanceList.size()));
for (EurekaInstance eurekaInstance : instanceList) {
ServiceInstance serviceInstance = new ServiceInstance();
serviceInstance.setInstanceId(eurekaInstance.getInstanceId());
serviceInstance.setServiceId(serviceInfo.getServiceId());
serviceInstance.setIpPort(eurekaInstance.getIpAddr() + ":" + eurekaInstance.fetchPort());
serviceInstance.setStatus(eurekaInstance.getStatus());
serviceInfo.getInstances().add(serviceInstance);
}
}
serviceInfoList.add(serviceInfo);
}
return serviceInfoList;
}
@Override
public void onlineInstance(ServiceInstance serviceInstance) throws Exception {
this.requestEurekaServer(EurekaUri.ONLINE_SERVICE, serviceInstance.getServiceId(), serviceInstance.getInstanceId());
}
@Override
public void offlineInstance(ServiceInstance serviceInstance) throws Exception {
this.requestEurekaServer(EurekaUri.OFFLINE_SERVICE, serviceInstance.getServiceId(), serviceInstance.getInstanceId());
}
private String requestEurekaServer(EurekaUri eurekaUri, String... args) throws IOException {
Request request = eurekaUri.getRequest(this.eurekaUrl, args);
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string();
} else {
log.error("操作失败,url:{}, msg:{}, code:{}", eurekaUri.getUri(args), response.message(), response.code());
throw new BizException("操作失败", String.valueOf(response.code()));
}
}
@PostConstruct
protected void after() {
String eurekaUrls = environment.getProperty("eureka.client.serviceUrl.defaultZone");
if (StringUtils.isBlank(eurekaUrls)) {
throw new BizException("未指定eureka.client.serviceUrl.defaultZone参数");
}
// 取第一个
String url = eurekaUrls.split("\\,")[0];
if (url.endsWith("/")) {
url = eurekaUrls.substring(0, eurekaUrls.length() - 1);
}
this.eurekaUrl = url;
}
}

@ -1 +1 @@
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.4f0872ef.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function t(t){for(var r,c,a=t[0],i=t[1],f=t[2],l=0,d=[];l<a.length;l++)c=a[l],u[c]&&d.push(u[c][0]),u[c]=0;for(r in i)Object.prototype.hasOwnProperty.call(i,r)&&(e[r]=i[r]);h&&h(t);while(d.length)d.shift()();return o.push.apply(o,f||[]),n()}function n(){for(var e,t=0;t<o.length;t++){for(var n=o[t],r=!0,c=1;c<n.length;c++){var a=n[c];0!==u[a]&&(r=!1)}r&&(o.splice(t--,1),e=i(i.s=n[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function a(e){return i.p+"static/js/"+({}[e]||e)+"."+{"chunk-238a81e9":"5955f13d","chunk-25908fca":"e7e4b6d5","chunk-29e7142c":"994a3ac0","chunk-2d2085ef":"a63a74dc","chunk-2d22c2e3":"46f37153","chunk-37401378":"4e39ec9b","chunk-4a59cbe4":"b5e74cc4","chunk-5f00e420":"5e409513","chunk-6a68a33e":"f59ae895","chunk-73b2dcec":"094bb2fa"}[e]+".js"}function i(t){if(r[t])return r[t].exports;var n=r[t]={i:t,l:!1,exports:{}};return e[t].call(n.exports,n,n.exports,i),n.l=!0,n.exports}i.e=function(e){var t=[],n={"chunk-238a81e9":1,"chunk-25908fca":1,"chunk-29e7142c":1,"chunk-37401378":1,"chunk-5f00e420":1,"chunk-6a68a33e":1,"chunk-73b2dcec":1};c[e]?t.push(c[e]):0!==c[e]&&n[e]&&t.push(c[e]=new Promise(function(t,n){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-238a81e9":"e8e2beee","chunk-25908fca":"89ab33e8","chunk-29e7142c":"d10599db","chunk-2d2085ef":"31d6cfe0","chunk-2d22c2e3":"31d6cfe0","chunk-37401378":"a43114f3","chunk-4a59cbe4":"31d6cfe0","chunk-5f00e420":"aeebecd4","chunk-6a68a33e":"3b12267b","chunk-73b2dcec":"99cf6327"}[e]+".css",u=i.p+r,o=document.getElementsByTagName("link"),a=0;a<o.length;a++){var f=o[a],l=f.getAttribute("data-href")||f.getAttribute("href");if("stylesheet"===f.rel&&(l===r||l===u))return t()}var d=document.getElementsByTagName("style");for(a=0;a<d.length;a++){f=d[a],l=f.getAttribute("data-href");if(l===r||l===u)return t()}var h=document.createElement("link");h.rel="stylesheet",h.type="text/css",h.onload=t,h.onerror=function(t){var r=t&&t.target&&t.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],h.parentNode.removeChild(h),n(o)},h.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(h)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)t.push(r[2]);else{var o=new Promise(function(t,n){r=u[e]=[t,n]});t.push(r[2]=o);var f,l=document.createElement("script");l.charset="utf-8",l.timeout=120,i.nc&&l.setAttribute("nonce",i.nc),l.src=a(e),f=function(t){l.onerror=l.onload=null,clearTimeout(d);var n=u[e];if(0!==n){if(n){var r=t&&("load"===t.type?"missing":t.type),c=t&&t.target&&t.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,n[1](o)}u[e]=void 0}};var d=setTimeout(function(){f({type:"timeout",target:l})},12e4);l.onerror=l.onload=f,document.head.appendChild(l)}return Promise.all(t)},i.m=e,i.c=r,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)i.d(n,r,function(t){return e[t]}.bind(null,r));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i.oe=function(e){throw console.error(e),e};var f=window["webpackJsonp"]=window["webpackJsonp"]||[],l=f.push.bind(f);f.push=t,f=f.slice();for(var d=0;d<f.length;d++)t(f[d]);var h=l;n()})([]);</script><script src=static/js/chunk-elementUI.8ebdfbab.js></script><script src=static/js/chunk-libs.9cf9cc40.js></script><script src=static/js/app.61234abc.js></script></body></html> <!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>SOP Admin</title><link href=static/css/chunk-elementUI.81cf475c.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.4f0872ef.css rel=stylesheet></head><body><noscript><strong>We're sorry but SOP Admin doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function t(t){for(var r,c,o=t[0],i=t[1],f=t[2],l=0,d=[];l<o.length;l++)c=o[l],u[c]&&d.push(u[c][0]),u[c]=0;for(r in i)Object.prototype.hasOwnProperty.call(i,r)&&(e[r]=i[r]);h&&h(t);while(d.length)d.shift()();return a.push.apply(a,f||[]),n()}function n(){for(var e,t=0;t<a.length;t++){for(var n=a[t],r=!0,c=1;c<n.length;c++){var o=n[c];0!==u[o]&&(r=!1)}r&&(a.splice(t--,1),e=i(i.s=n[0]))}return e}var r={},c={runtime:0},u={runtime:0},a=[];function o(e){return i.p+"static/js/"+({}[e]||e)+"."+{"chunk-009073d4":"28312808","chunk-238a81e9":"5955f13d","chunk-25908fca":"e7e4b6d5","chunk-29e7142c":"994a3ac0","chunk-2d2085ef":"a63a74dc","chunk-2d22c2e3":"4a098244","chunk-37401378":"4e39ec9b","chunk-4a59cbe4":"a6360c68","chunk-6a68a33e":"15951b55","chunk-73b2dcec":"094bb2fa"}[e]+".js"}function i(t){if(r[t])return r[t].exports;var n=r[t]={i:t,l:!1,exports:{}};return e[t].call(n.exports,n,n.exports,i),n.l=!0,n.exports}i.e=function(e){var t=[],n={"chunk-009073d4":1,"chunk-238a81e9":1,"chunk-25908fca":1,"chunk-29e7142c":1,"chunk-37401378":1,"chunk-6a68a33e":1,"chunk-73b2dcec":1};c[e]?t.push(c[e]):0!==c[e]&&n[e]&&t.push(c[e]=new Promise(function(t,n){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-009073d4":"0af16c7e","chunk-238a81e9":"e8e2beee","chunk-25908fca":"89ab33e8","chunk-29e7142c":"d10599db","chunk-2d2085ef":"31d6cfe0","chunk-2d22c2e3":"31d6cfe0","chunk-37401378":"a43114f3","chunk-4a59cbe4":"31d6cfe0","chunk-6a68a33e":"3b12267b","chunk-73b2dcec":"99cf6327"}[e]+".css",u=i.p+r,a=document.getElementsByTagName("link"),o=0;o<a.length;o++){var f=a[o],l=f.getAttribute("data-href")||f.getAttribute("href");if("stylesheet"===f.rel&&(l===r||l===u))return t()}var d=document.getElementsByTagName("style");for(o=0;o<d.length;o++){f=d[o],l=f.getAttribute("data-href");if(l===r||l===u)return t()}var h=document.createElement("link");h.rel="stylesheet",h.type="text/css",h.onload=t,h.onerror=function(t){var r=t&&t.target&&t.target.src||u,a=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");a.code="CSS_CHUNK_LOAD_FAILED",a.request=r,delete c[e],h.parentNode.removeChild(h),n(a)},h.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(h)}).then(function(){c[e]=0}));var r=u[e];if(0!==r)if(r)t.push(r[2]);else{var a=new Promise(function(t,n){r=u[e]=[t,n]});t.push(r[2]=a);var f,l=document.createElement("script");l.charset="utf-8",l.timeout=120,i.nc&&l.setAttribute("nonce",i.nc),l.src=o(e),f=function(t){l.onerror=l.onload=null,clearTimeout(d);var n=u[e];if(0!==n){if(n){var r=t&&("load"===t.type?"missing":t.type),c=t&&t.target&&t.target.src,a=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");a.type=r,a.request=c,n[1](a)}u[e]=void 0}};var d=setTimeout(function(){f({type:"timeout",target:l})},12e4);l.onerror=l.onload=f,document.head.appendChild(l)}return Promise.all(t)},i.m=e,i.c=r,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)i.d(n,r,function(t){return e[t]}.bind(null,r));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e["default"]}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i.oe=function(e){throw console.error(e),e};var f=window["webpackJsonp"]=window["webpackJsonp"]||[],l=f.push.bind(f);f.push=t,f=f.slice();for(var d=0;d<f.length;d++)t(f[d]);var h=l;n()})([]);</script><script src=static/js/chunk-elementUI.8ebdfbab.js></script><script src=static/js/chunk-libs.9cf9cc40.js></script><script src=static/js/app.095e8b9c.js></script></body></html>

@ -1 +1 @@
.custom-tree-node{-webkit-box-flex:1;-ms-flex:1;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;font-size:14px;padding-right:8px}.el-input.is-disabled .el-input__inner,.el-radio__input.is-disabled+span.el-radio__label{color:#909399}.limit-tip[data-v-0ec28e9a]{cursor:pointer;margin-left:10px} .custom-tree-node{-webkit-box-flex:1;-ms-flex:1;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;font-size:14px;padding-right:8px}.el-input.is-disabled .el-input__inner,.el-radio__input.is-disabled+span.el-radio__label{color:#909399}.limit-tip[data-v-b81bfbde]{cursor:pointer;margin-left:10px}

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d22c2e3"],{f1ac:function(t,e,a){"use strict";a.r(e);var n=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("div",{staticClass:"app-container"},[a("el-form",{staticClass:"demo-form-inline",attrs:{inline:!0,model:t.searchFormData,size:"mini"}},[a("el-form-item",{attrs:{label:"serviceId"}},[a("el-input",{staticStyle:{width:"250px"},attrs:{clearable:!0,placeholder:"serviceId"},model:{value:t.searchFormData.serviceId,callback:function(e){t.$set(t.searchFormData,"serviceId",e)},expression:"searchFormData.serviceId"}})],1),t._v(" "),a("el-form-item",[a("el-button",{attrs:{type:"primary",icon:"el-icon-search"},on:{click:t.onSearchTable}},[t._v("查询")])],1)],1),t._v(" "),a("el-table",{staticStyle:{width:"100%","margin-bottom":"20px"},attrs:{data:t.tableData,border:"","row-key":"id"}},[a("el-table-column",{attrs:{prop:"name",label:"服务名称(serviceId)",width:"200"}}),t._v(" "),a("el-table-column",{attrs:{prop:"instanceId",label:"instanceId",width:"250"}}),t._v(" "),a("el-table-column",{attrs:{prop:"ipAddr",label:"IP地址",width:"150"}}),t._v(" "),a("el-table-column",{attrs:{prop:"serverPort",label:"端口号",width:"100"}}),t._v(" "),a("el-table-column",{attrs:{prop:"status",label:"服务状态",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.parentId>0&&"UP"===e.row.status?a("el-tag",{attrs:{type:"success"}},[t._v("已上线")]):t._e(),t._v(" "),e.row.parentId>0&&"STARTING"===e.row.status?a("el-tag",{attrs:{type:"info"}},[t._v("正在启动")]):t._e(),t._v(" "),e.row.parentId>0&&"UNKNOWN"===e.row.status?a("el-tag",[t._v("未知")]):t._e(),t._v(" "),e.row.parentId>0&&("OUT_OF_SERVICE"===e.row.status||"DOWN"===e.row.status)?a("el-tag",{attrs:{type:"danger"}},[t._v("已下线")]):t._e()]}}])}),t._v(" "),a("el-table-column",{attrs:{prop:"updateTime",label:"最后更新时间",width:"160"}}),t._v(" "),a("el-table-column",{attrs:{label:"操作",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.parentId>0&&"UP"===e.row.status?a("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(a){return t.onOffline(e.row)}}},[t._v("下线")]):t._e(),t._v(" "),e.row.parentId>0&&"OUT_OF_SERVICE"===e.row.status?a("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(a){return t.onOnline(e.row)}}},[t._v("上线")]):t._e()]}}])})],1)],1)},r=[],i=(a("7f7f"),a("ac6a"),{data:function(){return{searchFormData:{serviceId:""},tableData:[]}},created:function(){this.loadTable()},methods:{loadTable:function(){this.post("service.instance.list",this.searchFormData,function(t){this.tableData=this.buildTreeData(t.data)})},buildTreeData:function(t){return t.forEach(function(e){var a=e.parentId;0===a||t.forEach(function(t){if(t.id===a){var n=t.children;n||(n=[]),n.push(e),t.children=n}})}),t=t.filter(function(t){return 0===t.parentId}),t},onSearchTable:function(){this.loadTable()},onOffline:function(t){this.confirm("确定要下线【"+t.name+"】吗?",function(e){var a={serviceId:t.name,instanceId:t.instanceId};this.post("service.instance.offline",a,function(){this.tip("下线成功"),e()})})},onOnline:function(t){this.confirm("确定要上线【"+t.name+"】吗?",function(e){var a={serviceId:t.name,instanceId:t.instanceId};this.post("service.instance.online",a,function(){this.tip("上线成功"),e()})})}}}),s=i,o=a("2877"),l=Object(o["a"])(s,n,r,!1,null,null,null);e["default"]=l.exports}}]);

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d22c2e3"],{f1ac:function(t,e,n){"use strict";n.r(e);var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"app-container"},[n("el-form",{staticClass:"demo-form-inline",attrs:{inline:!0,model:t.searchFormData,size:"mini"}},[n("el-form-item",{attrs:{label:"serviceId"}},[n("el-input",{staticStyle:{width:"250px"},attrs:{clearable:!0,placeholder:"serviceId"},model:{value:t.searchFormData.serviceId,callback:function(e){t.$set(t.searchFormData,"serviceId",e)},expression:"searchFormData.serviceId"}})],1),t._v(" "),n("el-form-item",[n("el-button",{attrs:{type:"primary",icon:"el-icon-search"},on:{click:t.onSearchTable}},[t._v("查询")])],1)],1),t._v(" "),n("el-table",{staticStyle:{width:"100%","margin-bottom":"20px"},attrs:{data:t.tableData,border:"","row-key":"id"}},[n("el-table-column",{attrs:{prop:"serviceId",label:"服务名称",width:"200"},scopedSlots:t._u([{key:"default",fn:function(e){return[n("span",{domProps:{innerHTML:t._s(t.renderServiceName(e.row))}})]}}])}),t._v(" "),n("el-table-column",{attrs:{prop:"ipPort",label:"IP端口",width:"250"}}),t._v(" "),n("el-table-column",{attrs:{prop:"status",label:"服务状态",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.parentId>0&&"UP"===e.row.status?n("el-tag",{attrs:{type:"success"}},[t._v("已上线")]):t._e(),t._v(" "),e.row.parentId>0&&"STARTING"===e.row.status?n("el-tag",{attrs:{type:"info"}},[t._v("正在启动")]):t._e(),t._v(" "),e.row.parentId>0&&"UNKNOWN"===e.row.status?n("el-tag",[t._v("未知")]):t._e(),t._v(" "),e.row.parentId>0&&("OUT_OF_SERVICE"===e.row.status||"DOWN"===e.row.status)?n("el-tag",{attrs:{type:"danger"}},[t._v("已下线")]):t._e()]}}])}),t._v(" "),n("el-table-column",{attrs:{prop:"updateTime",label:"最后更新时间",width:"160"}}),t._v(" "),n("el-table-column",{attrs:{label:"操作",width:"100"},scopedSlots:t._u([{key:"default",fn:function(e){return[e.row.parentId>0&&"UP"===e.row.status?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return t.onOffline(e.row)}}},[t._v("下线")]):t._e(),t._v(" "),e.row.parentId>0&&"OUT_OF_SERVICE"===e.row.status?n("el-button",{attrs:{type:"text",size:"mini"},on:{click:function(n){return t.onOnline(e.row)}}},[t._v("上线")]):t._e()]}}])})],1)],1)},r=[],i=(n("ac6a"),{data:function(){return{searchFormData:{serviceId:""},tableData:[]}},created:function(){this.loadTable()},methods:{loadTable:function(){this.post("service.instance.list",this.searchFormData,function(t){this.tableData=this.buildTreeData(t.data)})},buildTreeData:function(t){return t.forEach(function(e){var n=e.parentId;0===n||t.forEach(function(t){if(t.id===n){var a=t.children;a||(a=[]),a.push(e),t.children=a}})}),t=t.filter(function(t){return 0===t.parentId}),t},onSearchTable:function(){this.loadTable()},onOffline:function(t){this.confirm("确定要下线【"+t.serviceId+"】吗?",function(e){this.post("service.instance.offline",t,function(){this.tip("下线成功"),e()})})},onOnline:function(t){this.confirm("确定要上线【"+t.serviceId+"】吗?",function(e){this.post("service.instance.online",t,function(){this.tip("上线成功"),e()})})},renderServiceName:function(t){var e="";if(t.children&&t.children.length>0){var n=t.children.filter(function(t){return"UP"===t.status}).length;e=" (".concat(n,"/").concat(t.children.length,")")}return t.serviceId+e}}}),o=i,s=n("2877"),l=Object(s["a"])(o,a,r,!1,null,null,null);e["default"]=l.exports}}]);

@ -211,7 +211,7 @@ export default {
methods: { methods: {
// //
loadTree: function() { loadTree: function() {
this.post('service.list', {}, function(resp) { this.post('zookeeper.service.list', {}, function(resp) {
const respData = resp.data const respData = resp.data
this.treeData = this.convertToTreeData(respData, 0) this.treeData = this.convertToTreeData(respData, 0)
}) })

@ -337,7 +337,7 @@ export default {
methods: { methods: {
// //
loadTree: function() { loadTree: function() {
this.post('service.list', {}, function(resp) { this.post('zookeeper.service.list', {}, function(resp) {
const respData = resp.data const respData = resp.data
this.treeData = this.convertToTreeData(respData, 0) this.treeData = this.convertToTreeData(respData, 0)
}) })

@ -15,25 +15,19 @@
row-key="id" row-key="id"
> >
<el-table-column <el-table-column
prop="name" prop="serviceId"
label="服务名称(serviceId)" label="服务名称"
width="200" width="200"
/> >
<template slot-scope="scope">
<span v-html="renderServiceName(scope.row)"></span>
</template>
</el-table-column>
<el-table-column <el-table-column
prop="instanceId" prop="ipPort"
label="instanceId" label="IP端口"
width="250" width="250"
/> />
<el-table-column
prop="ipAddr"
label="IP地址"
width="150"
/>
<el-table-column
prop="serverPort"
label="端口号"
width="100"
/>
<el-table-column <el-table-column
prop="status" prop="status"
label="服务状态" label="服务状态"
@ -110,28 +104,30 @@ export default {
this.loadTable() this.loadTable()
}, },
onOffline: function(row) { onOffline: function(row) {
this.confirm('确定要下线【' + row.name + '】吗?', function(done) { this.confirm('确定要下线【' + row.serviceId + '】吗?', function(done) {
const params = { this.post('service.instance.offline', row, function() {
serviceId: row.name,
instanceId: row.instanceId
}
this.post('service.instance.offline', params, function() {
this.tip('下线成功') this.tip('下线成功')
done() done()
}) })
}) })
}, },
onOnline: function(row) { onOnline: function(row) {
this.confirm('确定要上线【' + row.name + '】吗?', function(done) { this.confirm('确定要上线【' + row.serviceId + '】吗?', function(done) {
const params = { this.post('service.instance.online', row, function() {
serviceId: row.name,
instanceId: row.instanceId
}
this.post('service.instance.online', params, function() {
this.tip('上线成功') this.tip('上线成功')
done() done()
}) })
}) })
},
renderServiceName: function(row) {
let instanceCount = ''
if (row.children && row.children.length > 0) {
const onlineCount = row.children.filter(el => {
return el.status === 'UP'
}).length
instanceCount = ` (${onlineCount}/${row.children.length})`
}
return row.serviceId + instanceCount
} }
} }
} }

@ -85,12 +85,12 @@
<el-option <el-option
v-for="item in serviceData" v-for="item in serviceData"
:key="item.id" :key="item.id"
:label="item.name + '(' + item.ipAddr + ':' + item.serverPort + ')'" :label="item.serviceId + '(' + item.ipPort + ')'"
:value="item" :value="item"
:disabled="isOptionDisabled(item)" :disabled="isOptionDisabled(item)"
> >
<span style="float: left">{{ item.name }} <span v-if="isOptionDisabled(item)">(已添加)</span></span> <span style="float: left">{{ item.serviceId }} <span v-if="isOptionDisabled(item)">(已添加)</span></span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.ipAddr + ':' + item.serverPort }}</span> <span style="float: right; color: #8492a6; font-size: 13px">{{ item.ipPort }}</span>
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
@ -156,7 +156,7 @@ export default {
}) })
}, },
isOptionDisabled: function(item) { isOptionDisabled: function(item) {
const ipPort = item.ipAddr + ':' + item.serverPort const ipPort = item.ipPort
const index = this.addedInstanceList.findIndex((value, index, arr) => { const index = this.addedInstanceList.findIndex((value, index, arr) => {
return value === ipPort return value === ipPort
}) })
@ -218,12 +218,7 @@ export default {
this.$refs['logDialogForm'].validate((valid) => { this.$refs['logDialogForm'].validate((valid) => {
if (valid) { if (valid) {
const instanceData = this.logDialogFormData.instanceData const instanceData = this.logDialogFormData.instanceData
const data = { this.post('monitor.instance.add', instanceData, function(resp) {
serviceId: instanceData.serviceId,
ip: instanceData.ipAddr,
port: instanceData.serverPort
}
this.post('monitor.instance.add', data, function(resp) {
this.logDialogInstanceVisible = false this.logDialogInstanceVisible = false
this.loadTable() this.loadTable()
}) })

@ -343,7 +343,7 @@ export default {
methods: { methods: {
// //
loadTree: function() { loadTree: function() {
this.post('service.list', {}, function(resp) { this.post('zookeeper.service.list', {}, function(resp) {
const respData = resp.data const respData = resp.data
this.treeData = this.convertToTreeData(respData, 0) this.treeData = this.convertToTreeData(respData, 0)
this.$nextTick(() => { this.$nextTick(() => {

Loading…
Cancel
Save