Browse Source

新增产品信息接口

zhangqiankun 3 years ago
parent
commit
8b73b4630b

+ 137 - 0
saas-account/src/main/java/com/persagy/account/controller/SaasAuthCenterController.java

@@ -0,0 +1,137 @@
+package com.persagy.account.controller;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.collections4.map.HashedMap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.alibaba.fastjson.JSONObject;
+import com.persagy.account.config.ApplicationProperties;
+import com.persagy.account.pojo.vo.thirty.SaasCodeTokenVO;
+import com.persagy.account.pojo.vo.thirty.SaasCodeVO;
+import com.persagy.common.constant.SaasCommonConstant;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.security.util.BouncycastleCipher;
+import com.persagy.security.util.SecureAES;
+
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.crypto.digest.DigestAlgorithm;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 三方授权中心
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021年4月27日 下午3:08:16
+ */
+@RestController
+@Api(tags = "授权管理")
+@RequestMapping(value = "/authCenter", method = RequestMethod.POST)
+public class SaasAuthCenterController {
+	
+	private static final String SAAS_CLIENT_ID_REDIS_KEY = "SAAS_PLATFORM_CLIENT_ID_KEY";
+	
+	@Autowired
+	private ApplicationProperties properties;
+	
+    @Autowired
+    private BouncycastleCipher bouncycastleCipher;
+    
+	@Autowired
+	private RedisTemplate<String, Object> redisTemplate;
+	
+    /**
+     * 申请授权码
+     */
+    @ApiOperation(value = "申请授权码")
+    @RequestMapping(value = "code")
+    public ResponseResult getCode(@RequestBody @Validated SaasCodeVO model) {
+    	// 验证客户端ID是否存在
+    	Boolean member = this.redisTemplate.opsForSet().isMember(SAAS_CLIENT_ID_REDIS_KEY, model.getClientId());
+    	if (!BooleanUtil.isTrue(member)) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0001.getCode(), ResponseCode.A0001.getDesc());
+		}
+    	// 验证是否授权码已存在
+    	String fastSimpleUUID = IdUtil.fastSimpleUUID();
+    	Boolean setIfAbsent = this.redisTemplate.opsForValue().setIfAbsent(model.getClientId() + "_CODE", fastSimpleUUID, 60000L, TimeUnit.MILLISECONDS);
+    	if (!BooleanUtil.isTrue(setIfAbsent)) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0302.getCode(), ResponseCode.A0001.getDesc());
+		}
+    	Map<String, String> code = new HashedMap<String, String>();
+    	code.put("code", fastSimpleUUID);
+    	return ResponseResultUtil.successResult(code);
+    }
+    
+    /**
+     * 根据授权码获取token
+     * @throws UnsupportedEncodingException 
+     */
+    @ApiOperation(value = "根据授权码获取token")
+    @RequestMapping(value = "codeToken")
+    public ResponseResult getCodeToken(@RequestBody @Validated SaasCodeTokenVO model) throws UnsupportedEncodingException {
+    	// 验证客户端ID是否存在
+    	Boolean member = this.redisTemplate.opsForSet().isMember(SAAS_CLIENT_ID_REDIS_KEY, model.getClientId());
+    	if (!BooleanUtil.isTrue(member)) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0001.getCode(), ResponseCode.A0001.getDesc());
+		}
+    	// 验证是否授权码存在
+    	Object object = this.redisTemplate.opsForValue().get(model.getClientId() + "_CODE");
+    	if (object == null) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0311.getCode(), ResponseCode.A0311.getDesc());
+		}
+    	String code = (String) object;
+    	if (!model.getCode().equals(code)) {
+    		return ResponseResultUtil.errorResult(ResponseCode.A0303.getCode(), ResponseCode.A0303.getDesc());
+		}
+    	// 生成token
+    	String key = model.getClientId() + "_TOKEN";
+    	long expire = Long.parseLong(this.properties.getTokenExpire());
+    	String sign = this.bouncycastleCipher.encrypt(this.tokenInfo(model.getClientId(), code), key, DigestAlgorithm.MD5, expire, TimeUnit.MINUTES);
+    	SecureAES aes = new SecureAES(properties.getAesKey(), properties.getAesIv());
+    	String data = aes.encryptAccount(this.tokenAuthInfo(key));
+    	String token = data + SaasCommonConstant.POINT_JOIN_SYMBOL + sign;
+    	Map<String, Object> map = new HashedMap<String, Object>();
+    	map.put("token", token);
+    	map.put("expire", expire);
+    	return ResponseResultUtil.successResult(map);
+    }
+    
+    /**
+     * 
+     * @param loginApp
+     * @return
+     */
+    private JSONObject tokenAuthInfo(String key) {
+		JSONObject object = new JSONObject();
+		object.put(SaasCommonConstant.ACCOUNT_ID, key);
+		return object;
+	}
+    
+    /**
+     * 根据授权码组合token原信息
+     * @param clientId
+     * @param code
+     * @return
+     */
+    private String tokenInfo(String clientId, String code) {
+		JSONObject object = new JSONObject();
+		object.put("clientId", clientId);
+		object.put("date", System.currentTimeMillis());
+		object.put("code", code);
+		return object.toJSONString();
+	}
+    
+}

+ 43 - 3
saas-account/src/main/java/com/persagy/account/controller/SaasLoginController.java

@@ -2,7 +2,9 @@ package com.persagy.account.controller;
 
 import java.io.UnsupportedEncodingException;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
 import javax.servlet.http.HttpServletRequest;
@@ -42,8 +44,10 @@ import com.persagy.security.util.SecureAES;
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.crypto.digest.DigestAlgorithm;
+import cn.hutool.http.HttpUtil;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
 
 /**
  * 登录
@@ -53,7 +57,7 @@ import io.swagger.annotations.ApiOperation;
  * @author zhangqiankun
  * @date 2021-03-13 15:29:50
  */
-
+@Slf4j
 @Api(tags = "账号信息")
 @RestController
 public class SaasLoginController {
@@ -77,7 +81,7 @@ public class SaasLoginController {
 	private RedisTemplate<String, Object> redisTemplate;
 	
     /**
-     * 运维系统账号登录,后续再优化token,目前不支持APP端登录
+     * 运维系统账号登录
      * 
      * @throws UnsupportedEncodingException 
      * @throws NumberFormatException 
@@ -103,7 +107,7 @@ public class SaasLoginController {
     		Date date = new Date();
     		Date validEndTime = account.getValidEndTime();
     		if (date.after(validEndTime)) {
-    			return ResponseResultUtil.errorResult(ResponseCode.A0220.getCode(), "此账号已过有效期,不允许再登录");
+    			return ResponseResultUtil.errorResult(ResponseCode.A0220.getCode(), "此账号已停用");
 			}
 		}
     	// 如果是业务系统账号,集团编码必须存在
@@ -183,6 +187,42 @@ public class SaasLoginController {
     }
     
     /**
+     * 外部账号登录验证
+     * @return
+     */
+    public boolean validExternalAccount(String accountSource) {
+    	if ("201".equals(accountSource)) {
+    		// 获取code
+    		String url = "http://sso4dev.wanda-dev.cn/oauth2/Authorize?state=53f2495d7b435ac571&client_id=GRP999&response_type=code&scope=openid%20profile&redirect_uri=https://develop.persagy.com/saasframe3/login";
+    		Map<String, Object> params = new HashMap<String, Object>();
+    		params.put("code", "code");
+    		params.put("client_id", "client_id");
+    		params.put("client_secret", "client_secret");
+    		params.put("redirect_uri", "redirect_uri");
+    		params.put("grant_type", "authorization_code");
+    		String post = HttpUtil.post(url, params, 60000);
+    		log.info(post);
+    		
+    		// 获取token
+    		url = "http://sso4dev.wanda-dev.cn/oauth2/GetToken";
+    		params = new HashMap<String, Object>();
+    		params.put("code", "code");
+    		params.put("client_id", "client_id");
+    		params.put("client_secret", "client_secret");
+    		params.put("redirect_uri", "redirect_uri");
+    		params.put("grant_type", "authorization_code");
+    		post = HttpUtil.post(url, params, 60000);
+    		log.info(post);
+    		
+    		// 根据token获取用户信息
+    		url = "http://sso4dev.wanda-dev.cn/oauth2/GetUserInfo";
+    		post = HttpUtil.get(url, 60000);
+    		log.info(post);
+		}
+    	return true;
+    }
+    
+    /**
      * 获取此账号的菜单权限树
      * 
      * @param account

+ 74 - 27
saas-account/src/main/java/com/persagy/account/controller/SaasProductController.java

@@ -2,19 +2,26 @@ package com.persagy.account.controller;
 
 import java.util.List;
 
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.google.common.collect.Lists;
-import com.persagy.common.utils.ResponseResult;
-import com.persagy.common.utils.ResponseResultUtil;
 import com.persagy.account.pojo.dto.SaasProduct;
-import com.persagy.account.pojo.dto.SaasProduct.Builder;
+import com.persagy.account.pojo.vo.product.SaasProductCreateVO;
+import com.persagy.account.pojo.vo.product.SaasProductPageVO;
+import com.persagy.account.pojo.vo.product.SaasProductQueryVO;
 import com.persagy.account.service.ISaasProductService;
+import com.persagy.common.enums.ResponseCode;
+import com.persagy.common.utils.ResponseResult;
+import com.persagy.common.utils.ResponseResultUtil;
+import com.persagy.common.utils.StringUtil;
 
 import cn.hutool.core.collection.CollectionUtil;
 import io.swagger.annotations.Api;
@@ -26,39 +33,74 @@ import io.swagger.annotations.ApiOperation;
  * @version 1.0.0
  * @company persagy 
  * @author zhangqiankun
- * @date 2021-04-26 15:45:41
+ * @date 2021-04-27 16:08:25
  */
-
-@Api(tags = "产品信息")
 @RestController
-@RequestMapping(value = "/saasProduct", method = RequestMethod.POST)
+@Api(tags = "产品信息")
+@SuppressWarnings("unchecked")
+@RequestMapping(value = "/product", method = RequestMethod.POST)
 public class SaasProductController {
     @Autowired
     private ISaasProductService saasProductService;
     
     /**
-     * 列表查询
+     * 查询产品信息
      */
-    @ApiOperation(value = "列表查询")
+	@ApiOperation(value = "查询产品信息")
     @RequestMapping(value = "querySaasProductList")
-    public ResponseResult querySaasProductList(@RequestBody SaasProduct saasProduct) {
-    	Builder builder = new SaasProduct.Builder().createQueryWrapper();
-    	LambdaQueryWrapper<SaasProduct> queryWrapper = builder.builderQueryWrapper();
+    public ResponseResult querySaasProductList(@RequestBody @Validated SaasProductQueryVO model) {
+    	LambdaQueryWrapper<SaasProduct> queryWrapper = new SaasProduct.BuilderQueryWrapper()
+    			.productCodeEq(model.getProductCode()).productNameLike(model.getProductName())
+    			.productStateEq(model.getProductState()).productMenuEq(model.getProductMenu())
+    			.updateUserEq(model.getUpdateUser()).builder();
+    	queryWrapper.orderByDesc(SaasProduct::getUpdateTime, SaasProduct::getId);		// 默认更新时间降序
     	List<SaasProduct> list = this.saasProductService.list(queryWrapper);
     	if (CollectionUtil.isEmpty(list)) {
 			return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
 		}
         return ResponseResultUtil.successResult(list, (long)list.size());
     }
+	
+    /**
+     * 分页查询产品信息
+     */
+    @ApiOperation(value = "分页查询产品信息")
+    @RequestMapping(value = "queryProductPageList")
+    public ResponseResult queryProductPageList(@RequestBody @Validated SaasProductPageVO pageVO) {
+    	Page<SaasProduct> page = new Page<SaasProduct>(pageVO.getPage(), pageVO.getSize());
+    	LambdaQueryWrapper<SaasProduct> queryWrapper = new SaasProduct.BuilderQueryWrapper()
+    			.productCodeEq(pageVO.getProductCode()).productNameLike(pageVO.getProductName())
+    			.productStateEq(pageVO.getProductState()).productMenuEq(pageVO.getProductMenu())
+    			.updateUserEq(pageVO.getUpdateUser()).builder();
+    	queryWrapper.orderByDesc(SaasProduct::getUpdateTime, SaasProduct::getId);		// 默认更新时间降序
+    	Page<SaasProduct> pageList = this.saasProductService.page(page, queryWrapper);
+    	if (pageList == null || CollectionUtil.isEmpty(pageList.getRecords())) {
+    		return ResponseResultUtil.successResult(Lists.newArrayList(), 0L);
+		}
+    	return ResponseResultUtil.successResult(pageList.getRecords(), pageList.getTotal());
+    }
 
     /**
      * 新增
      */
 	@ApiOperation(value = "保存")
 	@RequestMapping(value = "createSaasProduct")
-    public ResponseResult createSaasProduct(@RequestBody SaasProduct saasProduct) {
-        boolean result = this.saasProductService.save(saasProduct);
-        return result ? ResponseResultUtil.successResult("保存成功") : ResponseResultUtil.errorResult("保存失败");
+    public ResponseResult createSaasProduct(@RequestBody @Validated SaasProductCreateVO model) {
+		// 验证产品名称、产品编码的唯一性
+		boolean result = this.saasProductService.validProductCode(model.getProductCode(), null);
+		if (!result) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "产品编码已存在");
+		}
+		result = this.saasProductService.validProductName(model.getProductName(), null);
+		if (!result) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "产品名称已存在");
+		}
+		SaasProduct saasProduct = new SaasProduct();
+		BeanUtils.copyProperties(model, saasProduct);
+		saasProduct.setUpdateUser(model.getAccountId());
+		saasProduct.setId(null);
+        result = this.saasProductService.save(saasProduct);
+        return result ? ResponseResultUtil.successResult("保存成功", saasProduct.getId()) : ResponseResultUtil.errorResult("保存失败");
     }
     
     /**
@@ -66,19 +108,24 @@ public class SaasProductController {
      */
 	@ApiOperation(value = "更新")
 	@RequestMapping(value = "updateSaasProduct")
-    public ResponseResult updateSaasProduct(@RequestBody SaasProduct saasProduct) {
-        boolean result = this.saasProductService.updateById(saasProduct);
+    public ResponseResult updateSaasProduct(@RequestBody @Validated SaasProductCreateVO model) {
+		if (StringUtil.isBlank(model.getId())) {
+			return ResponseResultUtil.errorResult(ResponseCode.A0400.getCode(), "产品ID,不可为空"); 
+		}
+		// 验证产品名称、产品编码的唯一性
+		boolean result = this.saasProductService.validProductCode(model.getProductCode(), model.getId());
+		if (!result) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "产品编码已存在");
+		}
+		result = this.saasProductService.validProductName(model.getProductName(), model.getId());
+		if (!result) {
+			return ResponseResultUtil.errorResult(ResponseCode.C0341.getCode(), "产品名称已存在");
+		}
+		SaasProduct saasProduct = new SaasProduct();
+		BeanUtils.copyProperties(model, saasProduct);
+		saasProduct.setUpdateUser(model.getAccountId());
+        result = this.saasProductService.updateById(saasProduct);
         return result ? ResponseResultUtil.successResult("更新成功") : ResponseResultUtil.errorResult("更新失败");
     }
 
-    /**
-     * 物理删除
-     */
-    @ApiOperation(value = "删除")
-    @RequestMapping(value = "deleteSaasProduct")
-    public ResponseResult deleteSaasProduct(@RequestBody SaasProduct saasProduct) {
-        boolean result = this.saasProductService.removeById(saasProduct.getId());
-        return result ? ResponseResultUtil.successResult("删除成功") : ResponseResultUtil.errorResult("删除失败");
-    }
-    
 }

+ 1 - 1
saas-account/src/main/java/com/persagy/account/mapper/SaasProductMapper.java

@@ -11,7 +11,7 @@ import com.persagy.account.pojo.dto.SaasProduct;
  * @version 1.0.0
  * @company persagy 
  * @author zhangqiankun
- * @date 2021-04-26 15:45:41
+ * @date 2021-04-27 16:08:25
  */
 @Mapper
 public interface SaasProductMapper extends BaseMapper<SaasProduct> {

+ 110 - 76
saas-account/src/main/java/com/persagy/account/pojo/dto/SaasProduct.java

@@ -2,6 +2,7 @@ package com.persagy.account.pojo.dto;
 
 import java.util.Date;
 
+import com.baomidou.mybatisplus.annotation.FieldFill;
 import com.baomidou.mybatisplus.annotation.FieldStrategy;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
@@ -23,7 +24,7 @@ import lombok.ToString;
  * @version 1.0.0
  * @company persagy
  * @author zhangqiankun
- * @date 2021-04-26 15:45:41
+ * @date 2021-04-27 16:08:25
  */
 @Getter
 @Setter
@@ -49,150 +50,183 @@ public class SaasProduct extends BaseEntity<SaasProduct> {
 	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
 	private String productMenu; // 产品是否关联菜单,0-未关联,1-已关联
 
-	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	@TableField(fill = FieldFill.INSERT, updateStrategy = FieldStrategy.NOT_EMPTY)
 	private Date createTime; // 创建时间
 
-	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+	@TableField(fill = FieldFill.INSERT_UPDATE, updateStrategy = FieldStrategy.NOT_EMPTY)
 	private Date updateTime; // 更新时间
 
 	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
 	private String updateUser; // 最后一次操作者ID
 
 	@TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
-	private String remark; // 备注
+	private String remark; 		// 备注
+
+	public static class BuilderQueryWrapper {
+
+		private LambdaQueryWrapper<SaasProduct> queryWrapper = new LambdaQueryWrapper<SaasProduct>();
 
-	public static class Builder {
+		public BuilderQueryWrapper idEq(String id) {
+			if (StringUtil.isNotBlank(id)) {
+				queryWrapper.eq(SaasProduct::getId, id);
+			}
+			return this;
+		}
 
-		private LambdaQueryWrapper<SaasProduct> queryWrapper = null;
+		public BuilderQueryWrapper productCodeEq(String productCode) {
+			if (StringUtil.isNotBlank(productCode)) {
+				queryWrapper.eq(SaasProduct::getProductCode, productCode);
+			}
+			return this;
+		}
+
+		public BuilderQueryWrapper productNameEq(String productName) {
+			if (StringUtil.isNotBlank(productName)) {
+				queryWrapper.eq(SaasProduct::getProductName, productName);
+			}
+			return this;
+		}
+		
+		public BuilderQueryWrapper productNameLike(String productName) {
+			if (StringUtil.isNotBlank(productName)) {
+				queryWrapper.like(SaasProduct::getProductName, productName);
+			}
+			return this;
+		}
 
-		private LambdaUpdateWrapper<SaasProduct> updateWrapper = null;
+		public BuilderQueryWrapper productIconEq(String productIcon) {
+			if (StringUtil.isNotBlank(productIcon)) {
+				queryWrapper.eq(SaasProduct::getProductIcon, productIcon);
+			}
+			return this;
+		}
 
-		public Builder createQueryWrapper() {
-			queryWrapper = new LambdaQueryWrapper<SaasProduct>();
+		public BuilderQueryWrapper productStateEq(String productState) {
+			if (StringUtil.isNotBlank(productState)) {
+				queryWrapper.eq(SaasProduct::getProductState, productState);
+			}
 			return this;
 		}
 
-		public Builder createUpdateWrapper() {
-			updateWrapper = new LambdaUpdateWrapper<SaasProduct>();
+		public BuilderQueryWrapper productMenuEq(String productMenu) {
+			if (StringUtil.isNotBlank(productMenu)) {
+				queryWrapper.eq(SaasProduct::getProductMenu, productMenu);
+			}
 			return this;
 		}
 
-		public Builder idEq(String id) {
+		public BuilderQueryWrapper createTimeEq(Date createTime) {
+			if (null != createTime) {
+				queryWrapper.eq(SaasProduct::getCreateTime, createTime);
+			}
+			return this;
+		}
+
+		public BuilderQueryWrapper updateTimeEq(Date updateTime) {
+			if (null != updateTime) {
+				queryWrapper.eq(SaasProduct::getUpdateTime, updateTime);
+			}
+			return this;
+		}
+
+		public BuilderQueryWrapper updateUserEq(String updateUser) {
+			if (StringUtil.isNotBlank(updateUser)) {
+				queryWrapper.eq(SaasProduct::getUpdateUser, updateUser);
+			}
+			return this;
+		}
+
+		public BuilderQueryWrapper remarkEq(String remark) {
+			if (StringUtil.isNotBlank(remark)) {
+				queryWrapper.eq(SaasProduct::getRemark, remark);
+			}
+			return this;
+		}
+
+		public LambdaQueryWrapper<SaasProduct> builder() {
+			return queryWrapper;
+		}
+
+	}
+
+	public static class BuilderUpdateWrapper {
+
+		private LambdaUpdateWrapper<SaasProduct> updateWrapper = new LambdaUpdateWrapper<SaasProduct>();
+
+		public BuilderUpdateWrapper idEq(String id) {
 			if (StringUtil.isNotBlank(id)) {
-				if (updateWrapper != null) {
-					updateWrapper.eq(SaasProduct::getId, id);
-				} else {
-					queryWrapper.eq(SaasProduct::getId, id);
-				}
+				updateWrapper.eq(SaasProduct::getId, id);
 			}
 			return this;
 		}
 
-		public Builder productCodeEq(String productCode) {
+		public BuilderUpdateWrapper productCodeEq(String productCode) {
 			if (StringUtil.isNotBlank(productCode)) {
-				if (updateWrapper != null) {
-					updateWrapper.eq(SaasProduct::getProductCode, productCode);
-				} else {
-					queryWrapper.eq(SaasProduct::getProductCode, productCode);
-				}
+				updateWrapper.eq(SaasProduct::getProductCode, productCode);
 			}
 			return this;
 		}
 
-		public Builder productNameEq(String productName) {
+		public BuilderUpdateWrapper productNameEq(String productName) {
 			if (StringUtil.isNotBlank(productName)) {
-				if (updateWrapper != null) {
-					updateWrapper.eq(SaasProduct::getProductName, productName);
-				} else {
-					queryWrapper.eq(SaasProduct::getProductName, productName);
-				}
+				updateWrapper.eq(SaasProduct::getProductName, productName);
 			}
 			return this;
 		}
 
-		public Builder productIconEq(String productIcon) {
+		public BuilderUpdateWrapper productIconEq(String productIcon) {
 			if (StringUtil.isNotBlank(productIcon)) {
-				if (updateWrapper != null) {
-					updateWrapper.eq(SaasProduct::getProductIcon, productIcon);
-				} else {
-					queryWrapper.eq(SaasProduct::getProductIcon, productIcon);
-				}
+				updateWrapper.eq(SaasProduct::getProductIcon, productIcon);
 			}
 			return this;
 		}
 
-		public Builder productStateEq(String productState) {
+		public BuilderUpdateWrapper productStateEq(String productState) {
 			if (StringUtil.isNotBlank(productState)) {
-				if (updateWrapper != null) {
-					updateWrapper.eq(SaasProduct::getProductState, productState);
-				} else {
-					queryWrapper.eq(SaasProduct::getProductState, productState);
-				}
+				updateWrapper.eq(SaasProduct::getProductState, productState);
 			}
 			return this;
 		}
 
-		public Builder productMenuEq(String productMenu) {
+		public BuilderUpdateWrapper productMenuEq(String productMenu) {
 			if (StringUtil.isNotBlank(productMenu)) {
-				if (updateWrapper != null) {
-					updateWrapper.eq(SaasProduct::getProductMenu, productMenu);
-				} else {
-					queryWrapper.eq(SaasProduct::getProductMenu, productMenu);
-				}
+				updateWrapper.eq(SaasProduct::getProductMenu, productMenu);
 			}
 			return this;
 		}
 
-		public Builder createTimeEq(Date createTime) {
+		public BuilderUpdateWrapper createTimeEq(Date createTime) {
 			if (null != createTime) {
-				if (updateWrapper != null) {
-					updateWrapper.eq(SaasProduct::getCreateTime, createTime);
-				} else {
-					queryWrapper.eq(SaasProduct::getCreateTime, createTime);
-				}
+				updateWrapper.eq(SaasProduct::getCreateTime, createTime);
 			}
 			return this;
 		}
 
-		public Builder updateTimeEq(Date updateTime) {
+		public BuilderUpdateWrapper updateTimeEq(Date updateTime) {
 			if (null != updateTime) {
-				if (updateWrapper != null) {
-					updateWrapper.eq(SaasProduct::getUpdateTime, updateTime);
-				} else {
-					queryWrapper.eq(SaasProduct::getUpdateTime, updateTime);
-				}
+				updateWrapper.eq(SaasProduct::getUpdateTime, updateTime);
 			}
 			return this;
 		}
 
-		public Builder updateUserEq(String updateUser) {
+		public BuilderUpdateWrapper updateUserEq(String updateUser) {
 			if (StringUtil.isNotBlank(updateUser)) {
-				if (updateWrapper != null) {
-					updateWrapper.eq(SaasProduct::getUpdateUser, updateUser);
-				} else {
-					queryWrapper.eq(SaasProduct::getUpdateUser, updateUser);
-				}
+				updateWrapper.eq(SaasProduct::getUpdateUser, updateUser);
 			}
 			return this;
 		}
 
-		public Builder remarkEq(String remark) {
+		public BuilderUpdateWrapper remarkEq(String remark) {
 			if (StringUtil.isNotBlank(remark)) {
-				if (updateWrapper != null) {
-					updateWrapper.eq(SaasProduct::getRemark, remark);
-				} else {
-					queryWrapper.eq(SaasProduct::getRemark, remark);
-				}
+				updateWrapper.eq(SaasProduct::getRemark, remark);
 			}
 			return this;
 		}
 
-		public LambdaQueryWrapper<SaasProduct> builderQueryWrapper() {
-			return queryWrapper;
-		}
-
-		public LambdaUpdateWrapper<SaasProduct> builderUpdateWrapper() {
+		public LambdaUpdateWrapper<SaasProduct> builder() {
 			return updateWrapper;
 		}
+	
 	}
+	
 }

+ 52 - 0
saas-account/src/main/java/com/persagy/account/pojo/vo/product/SaasProductCreateVO.java

@@ -0,0 +1,52 @@
+package com.persagy.account.pojo.vo.product;
+
+import javax.validation.constraints.NotBlank;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 产品信息查询
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021年4月27日 下午5:03:53
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasProductCreateVO extends BaseUserModel {
+	
+	@ApiModelProperty(value = "产品ID,更新时不可为空", example = "1001")
+	private String id; 		// 产品id
+
+	@NotBlank(message = "产品编码,不可为空")
+	@ApiModelProperty(value = "产品编码", required = true, example = "1001")
+	private String productCode; // 产品编码
+
+	@NotBlank(message = "产品编码,不可为空")
+	@ApiModelProperty(value = "产品名称", required = true, example = "chanpin")
+	private String productName; // 产品名称
+
+	@NotBlank(message = "产品图标,不可为空")
+	@ApiModelProperty(value = "产品图标", required = true, example = "chanpin")
+	private String productIcon; // 产品图标
+	
+	@NotBlank(message = "产品编码,不可为空")
+	@ApiModelProperty(value = "产品状态,0-建设中,1-已完成,2-已关联", required = true, example = "0")
+	private String productState; // 产品状态,0-建设中,1-已完成,2-已关联
+
+	@NotBlank(message = "产品编码,不可为空")
+	@ApiModelProperty(value = "产品是否关联菜单,0-未关联,1-已关联", required = true, example = "0")
+	private String productMenu; // 产品是否关联菜单,0-未关联,1-已关联
+
+	@ApiModelProperty(value = "备注", example = "测试")
+	private String remark; 		// 备注
+
+}

+ 36 - 0
saas-account/src/main/java/com/persagy/account/pojo/vo/product/SaasProductPageVO.java

@@ -0,0 +1,36 @@
+package com.persagy.account.pojo.vo.product;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 项目信息
+ * 
+ * @version 1.0.0
+ * @company persagy
+ * @author zhangqiankun
+ * @date 2021-03-13 15:29:50
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasProductPageVO extends SaasProductQueryVO {
+
+	@Min(value = 1, message = "分页页码,不可低于1")
+	@NotNull(message = "分页页码,不可为空")
+	@ApiModelProperty(value = "分页页码", example = "1", required = true)
+	private Integer page;
+
+	@Min(value = 1, message = "分页大小,不可低于1")
+	@NotNull(message = "分页大小,不可为空")
+	@ApiModelProperty(value = "分页大小", example = "10", required = true)
+	private Integer size;
+
+}

+ 39 - 0
saas-account/src/main/java/com/persagy/account/pojo/vo/product/SaasProductQueryVO.java

@@ -0,0 +1,39 @@
+package com.persagy.account.pojo.vo.product;
+
+import com.persagy.common.model.BaseUserModel;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 产品信息查询
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021年4月27日 下午5:03:53
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasProductQueryVO extends BaseUserModel {
+
+	@ApiModelProperty(value = "产品编码", example = "1001")
+	private String productCode; // 产品编码
+
+	@ApiModelProperty(value = "产品名称,模糊查询", example = "chanpin")
+	private String productName; // 产品名称
+
+	@ApiModelProperty(value = "产品状态,0-建设中,1-已完成,2-已关联", example = "0")
+	private String productState; // 产品状态,0-建设中,1-已完成,2-已关联
+
+	@ApiModelProperty(value = "产品是否关联菜单,0-未关联,1-已关联", example = "0")
+	private String productMenu; // 产品是否关联菜单,0-未关联,1-已关联
+
+	@ApiModelProperty(value = "最后一次操作者ID", example = "RC")
+	private String updateUser; // 最后一次操作者ID
+
+}

+ 33 - 0
saas-account/src/main/java/com/persagy/account/pojo/vo/thirty/SaasCodeTokenVO.java

@@ -0,0 +1,33 @@
+package com.persagy.account.pojo.vo.thirty;
+
+import javax.validation.constraints.NotBlank;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 申请授权码
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021年4月27日 下午3:12:45
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasCodeTokenVO {
+	
+	@NotBlank(message = "客户端ID,不可为空")
+	@ApiModelProperty(value = "客户端ID", required = true, example = "13546545")
+	private String clientId; 	// 客户端ID
+	
+	@NotBlank(message = "授权码,不可为空")
+	@ApiModelProperty(value = "授权码", required = true, example = "13546545")
+	private String code; 	// 授权码
+	
+}

+ 29 - 0
saas-account/src/main/java/com/persagy/account/pojo/vo/thirty/SaasCodeVO.java

@@ -0,0 +1,29 @@
+package com.persagy.account.pojo.vo.thirty;
+
+import javax.validation.constraints.NotBlank;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+
+/**
+ * 申请授权码
+ * 
+ * @version 1.0.0
+ * @company persagy 
+ * @author zhangqiankun
+ * @date 2021年4月27日 下午3:12:45
+ */
+@Getter
+@Setter
+@ApiModel
+@ToString
+public class SaasCodeVO {
+	
+	@NotBlank(message = "客户端ID,不可为空")
+	@ApiModelProperty(value = "客户端ID", required = true, example = "13546545")
+	private String clientId; 	// 客户端ID
+	
+}

+ 17 - 1
saas-account/src/main/java/com/persagy/account/service/ISaasProductService.java

@@ -9,9 +9,25 @@ import com.persagy.account.pojo.dto.SaasProduct;
  * @version 1.0.0
  * @company persagy 
  * @author zhangqiankun
- * @date 2021-04-26 15:45:41
+ * @date 2021-04-27 16:08:25
  */
 public interface ISaasProductService extends ISuperService<SaasProduct> {
 
+	/**
+	 * 验证产品编码的唯一性
+	 * 
+	 * @param productCode
+	 * @param id
+	 */
+	boolean validProductCode(String productCode, String id);
+	
+	/**
+	 * 验证产品名称的唯一性
+	 * 
+	 * @param productName
+	 * @param id
+	 */
+	boolean validProductName(String productName, String id);
+
 }
 

+ 29 - 1
saas-account/src/main/java/com/persagy/account/service/impl/SaasProductServiceImpl.java

@@ -3,6 +3,8 @@ package com.persagy.account.service.impl;
 import org.springframework.stereotype.Service;
 
 import com.persagy.common.service.impl.SuperServiceImpl;
+import com.persagy.common.utils.StringUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.persagy.account.mapper.SaasProductMapper;
 import com.persagy.account.pojo.dto.SaasProduct;
 import com.persagy.account.service.ISaasProductService;
@@ -13,9 +15,35 @@ import com.persagy.account.service.ISaasProductService;
  * @version 1.0.0
  * @company persagy 
  * @author zhangqiankun
- * @date 2021-04-26 15:45:41
+ * @date 2021-04-27 16:08:25
  */
 @Service
 public class SaasProductServiceImpl extends SuperServiceImpl<SaasProductMapper, SaasProduct> implements ISaasProductService {
 
+	@Override
+	public boolean validProductCode(String productCode, String id) {
+		LambdaQueryWrapper<SaasProduct> queryWrapper = new SaasProduct.BuilderQueryWrapper().productCodeEq(productCode).builder();
+		SaasProduct selectOne = this.baseMapper.selectOne(queryWrapper);
+		if (selectOne == null) {
+			return true;
+		}
+		if (StringUtil.isNotBlank(id) && selectOne.getId().equals(id)) {
+			return true;
+		}
+		return false;
+	}
+
+	@Override
+	public boolean validProductName(String productName, String id) {
+		LambdaQueryWrapper<SaasProduct> queryWrapper = new SaasProduct.BuilderQueryWrapper().productNameEq(productName).builder();
+		SaasProduct selectOne = this.baseMapper.selectOne(queryWrapper);
+		if (selectOne == null) {
+			return true;
+		}
+		if (StringUtil.isNotBlank(id) && selectOne.getId().equals(id)) {
+			return true;
+		}
+		return false;
+	}
+
 }

+ 2 - 1
saas-account/src/main/resources/mapper/SaasProductMapper.xml

@@ -2,6 +2,7 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 
 <mapper namespace="com.persagy.account.mapper.SaasProductMapper">
+    
 	<resultMap id="BaseResultMap" type="com.persagy.account.pojo.dto.SaasProduct">
 		<result column="ID" property="id" jdbcType="VARCHAR" />
 		<result column="PRODUCT_CODE" property="productCode" jdbcType="VARCHAR" />
@@ -14,5 +15,5 @@
 		<result column="UPDATE_USER" property="updateUser" jdbcType="VARCHAR" />
 		<result column="REMARK" property="remark" jdbcType="VARCHAR" />
 	</resultMap>
-
+	
 </mapper>

+ 191 - 2
saas-doc/doc/saas_platform.md

@@ -8,7 +8,7 @@
 当响应内容中 respCode 为 A0301 时,web端应重定向到登录页面,进行登录
 API接口直接调用时,需先请求获取OpenId(目前为账号ID)的接口,再根据此OpenId获取token,再进行相关业务接口请求
 {
-    "respCode": "A0301",	//响应码
+    "respCode": "A0301",	//响应码
     "respMsg": "访问未授权"	//响应描述
 }
 ```
@@ -61,7 +61,8 @@ API接口直接调用时,需先请求获取OpenId(目前为账号ID)的接口
 	    "username":"zhangsan",   //账号登录名,必填
 	    "password":"123456",    //账号密码,必填
 	    "remember":false,		// 是否记住登录,true-记住,默认false,选填
-	    "auths":false			// 是否获取此账号对应的菜单权限树,true-获取,默认false,选填
+	    "auths":false,			// 是否获取此账号对应的菜单权限树,true-获取,默认false,选填
+	    "redirectUrl":"http://127.0.0.1:8080/test"	//登录成功后的重定向链接,选填;当为空时,正常登陆,否则重定向到此地址
 	}
 
 返回:
@@ -1527,6 +1528,142 @@ Header:Content-Type=application/json
 	    "respMsg": "密码重置成功"
 	}
 
+## 产品管理
+
+### 查询产品信息
+
+	URL:http://develop.persagy.com/saas-platform/saas-account/product/querySaasProductList
+	Method:POST
+	Header:Content-Type=application/json
+
+请求:
+
+	{
+	    "accountId":"AC68464684542455",     // 账号ID,必填,不做为sql条件
+	    "appId":"PC",                   // 应用ID,PC-电脑,APP-手机应用,必填,不做为sql条件
+	    "productCode":"1001",           // 产品编码,选填,唯一
+	    "productName":"测试",           // 产品名称,选填,唯一
+	    "productState":"0",         // 产品状态,0-建设中,1-已完成,2-已关联,选填
+	    "productMenu":"0"          // 产品是否关联菜单,0-未关联,1-已关联,选填
+	}
+
+返回:
+
+	{
+	    "content": [
+	        {
+	            "createTime": 1619519546000,
+	            "id": "PD1386991620691402753",
+	            "productCode": "1001",
+	            "productIcon": "layui-test-icon",
+	            "productMenu": "0",
+	            "productName": "测试",
+	            "productState": "0",
+	            "remark": "测试但是",
+	            "updateTime": 1619519710000,
+	            "updateUser": "AC68464684542455"
+	        }
+	    ],
+	    "count": 1,
+	    "respCode": "00000",
+	    "respMsg": "success"
+	}
+
+### 分页查询产品信息
+
+	URL:http://develop.persagy.com/saas-platform/saas-account/product/queryProductPageList
+	Method:POST
+	Header:Content-Type=application/json
+
+请求:
+
+	{
+	    "accountId":"AC68464684542455",     // 账号ID,必填,不做为sql条件
+	    "appId":"PC",                   // 应用ID,PC-电脑,APP-手机应用,必填,不做为sql条件
+	    "productCode":"1001",           // 产品编码,选填,唯一
+	    "productName":"测试",           // 产品名称,选填,唯一
+	    "productState":"0",         // 产品状态,0-建设中,1-已完成,2-已关联,选填
+	    "productMenu":"0",          // 产品是否关联菜单,0-未关联,1-已关联,选填
+	    "page":1,       //分页页码,不可低于1,必填
+	    "size":10       //分页大小,不可低于1,必填
+	}
+
+返回:
+
+	{
+	    "content": [
+	        {
+	            "createTime": 1619519546000,
+	            "id": "PD1386991620691402753",
+	            "productCode": "1001",
+	            "productIcon": "layui-test-icon",
+	            "productMenu": "0",
+	            "productName": "测试",
+	            "productState": "0",
+	            "remark": "测试但是",
+	            "updateTime": 1619519710000,
+	            "updateUser": "AC68464684542455"
+	        }
+	    ],
+	    "count": 1,
+	    "respCode": "00000",
+	    "respMsg": "success"
+	}
+
+### 新增产品信息
+
+	URL:http://develop.persagy.com/saas-platform/saas-account/product/querySaasAccountList
+	Method:POST
+	Header:Content-Type=application/json
+
+请求:
+
+	{
+	    "accountId":"AC68464684542455",     // 账号ID,必填,不做为sql条件
+	    "appId":"PC",                   // 应用ID,PC-电脑,APP-手机应用,必填
+	    "productCode":"1001",           // 产品编码,必填,唯一
+	    "productName":"测试",           // 产品名称,必填,唯一
+	    "productIcon":"layui-test-icon",   // 产品图标,必填
+	    "productState":"0",         // 产品状态,0-建设中,1-已完成,2-已关联,必填
+	    "productMenu":"0",          // 产品是否关联菜单,0-未关联,1-已关联,必填
+	    "remark":"测试"             //备注,选填
+	}
+
+返回:
+
+	{
+	    "content": "PD1386991620691402753",
+	    "respCode": "00000",
+	    "respMsg": "保存成功"
+	}
+
+### 更新产品信息
+
+	URL:http://develop.persagy.com/saas-platform/saas-account/product/querySaasAccountList
+	Method:POST
+	Header:Content-Type=application/json
+
+请求:
+
+	{
+	    "accountId":"AC68464684542455",     // 账号ID,必填,不做为sql条件
+	    "appId":"PC",                   // 应用ID,PC-电脑,APP-手机应用,必填
+	    "id":"PD1386991620691402753",        //产品ID,必填
+	    "productCode":"1001",           // 产品编码,必填,唯一
+	    "productName":"测试",           // 产品名称,必填,唯一
+	    "productIcon":"layui-test-icon",   // 产品图标,必填
+	    "productState":"0",         // 产品状态,0-建设中,1-已完成,2-已关联,必填
+	    "productMenu":"0",          // 产品是否关联菜单,0-未关联,1-已关联,必填
+	    "remark":"测试但是"             //备注,选填
+	}
+
+返回:
+
+	{
+	    "respCode": "00000",
+	    "respMsg": "更新成功"
+	}
+
 ## 角色管理
 
 ### 查询角色信息(未做权限过滤,全局角色列表)
@@ -2689,3 +2826,55 @@ Header:Content-Type=application/json
 	    "respMsg": "success"
 	}
 
+## 三方账号对接管理
+
+### 申请授权码
+
+	URL:http://develop.persagy.com/saas-platform/saas-account/authCenter/code
+	Method:POST
+	Header:Content-Type=application/json
+
+请求:
+
+	{
+		"clientId":"RGF4RHUYTJMNRWH4N"  // 授权三方机构标识ID,由运维平台在对接时颁发,必填
+	}
+
+返回:
+
+	{
+	    "content": {
+	    	"code":"123",		//一次性的code值,后续获取token时使用
+	    },
+	    "respCode": "00000",
+	    "respMsg": "success"
+	}
+
+### 根据授权码获取token
+
+	URL:http://develop.persagy.com/saas-platform/saas-account/authCenter/codeToken
+	Method:POST
+	Header:Content-Type=application/json
+
+请求:
+
+	{
+		"code":"123",    					//一次性的授权码,必填
+		"clientId":"RGF4RHUYTJMNRWH4N"  // 授权三方机构标识ID,由运维平台在对接时颁发,必填
+	}
+
+返回:
+
+	{
+	    "content": {
+	    	"token":"31430ad51fd0c5b1c66dd8ba382cc33392974cc138dea908.F4B702C0FE3AE2F8DCE6443B434BD26E",	//格式:授权信息.token
+	        "expire": "60"			//token有效期,单位:分钟
+	    },
+	    "respCode": "00000",
+	    "respMsg": "success"
+	}
+
+### 账号注册-RabbitMQ消息
+
+
+

BIN
saas-doc/doc/运维管理3.0-数据库表设计.xlsx


+ 19 - 1
saas-doc/sql/saas_platform.sql

@@ -209,4 +209,22 @@ CREATE TABLE `saas_role_menu` (
   UNIQUE KEY `UK_FOLE_MENU_GROUP` (`GROUP_CODE`,`ROLE_ID`,`MENU_ID`,`FUNCTION_ID`) USING BTREE
 ) ENGINE=InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '角色-菜单功能关联信息' ROW_FORMAT = Dynamic;
 
-SET FOREIGN_KEY_CHECKS = 1;
+-- ----------------------------
+-- Table structure for saas_product
+-- ----------------------------
+DROP TABLE IF EXISTS `saas_product`;
+CREATE TABLE `saas_product` (
+  `ID` varchar(64) NOT NULL,
+  `PRODUCT_CODE` varchar(50) DEFAULT NULL COMMENT '产品编码',
+  `PRODUCT_NAME` varchar(50) DEFAULT NULL COMMENT '产品名称',
+  `PRODUCT_ICON` varchar(100) DEFAULT NULL COMMENT '产品图标',
+  `PRODUCT_STATE` varchar(1) DEFAULT '0' COMMENT '产品状态,0-建设中,1-已完成,2-已关联',
+  `PRODUCT_MENU` varchar(1) DEFAULT '0' COMMENT '产品是否关联菜单,0-未关联,1-已关联',
+  `CREATE_TIME` timestamp NULL DEFAULT NULL COMMENT '创建时间',
+  `UPDATE_TIME` timestamp NULL DEFAULT NULL COMMENT '更新时间',
+  `UPDATE_USER` varchar(64) DEFAULT NULL COMMENT '最后一次操作者ID',
+  `REMARK` varchar(255) DEFAULT NULL COMMENT '备注',
+  PRIMARY KEY (`ID`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='产品信息';
+
+SET FOREIGN_KEY_CHECKS = 1;