|
|
|
@ -2,13 +2,18 @@ package cn.estsh.i3plus.core.apiservice.controller.base;
|
|
|
|
|
|
|
|
|
|
import cn.estsh.i3plus.core.api.iservice.base.ISynchronizedService;
|
|
|
|
|
import cn.estsh.i3plus.core.api.iservice.base.ISystemInitService;
|
|
|
|
|
import cn.estsh.i3plus.core.api.iservice.base.ISystemLoginService;
|
|
|
|
|
import cn.estsh.i3plus.core.api.iservice.base.ISystemLoginStrategyService;
|
|
|
|
|
import cn.estsh.i3plus.core.api.iservice.busi.*;
|
|
|
|
|
import cn.estsh.i3plus.core.apiservice.controller.busi.PersonnelController;
|
|
|
|
|
import cn.estsh.i3plus.core.apiservice.controller.busi.SysUserInfoController;
|
|
|
|
|
import cn.estsh.i3plus.core.apiservice.util.SysUserPasswordUtil;
|
|
|
|
|
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
|
|
|
|
|
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
|
|
|
|
|
import cn.estsh.i3plus.platform.common.tool.*;
|
|
|
|
|
import cn.estsh.i3plus.platform.common.tool.JsonUtilTool;
|
|
|
|
|
import cn.estsh.i3plus.platform.common.tool.ServletRequestTool;
|
|
|
|
|
import cn.estsh.i3plus.platform.common.tool.StringTool;
|
|
|
|
|
import cn.estsh.i3plus.platform.common.tool.TimeTool;
|
|
|
|
|
import cn.estsh.i3plus.platform.common.util.CommonConstWords;
|
|
|
|
|
import cn.estsh.i3plus.platform.common.util.PlatformConstWords;
|
|
|
|
|
import cn.estsh.i3plus.pojo.base.annotation.AnnoIgnoreLog;
|
|
|
|
@ -16,9 +21,11 @@ import cn.estsh.i3plus.pojo.base.bean.BaseConstWords;
|
|
|
|
|
import cn.estsh.i3plus.pojo.base.bean.BaseThreadLocal;
|
|
|
|
|
import cn.estsh.i3plus.pojo.base.bean.ListPager;
|
|
|
|
|
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
|
|
|
|
|
import cn.estsh.i3plus.pojo.base.enumutil.ImppEnumUtil;
|
|
|
|
|
import cn.estsh.i3plus.pojo.base.enumutil.ResourceEnumUtil;
|
|
|
|
|
import cn.estsh.i3plus.pojo.model.common.CloudPagerModel;
|
|
|
|
|
import cn.estsh.i3plus.pojo.model.license.ImppLicense;
|
|
|
|
|
import cn.estsh.i3plus.pojo.model.platform.SysLoginModel;
|
|
|
|
|
import cn.estsh.i3plus.pojo.model.platform.UserDetailModel;
|
|
|
|
|
import cn.estsh.i3plus.pojo.model.platform.UserDetailPagerModel;
|
|
|
|
|
import cn.estsh.i3plus.pojo.platform.bean.*;
|
|
|
|
@ -28,24 +35,48 @@ import cn.estsh.impp.framework.boot.exception.ImppBusiException;
|
|
|
|
|
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
|
|
|
|
|
import cn.estsh.impp.framework.boot.license.ImppLicenseTool;
|
|
|
|
|
import cn.estsh.impp.framework.boot.license.serviceimpl.ImppLicenseDecoder;
|
|
|
|
|
import cn.estsh.impp.framework.boot.util.*;
|
|
|
|
|
import cn.estsh.impp.framework.boot.util.ImppRedis;
|
|
|
|
|
import cn.estsh.impp.framework.boot.util.LocaleUtils;
|
|
|
|
|
import cn.estsh.impp.framework.boot.util.RedisCacheTool;
|
|
|
|
|
import cn.estsh.impp.framework.boot.util.ResultBean;
|
|
|
|
|
import cn.estsh.impp.framework.boot.util.SpringContextsUtil;
|
|
|
|
|
import cn.estsh.impp.framework.boot.util.ValidatorBean;
|
|
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
import io.swagger.annotations.Api;
|
|
|
|
|
import io.swagger.annotations.ApiOperation;
|
|
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
import org.apache.shiro.authc.*;
|
|
|
|
|
import org.apache.shiro.authc.AuthenticationException;
|
|
|
|
|
import org.apache.shiro.authc.CredentialsException;
|
|
|
|
|
import org.apache.shiro.authc.IncorrectCredentialsException;
|
|
|
|
|
import org.apache.shiro.authc.LockedAccountException;
|
|
|
|
|
import org.apache.shiro.authc.UnknownAccountException;
|
|
|
|
|
import org.slf4j.Logger;
|
|
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
|
import org.springframework.amqp.rabbit.core.RabbitTemplate;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
|
|
|
|
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.PutMapping;
|
|
|
|
|
import org.springframework.web.bind.annotation.RequestBody;
|
|
|
|
|
import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
|
|
import org.springframework.web.bind.annotation.RequestParam;
|
|
|
|
|
import org.springframework.web.bind.annotation.RestController;
|
|
|
|
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
import java.util.Optional;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.function.BiFunction;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
import static cn.estsh.i3plus.platform.common.util.CommonConstWords.DEFAULT_LANGUAGE;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @Description :
|
|
|
|
|
* @Reference :
|
|
|
|
@ -100,6 +131,9 @@ public class WhiteController extends CoreBaseController {
|
|
|
|
|
private ISysConfigService configService;
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private ISystemLoginService loginService;
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
private SysUserPasswordUtil userPasswordUtil;
|
|
|
|
|
|
|
|
|
|
@Resource(name = CommonConstWords.IMPP_REDIS_RES)
|
|
|
|
@ -114,7 +148,6 @@ public class WhiteController extends CoreBaseController {
|
|
|
|
|
@Autowired
|
|
|
|
|
private RabbitTemplate rabbitTemplate;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@GetMapping(value = "/sys-locale-language/list")
|
|
|
|
|
@ApiOperation(value = "查询可用语言", notes = "查询可用语言")
|
|
|
|
|
public ResultBean listSysLocaleLanguage() {
|
|
|
|
@ -140,6 +173,19 @@ public class WhiteController extends CoreBaseController {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@GetMapping(value = "/session-user")
|
|
|
|
|
@ApiOperation(value = "获取用户信息", notes = "获取当前登录用户账号详细信息")
|
|
|
|
|
public ResultBean getSession() {
|
|
|
|
|
LOGGER.info("获取用户信息...lang:{}", AuthUtil.getSessionAttribute("languageCode"));
|
|
|
|
|
try {
|
|
|
|
|
SessionUser sUser = AuthUtil.getSessionUser();
|
|
|
|
|
LOGGER.info("用户:{}", sUser);
|
|
|
|
|
return new ResultBean(true, "", sUser);
|
|
|
|
|
} catch (ImppBusiException e) {
|
|
|
|
|
return new ResultBean(false, e.getErrorDetail() + "-[解决]" + e.getErrorSolution());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
@ -155,97 +201,109 @@ public class WhiteController extends CoreBaseController {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@GetMapping(value = "/auth/login")
|
|
|
|
|
@ApiOperation(value = "登陆", notes = "登陆")
|
|
|
|
|
public ResultBean login(HttpServletRequest request, String loginName, String loginPwd,
|
|
|
|
|
@RequestParam(required = false) String languageCode,
|
|
|
|
|
@RequestParam(required = false) String deviceId) {
|
|
|
|
|
Long startTime = System.currentTimeMillis();
|
|
|
|
|
startMultiService();
|
|
|
|
|
licenseClickService.checkLicenseNumberLogin();
|
|
|
|
|
@GetMapping(value = "/auth/{loginStrategy}/sso-login")
|
|
|
|
|
@ApiOperation(value = "登录", notes = "登录")
|
|
|
|
|
public ResultBean ssoLogin(HttpServletRequest request, @PathVariable(name = "loginStrategy") String loginStrategy) throws NoSuchFieldException {
|
|
|
|
|
String fieldMapping = RedisCacheTool.getSysConfigStrVal(PlatformConstWords.SSO_REQUEST_MAPPING);
|
|
|
|
|
if (StringUtils.isEmpty(fieldMapping)) {
|
|
|
|
|
return ResultBean.fail("请在平台数据库中配置表添加字段映射配置");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOGGER.info("用户登陆 loginName:{} loginPwd:{} languageCode:{}", loginName, loginPwd, languageCode);
|
|
|
|
|
ResultBean result = null;
|
|
|
|
|
CommonEnumUtil.USER_LOGIN_STATUS userLoginStatus = CommonEnumUtil.USER_LOGIN_STATUS.LOGIN_SUCCESS;
|
|
|
|
|
SysLoginModel loginModel = assembleLoginModelByRequest(request, fieldMapping);
|
|
|
|
|
loginModel.setLoginStrategy(loginStrategy);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
ValidatorBean.checkNotNull(languageCode, "语言不能为空");
|
|
|
|
|
// TODO 后期移除,暂时用于避免自动登录后前台没有正确的传输组织代码信息
|
|
|
|
|
if ("null".equals(languageCode)) {
|
|
|
|
|
languageCode = DEFAULT_LANGUAGE;
|
|
|
|
|
ValidatorBean.beginValid(loginModel)
|
|
|
|
|
.notNull("loginStrategy", loginModel.getLoginStrategy())
|
|
|
|
|
.notNull("loginName", loginModel.getLoginName());
|
|
|
|
|
String beanName = ImppEnumUtil.AUTH_LOGIN_STRATEGY.codeOfStrategyName(loginModel.getLoginStrategy());
|
|
|
|
|
ISystemLoginStrategyService loginStrategyService = (ISystemLoginStrategyService) SpringContextsUtil.getBean(beanName);
|
|
|
|
|
|
|
|
|
|
BaseThreadLocal.setData(PlatformConstWords.IS_SSO_LOGIN, true);
|
|
|
|
|
|
|
|
|
|
return loginByStrategy(request, loginModel, loginStrategyService.login());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置语言代码
|
|
|
|
|
BaseThreadLocal.setData(BaseThreadLocal.LANGUAGE_CODE, languageCode);
|
|
|
|
|
private SysLoginModel assembleLoginModelByRequest(HttpServletRequest request, String fieldMapping) {
|
|
|
|
|
JSONObject mappingObject = (JSONObject) JSONObject.parse(fieldMapping);
|
|
|
|
|
|
|
|
|
|
ValidatorBean.checkNotNull(loginName, "用户名不能为空");
|
|
|
|
|
ValidatorBean.checkNotNull(loginPwd, "密码不能为空");
|
|
|
|
|
SysLoginModel loginModel = new SysLoginModel();
|
|
|
|
|
getJsonObjectParameterFromRequest("loginName", request, mappingObject).ifPresent(d -> loginModel.setLoginName(d.toString()));
|
|
|
|
|
getJsonObjectParameterFromRequest("loginPwd", request, mappingObject).ifPresent(d -> loginModel.setLoginPwd(d.toString()));
|
|
|
|
|
getJsonObjectParameterFromRequest("appId", request, mappingObject).ifPresent(d -> loginModel.setAppId(d.toString()));
|
|
|
|
|
getJsonObjectParameterFromRequest("languageCode", request, mappingObject).ifPresent(d -> loginModel.setLanguageCode(d.toString()));
|
|
|
|
|
getJsonObjectParameterFromRequest("deviceId", request, mappingObject).ifPresent(d -> loginModel.setDeviceId(d.toString()));
|
|
|
|
|
|
|
|
|
|
int sessionMode = RedisCacheTool.getSysConfigIntVal(CommonConstWords.CONFIG_SESSION_MODE, CommonConstWords.CONFIG_SESSION_MODE_DEFAULT);
|
|
|
|
|
if (sessionMode != CommonEnumUtil.SESSION_MODE.SEIZE.getValue()) {
|
|
|
|
|
logout();
|
|
|
|
|
return loginModel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SessionUser user = userService.queryUserLogin(loginName.trim(), loginPwd.trim(), languageCode, getLoginPlatform().getValue(), deviceId);
|
|
|
|
|
private Optional<Object> getJsonObjectParameterFromRequest(String key, HttpServletRequest request, JSONObject mappingObject) {
|
|
|
|
|
Object data = request.getParameter(mappingObject.get(key) == null ? "" : mappingObject.get(key).toString());
|
|
|
|
|
return Optional.ofNullable(data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String redisKey = CommonConstWords.USER_LOGIN_ERROR + "_" + user.getUser().getId();
|
|
|
|
|
redisCore.deleteKey(redisKey);
|
|
|
|
|
@GetMapping(value = "/auth/login")
|
|
|
|
|
@ApiOperation(value = "登录", notes = "登录")
|
|
|
|
|
public ResultBean login(HttpServletRequest request, String loginName, String loginPwd,
|
|
|
|
|
@RequestParam(required = false) String languageCode,
|
|
|
|
|
@RequestParam(required = false) String deviceId) {
|
|
|
|
|
SysLoginModel loginModel = SysLoginModel.builder()
|
|
|
|
|
.loginName(loginName)
|
|
|
|
|
.loginPwd(loginPwd)
|
|
|
|
|
.languageCode(languageCode)
|
|
|
|
|
.deviceId(deviceId)
|
|
|
|
|
.loginStrategy(ImppEnumUtil.AUTH_LOGIN_STRATEGY.ACCOUNT.getCode()).build();
|
|
|
|
|
String beanName = ImppEnumUtil.AUTH_LOGIN_STRATEGY.codeOfStrategyName(loginModel.getLoginStrategy());
|
|
|
|
|
ISystemLoginStrategyService loginStrategyService = (ISystemLoginStrategyService) SpringContextsUtil.getBean(beanName);
|
|
|
|
|
|
|
|
|
|
// LOGGER.info("会员登陆:{}",user);
|
|
|
|
|
return loginByStrategy(request, loginModel, loginStrategyService.login());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = new ResultBean(true, AuthUtil.getSession().getId().toString(), AuthUtil.getSessionUser());
|
|
|
|
|
result.setUrl("/");
|
|
|
|
|
|
|
|
|
|
// 记录登录记录
|
|
|
|
|
recordSysUserLog(user.getUser().getUserInfoId(), loginName, CommonEnumUtil.USER_LOGIN_STATUS.LOGIN_SUCCESS.getValue());
|
|
|
|
|
AuthUtil.setOrganize(user.getUser().getOrganize());
|
|
|
|
|
private ResultBean loginByStrategy(HttpServletRequest request, SysLoginModel loginModel, BiFunction<HttpServletRequest, SysLoginModel, ResultBean> loginStrategy) {
|
|
|
|
|
long startTime = System.currentTimeMillis();
|
|
|
|
|
licenseClickService.checkLicenseNumberLogin();
|
|
|
|
|
|
|
|
|
|
LOGGER.info("用户登陆 loginName:{} loginPwd:{} languageCode:{}", loginModel.getLoginName(), loginModel.getLoginPwd(), loginModel.getLanguageCode());
|
|
|
|
|
ResultBean result = null;
|
|
|
|
|
CommonEnumUtil.USER_LOGIN_STATUS userLoginStatus = CommonEnumUtil.USER_LOGIN_STATUS.LOGIN_SUCCESS;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
result = loginStrategy.apply(request, loginModel);
|
|
|
|
|
} catch (IncorrectCredentialsException e) {
|
|
|
|
|
result = ResultBean.fail(ImppExceptionEnum.LOGIN_EXCEPTION_USER_PASSWORD);
|
|
|
|
|
userPasswordUtil.checkLoginErrorNumber(loginName, result, e);
|
|
|
|
|
userPasswordUtil.checkLoginErrorNumber(loginModel.getLoginName(), result, e);
|
|
|
|
|
|
|
|
|
|
userLoginStatus = CommonEnumUtil.USER_LOGIN_STATUS.WRONG_PASSWORD;
|
|
|
|
|
} catch (CredentialsException e) {
|
|
|
|
|
// 用户名或密码错误
|
|
|
|
|
result = ResultBean.fail(ImppExceptionEnum.LOGIN_EXCEPTION_USER_NAME);
|
|
|
|
|
|
|
|
|
|
// 记录登录记录
|
|
|
|
|
userLoginStatus = CommonEnumUtil.USER_LOGIN_STATUS.WRONG_USERNAME_OR_PASSWORD;
|
|
|
|
|
} catch (LockedAccountException e) {
|
|
|
|
|
// 账号已锁定
|
|
|
|
|
result = ResultBean.fail(ImppExceptionEnum.LOGIN_EXCEPTION_USER_LOCKING);
|
|
|
|
|
|
|
|
|
|
// 记录登录记录
|
|
|
|
|
userLoginStatus = CommonEnumUtil.USER_LOGIN_STATUS.USER_LOGIN_LOCKING;
|
|
|
|
|
} catch (UnknownAccountException e) {
|
|
|
|
|
// 用户信息不存在
|
|
|
|
|
result = ResultBean.fail(ImppExceptionEnum.LOGIN_EXCEPTION_USER_INFO_NULL);
|
|
|
|
|
|
|
|
|
|
// 记录登录记录
|
|
|
|
|
userLoginStatus = CommonEnumUtil.USER_LOGIN_STATUS.USER_INFO_NULL;
|
|
|
|
|
} catch (AuthenticationException e) {
|
|
|
|
|
// 系统异常
|
|
|
|
|
result = ResultBean.fail(ImppExceptionEnum.LOGIN_EXCEPTION_USER_PASSWORD.getDescription()).setCode(ImppExceptionEnum.LOGIN_EXCEPTION_USER_PASSWORD.getCode());
|
|
|
|
|
result.setErrorMsg(e.getMessage());
|
|
|
|
|
|
|
|
|
|
// 记录登录记录
|
|
|
|
|
userLoginStatus = CommonEnumUtil.USER_LOGIN_STATUS.SYSTEM_ERROR;
|
|
|
|
|
} catch (ImppBusiException e) {
|
|
|
|
|
result = ResultBean.fail(e);
|
|
|
|
|
|
|
|
|
|
// 记录登录记录
|
|
|
|
|
userLoginStatus = CommonEnumUtil.USER_LOGIN_STATUS.SYSTEM_ERROR;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
result = ResultBean.fail(e.getMessage()).setCode(ImppExceptionEnum.SYSTEM_EXCEPTION.getCode())
|
|
|
|
|
.setErrorMsg(LocaleUtils.getEnumLocaleResDesc(ImppExceptionEnum.SYSTEM_EXCEPTION, ImppExceptionEnum.SYSTEM_EXCEPTION.getDescription()));
|
|
|
|
|
|
|
|
|
|
// 记录登录记录
|
|
|
|
|
userLoginStatus = CommonEnumUtil.USER_LOGIN_STATUS.SYSTEM_ERROR;
|
|
|
|
|
} finally {
|
|
|
|
|
// 记录登录记录
|
|
|
|
|
recordSysUserLog(null, loginName, userLoginStatus.getValue());
|
|
|
|
|
recordSysUserLog(null, loginModel.getLoginName(), userLoginStatus.getValue());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOGGER.info("会员{}登陆登录完成 ,语言:{} , 登录耗时:{}", loginName, BaseThreadLocal.getThreadLanguageCode(), (System.currentTimeMillis() - startTime));
|
|
|
|
|
LOGGER.info("会员{}登陆登录完成 ,语言:{} , 登录耗时:{}", loginModel.getLoginName(), BaseThreadLocal.getThreadLanguageCode(), (System.currentTimeMillis() - startTime));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -493,30 +551,6 @@ public class WhiteController extends CoreBaseController {
|
|
|
|
|
Arrays.asList(CommonEnumUtil.LOG_LOGIN_PLATFORM.values()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取登录平台信息
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
private CommonEnumUtil.LOG_LOGIN_PLATFORM getLoginPlatform() {
|
|
|
|
|
String value = CookieTool.getCookieValue(request, CommonConstWords.SESSION_LOGIN_PLATFORM);
|
|
|
|
|
if (StringUtils.isBlank(value)) {
|
|
|
|
|
value = CommonEnumUtil.LOG_LOGIN_PLATFORM.PC_IMPP_CORE.getValue() + "";
|
|
|
|
|
} else {
|
|
|
|
|
try {
|
|
|
|
|
Integer.parseInt(value);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
throw ImppExceptionBuilder.newInstance()
|
|
|
|
|
.setSystemID(CommonEnumUtil.SOFT_TYPE.CORE.getCode())
|
|
|
|
|
.setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_FORMAT.getCode())
|
|
|
|
|
.setErrorDetail("平台登录标识转换错误")
|
|
|
|
|
.setErrorSolution("请重新操作")
|
|
|
|
|
.build();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CommonEnumUtil.LOG_LOGIN_PLATFORM platform = CommonEnumUtil.LOG_LOGIN_PLATFORM.valueOf(Integer.parseInt(value));
|
|
|
|
|
return platform == null ? CommonEnumUtil.LOG_LOGIN_PLATFORM.PC_IMPP_CORE : platform;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@GetMapping("/sys-organize/list")
|
|
|
|
|
@ApiOperation(value = "获取全部组织", notes = "获取全部组织")
|
|
|
|
|